mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-27 16:03:52 +00:00
Refactor BackgroundSource
This commit is contained in:
@@ -195,6 +195,8 @@ en:
|
||||
title: Background
|
||||
description: Background settings
|
||||
percent_brightness: "{opacity}% brightness"
|
||||
custom: Custom
|
||||
custom_prompt: "Enter a tile template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme."
|
||||
fix_misalignment: Fix misalignment
|
||||
reset: reset
|
||||
restore:
|
||||
|
||||
2
dist/locales/en.json
vendored
2
dist/locales/en.json
vendored
@@ -241,6 +241,8 @@
|
||||
"title": "Background",
|
||||
"description": "Background settings",
|
||||
"percent_brightness": "{opacity}% brightness",
|
||||
"custom": "Custom",
|
||||
"custom_prompt": "Enter a tile template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.",
|
||||
"fix_misalignment": "Fix misalignment",
|
||||
"reset": "reset"
|
||||
},
|
||||
|
||||
@@ -10,21 +10,19 @@ iD.Background = function(context) {
|
||||
if (source.sourcetag === 'Bing') {
|
||||
return iD.BackgroundSource.Bing(source, dispatch);
|
||||
} else {
|
||||
return iD.BackgroundSource.template(source);
|
||||
return iD.BackgroundSource(source);
|
||||
}
|
||||
});
|
||||
|
||||
backgroundSources.push(iD.BackgroundSource.Custom);
|
||||
|
||||
function findSource(sourcetag) {
|
||||
return _.find(backgroundSources, function(d) {
|
||||
return d.data.sourcetag && d.data.sourcetag === sourcetag;
|
||||
return d.sourcetag && d.sourcetag === sourcetag;
|
||||
});
|
||||
}
|
||||
|
||||
function updateImagery() {
|
||||
var b = background.baseLayerSource().data,
|
||||
o = overlayLayers.map(function (d) { return d.source().data.sourcetag; }).join(','),
|
||||
var b = background.baseLayerSource(),
|
||||
o = overlayLayers.map(function (d) { return d.source().sourcetag; }).join(','),
|
||||
q = iD.util.stringQs(location.hash.substring(1));
|
||||
|
||||
var tag = b.sourcetag;
|
||||
@@ -54,7 +52,7 @@ iD.Background = function(context) {
|
||||
}
|
||||
|
||||
overlayLayers.forEach(function (d) {
|
||||
imageryUsed.push(d.source().data.sourcetag || d.source().data.name);
|
||||
imageryUsed.push(d.source().sourcetag || d.source().name);
|
||||
});
|
||||
|
||||
if (background.showsGpxLayer()) {
|
||||
@@ -82,7 +80,7 @@ iD.Background = function(context) {
|
||||
gpx.call(gpxLayer);
|
||||
|
||||
var overlays = selection.selectAll('.overlay-layer')
|
||||
.data(overlayLayers, function(d) { return d.source().data.name });
|
||||
.data(overlayLayers, function(d) { return d.source().name });
|
||||
|
||||
overlays.enter().insert('div', '.layer-data')
|
||||
.attr('class', 'layer-layer overlay-layer');
|
||||
@@ -96,11 +94,8 @@ iD.Background = function(context) {
|
||||
}
|
||||
|
||||
background.sources = function(extent) {
|
||||
return backgroundSources.filter(function(layer) {
|
||||
return !layer.data.extents ||
|
||||
layer.data.extents.some(function(layerExtent) {
|
||||
return iD.geo.Extent(layerExtent).intersects(extent);
|
||||
});
|
||||
return backgroundSources.filter(function(source) {
|
||||
return source.intersects(extent);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -149,7 +144,7 @@ iD.Background = function(context) {
|
||||
|
||||
background.showsLayer = function(d) {
|
||||
return d === baseLayer.source() ||
|
||||
(d.data.name === 'Custom' && baseLayer.source().data.name === 'Custom') ||
|
||||
(d.name === 'Custom' && baseLayer.source().name === 'Custom') ||
|
||||
overlayLayers.some(function(l) { return l.source() === d; });
|
||||
};
|
||||
|
||||
@@ -177,14 +172,14 @@ iD.Background = function(context) {
|
||||
};
|
||||
|
||||
background.nudge = function(d, zoom) {
|
||||
baseLayer.nudge(d, zoom);
|
||||
baseLayer.source().nudge(d, zoom);
|
||||
dispatch.change();
|
||||
return background;
|
||||
};
|
||||
|
||||
background.offset = function(d) {
|
||||
if (!arguments.length) return baseLayer.offset();
|
||||
baseLayer.offset(d);
|
||||
if (!arguments.length) return baseLayer.source().offset();
|
||||
baseLayer.source().offset(d);
|
||||
dispatch.change();
|
||||
return background;
|
||||
};
|
||||
@@ -193,7 +188,7 @@ iD.Background = function(context) {
|
||||
chosen = q.background || q.layer;
|
||||
|
||||
if (chosen && chosen.indexOf('custom:') === 0) {
|
||||
background.baseLayerSource(iD.BackgroundSource.template({
|
||||
background.baseLayerSource(iD.BackgroundSource({
|
||||
template: chosen.replace(/^custom:/, ''),
|
||||
name: 'Custom'
|
||||
}));
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
iD.BackgroundSource = {};
|
||||
iD.BackgroundSource = function(data) {
|
||||
var source = _.clone(data),
|
||||
offset = [0, 0];
|
||||
|
||||
// derive the url of a 'quadkey' style tile from a coordinate object
|
||||
iD.BackgroundSource.template = function(data) {
|
||||
source.scaleExtent = data.scaleExtent || [0, 20];
|
||||
|
||||
function generator(coord) {
|
||||
source.offset = function(_) {
|
||||
if (!arguments.length) return offset;
|
||||
offset = _;
|
||||
return source;
|
||||
};
|
||||
|
||||
source.nudge = function(_, zoomlevel) {
|
||||
offset[0] += _[0] / Math.pow(2, zoomlevel);
|
||||
offset[1] += _[1] / Math.pow(2, zoomlevel);
|
||||
return source;
|
||||
};
|
||||
|
||||
source.url = function(coord) {
|
||||
var u = '';
|
||||
for (var zoom = coord[2]; zoom > 0; zoom--) {
|
||||
var b = 0;
|
||||
@@ -28,19 +41,24 @@ iD.BackgroundSource.template = function(data) {
|
||||
var subdomains = r.split(':')[1].split(',');
|
||||
return subdomains[coord[2] % subdomains.length];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
generator.data = data;
|
||||
generator.copyrightNotices = function() {};
|
||||
source.intersects = function(extent) {
|
||||
return !data.extents || data.extents.some(function(ex) {
|
||||
return iD.geo.Extent(ex).intersects(extent);
|
||||
});
|
||||
};
|
||||
|
||||
return generator;
|
||||
source.copyrightNotices = function() {};
|
||||
|
||||
return source;
|
||||
};
|
||||
|
||||
iD.BackgroundSource.Bing = function(data, dispatch) {
|
||||
// http://msdn.microsoft.com/en-us/library/ff701716.aspx
|
||||
// http://msdn.microsoft.com/en-us/library/ff701701.aspx
|
||||
|
||||
var bing = iD.BackgroundSource.template(data),
|
||||
var bing = iD.BackgroundSource(data),
|
||||
key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
|
||||
url = 'http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
|
||||
key + '&jsonp={callback}',
|
||||
@@ -76,15 +94,3 @@ iD.BackgroundSource.Bing = function(data, dispatch) {
|
||||
|
||||
return bing;
|
||||
};
|
||||
|
||||
iD.BackgroundSource.Custom = function() {
|
||||
var template = window.prompt('Enter a tile template. ' +
|
||||
'Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.');
|
||||
if (!template) return null;
|
||||
return iD.BackgroundSource.template({
|
||||
template: template,
|
||||
name: 'Custom'
|
||||
});
|
||||
};
|
||||
|
||||
iD.BackgroundSource.Custom.data = { 'name': 'Custom' };
|
||||
|
||||
@@ -3,8 +3,6 @@ iD.TileLayer = function() {
|
||||
tile = d3.geo.tile(),
|
||||
projection,
|
||||
cache = {},
|
||||
offset = [0, 0],
|
||||
offsets = {},
|
||||
tileOrigin,
|
||||
z,
|
||||
transformProp = iD.util.prefixCSSProperty('Transform'),
|
||||
@@ -25,7 +23,7 @@ iD.TileLayer = function() {
|
||||
function lookUp(d) {
|
||||
for (var up = -1; up > -d[2]; up--) {
|
||||
var tile = atZoom(d, up);
|
||||
if (cache[source(tile)] !== false) {
|
||||
if (cache[source.url(tile)] !== false) {
|
||||
return tile;
|
||||
}
|
||||
}
|
||||
@@ -43,7 +41,7 @@ iD.TileLayer = function() {
|
||||
}
|
||||
|
||||
function addSource(d) {
|
||||
d.push(source(d));
|
||||
d.push(source.url(d));
|
||||
return d;
|
||||
}
|
||||
|
||||
@@ -83,8 +81,8 @@ iD.TileLayer = function() {
|
||||
}
|
||||
|
||||
var pixelOffset = [
|
||||
Math.round(offset[0] * Math.pow(2, z)),
|
||||
Math.round(offset[1] * Math.pow(2, z))
|
||||
Math.round(source.offset()[0] * Math.pow(2, z)),
|
||||
Math.round(source.offset()[1] * Math.pow(2, z))
|
||||
];
|
||||
|
||||
function load(d) {
|
||||
@@ -141,19 +139,6 @@ iD.TileLayer = function() {
|
||||
.classed('tile-removing', false);
|
||||
}
|
||||
|
||||
background.offset = function(_) {
|
||||
if (!arguments.length) return offset;
|
||||
offset = _;
|
||||
if (source.data) offsets[source.data.name] = offset;
|
||||
return background;
|
||||
};
|
||||
|
||||
background.nudge = function(_, zoomlevel) {
|
||||
offset[0] += _[0] / Math.pow(2, zoomlevel);
|
||||
offset[1] += _[1] / Math.pow(2, zoomlevel);
|
||||
return background;
|
||||
};
|
||||
|
||||
background.projection = function(_) {
|
||||
if (!arguments.length) return projection;
|
||||
projection = _;
|
||||
@@ -169,13 +154,8 @@ iD.TileLayer = function() {
|
||||
background.source = function(_) {
|
||||
if (!arguments.length) return source;
|
||||
source = _;
|
||||
if (source.data) {
|
||||
offset = offsets[source.data.name] = offsets[source.data.name] || [0, 0];
|
||||
} else {
|
||||
offset = [0, 0];
|
||||
}
|
||||
cache = {};
|
||||
tile.scaleExtent((source.data && source.data.scaleExtent) || [1, 20]);
|
||||
tile.scaleExtent(source.scaleExtent);
|
||||
return background;
|
||||
};
|
||||
|
||||
|
||||
@@ -8,22 +8,22 @@ iD.ui.Attribution = function(context) {
|
||||
}
|
||||
|
||||
var attribution = selection.selectAll('.provided-by')
|
||||
.data([context.background().baseLayerSource()], function(d) { return d.data.name; });
|
||||
.data([context.background().baseLayerSource()], function(d) { return d.name; });
|
||||
|
||||
attribution.enter()
|
||||
.append('span')
|
||||
.attr('class', 'provided-by')
|
||||
.each(function(d) {
|
||||
var source = d.data.sourcetag || d.data.name;
|
||||
var source = d.sourcetag || d.name;
|
||||
|
||||
if (d.data.logo) {
|
||||
source = '<img class="source-image" src="' + context.imagePath(d.data.logo) + '">';
|
||||
if (d.logo) {
|
||||
source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
|
||||
}
|
||||
|
||||
if (d.data.terms_url) {
|
||||
if (d.terms_url) {
|
||||
d3.select(this)
|
||||
.append('a')
|
||||
.attr('href', d.data.terms_url)
|
||||
.attr('href', d.terms_url)
|
||||
.attr('target', '_blank')
|
||||
.html(source);
|
||||
} else {
|
||||
|
||||
@@ -28,7 +28,7 @@ iD.ui.Background = function(context) {
|
||||
return context.background().showsLayer(d);
|
||||
}
|
||||
|
||||
content.selectAll('label.layer')
|
||||
content.selectAll('label.layer, label.custom_layer')
|
||||
.classed('active', active)
|
||||
.selectAll('input')
|
||||
.property('checked', active);
|
||||
@@ -36,18 +36,24 @@ iD.ui.Background = function(context) {
|
||||
|
||||
function clickSetSource(d) {
|
||||
d3.event.preventDefault();
|
||||
if (d.data.name === 'Custom') {
|
||||
var configured = d();
|
||||
if (!configured) {
|
||||
selectLayer();
|
||||
return;
|
||||
}
|
||||
d = configured;
|
||||
}
|
||||
context.background().baseLayerSource(d);
|
||||
selectLayer();
|
||||
}
|
||||
|
||||
function clickCustom() {
|
||||
d3.event.preventDefault();
|
||||
var template = window.prompt(t('background.custom_prompt'));
|
||||
if (!template) {
|
||||
selectLayer();
|
||||
return;
|
||||
}
|
||||
context.background().baseLayerSource(iD.BackgroundSource({
|
||||
template: template,
|
||||
name: 'Custom'
|
||||
}));
|
||||
selectLayer();
|
||||
}
|
||||
|
||||
function clickSetOverlay(d) {
|
||||
d3.event.preventDefault();
|
||||
context.background().toggleOverlayLayer(d);
|
||||
@@ -65,29 +71,27 @@ iD.ui.Background = function(context) {
|
||||
.filter(filter);
|
||||
|
||||
var layerLinks = layerList.selectAll('label.layer')
|
||||
.data(sources, function(d) { return d.data.name; });
|
||||
.data(sources, function(d) { return d.name; });
|
||||
|
||||
var layerInner = layerLinks.enter()
|
||||
.append('label')
|
||||
.insert('label', '.custom_layer')
|
||||
.attr('class', 'layer');
|
||||
|
||||
// only set tooltips for layers with tooltips
|
||||
layerInner
|
||||
.filter(function(d) { return d.data.description; })
|
||||
.filter(function(d) { return d.description; })
|
||||
.call(bootstrap.tooltip()
|
||||
.title(function(d) { return d.data.description; })
|
||||
.placement('left')
|
||||
);
|
||||
.title(function(d) { return d.description; })
|
||||
.placement('left'));
|
||||
|
||||
layerInner.append('input')
|
||||
.attr('type', type)
|
||||
.attr('name', 'layers')
|
||||
.attr('value', function(d) { return d.data.name; })
|
||||
.attr('value', function(d) { return d.name; })
|
||||
.on('change', change);
|
||||
|
||||
layerInner.insert('span').text(function(d) {
|
||||
return d.data.name;
|
||||
});
|
||||
layerInner.append('span')
|
||||
.text(function(d) { return d.name; });
|
||||
|
||||
layerLinks.exit()
|
||||
.remove();
|
||||
@@ -96,13 +100,8 @@ iD.ui.Background = function(context) {
|
||||
}
|
||||
|
||||
function update() {
|
||||
backgroundList.call(drawList, 'radio', clickSetSource, function(d) {
|
||||
return !d.data.overlay;
|
||||
});
|
||||
|
||||
overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) {
|
||||
return d.data.overlay;
|
||||
});
|
||||
backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
|
||||
overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
|
||||
|
||||
var hasGpx = context.background().hasGpxLayer(),
|
||||
showsGpx = context.background().showsGpxLayer();
|
||||
@@ -219,6 +218,19 @@ iD.ui.Background = function(context) {
|
||||
.append('div')
|
||||
.attr('class', 'toggle-list layer-list');
|
||||
|
||||
var custom = backgroundList
|
||||
.append('label')
|
||||
.attr('class', 'custom_layer')
|
||||
.datum({name: 'Custom'});
|
||||
|
||||
custom.append('input')
|
||||
.attr('type', 'radio')
|
||||
.attr('name', 'layers')
|
||||
.on('change', clickCustom);
|
||||
|
||||
custom.append('span')
|
||||
.text(t('background.custom'));
|
||||
|
||||
var overlayList = content
|
||||
.append('div')
|
||||
.attr('class', 'toggle-list layer-list');
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
describe('iD.BackgroundSource.Template', function() {
|
||||
describe('iD.BackgroundSource', function() {
|
||||
it('does not error with blank template', function() {
|
||||
var source = iD.BackgroundSource.template({ template: '' });
|
||||
var source = iD.BackgroundSource({ template: '' });
|
||||
expect(source([0,1,2])).to.equal('');
|
||||
});
|
||||
|
||||
it('generates a tile-generating source', function() {
|
||||
var source = iD.BackgroundSource.template({ template: '{z}/{x}/{y}' });
|
||||
var source = iD.BackgroundSource({ template: '{z}/{x}/{y}' });
|
||||
expect(source([0,1,2])).to.equal('2/0/1');
|
||||
});
|
||||
|
||||
it('supports subdomains', function() {
|
||||
var source = iD.BackgroundSource.template({ template: '{t}/{z}/{x}/{y}', subdomains: ['apples', 'oranges'] });
|
||||
var source = iD.BackgroundSource({ template: '{t}/{z}/{x}/{y}', subdomains: ['apples', 'oranges'] });
|
||||
expect(source([0,1,2])).to.equal('oranges/2/0/1');
|
||||
});
|
||||
|
||||
it('distributes requests between subdomains', function() {
|
||||
var source = iD.BackgroundSource.template({ template: '{t}/{z}/{x}/{y}', subdomains: ['apples', 'oranges'] });
|
||||
var source = iD.BackgroundSource({ template: '{t}/{z}/{x}/{y}', subdomains: ['apples', 'oranges'] });
|
||||
expect(source([0,1,1])).to.equal('oranges/1/0/1');
|
||||
expect(source([0,2,1])).to.equal('apples/1/0/2');
|
||||
});
|
||||
|
||||
it('supports josm style templates', function() {
|
||||
var source = iD.BackgroundSource.template({ template: '{switch:foo,bar}/{zoom}/{x}/{y}' });
|
||||
var source = iD.BackgroundSource({ template: '{switch:foo,bar}/{zoom}/{x}/{y}' });
|
||||
expect(source([0,1,1])).to.equal('bar/1/0/1');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user