Refactor BackgroundSource

This commit is contained in:
John Firebaugh
2013-08-22 11:45:35 -07:00
parent 7b2eaa2fd8
commit 0180367399
8 changed files with 99 additions and 102 deletions

View File

@@ -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:

View File

@@ -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"
},

View File

@@ -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'
}));

View File

@@ -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' };

View File

@@ -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;
};

View File

@@ -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 {

View File

@@ -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');

View File

@@ -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');
});
});