diff --git a/css/app.css b/css/app.css
index e4fcec85a..256b7c91b 100644
--- a/css/app.css
+++ b/css/app.css
@@ -39,6 +39,13 @@ body {
height: 100%;
}
+#defs {
+ /* Can't be display: none or the clippaths are ignored. */
+ position: absolute;
+ width: 0;
+ height: 0;
+}
+
.spacer {
height: 40px;
margin-right: 10px;
diff --git a/index.html b/index.html
index 9f0c7a6f5..4fd3ffbaf 100644
--- a/index.html
+++ b/index.html
@@ -59,14 +59,15 @@
+
+
+
-
-
diff --git a/js/id/svg/defs.js b/js/id/svg/defs.js
new file mode 100644
index 000000000..ad9182a41
--- /dev/null
+++ b/js/id/svg/defs.js
@@ -0,0 +1,129 @@
+/*
+ A standalone SVG element that contains only a `defs` sub-element. To be
+ used once globally, since defs IDs must be unique within a document.
+*/
+iD.svg.Defs = function(context) {
+ function autosize(image) {
+ var img = document.createElement('img');
+ img.src = image.attr('xlink:href');
+ img.onload = function() {
+ image.attr({
+ width: img.width,
+ height: img.height
+ });
+ };
+ }
+
+ function SpriteDefinition(id, href, data) {
+ return function(defs) {
+ defs.append('image')
+ .attr('id', id)
+ .attr('xlink:href', href)
+ .call(autosize);
+
+ defs.selectAll()
+ .data(data)
+ .enter().append('use')
+ .attr('id', function(d) { return d.key; })
+ .attr('transform', function(d) { return 'translate(-' + d.value[0] + ',-' + d.value[1] + ')'; })
+ .attr('xlink:href', '#' + id);
+ };
+ }
+
+ return function (selection) {
+ var defs = selection.append('defs');
+
+ defs.append('marker')
+ .attr({
+ id: 'oneway-marker',
+ viewBox: '0 0 10 10',
+ refY: 2.5,
+ refX: 5,
+ markerWidth: 2,
+ markerHeight: 2,
+ orient: 'auto'
+ })
+ .append('path')
+ .attr('d', 'M 5 3 L 0 3 L 0 2 L 5 2 L 5 0 L 10 2.5 L 5 5 z');
+
+ var patterns = defs.selectAll('pattern')
+ .data([
+ // pattern name, pattern image name
+ ['wetland', 'wetland'],
+ ['construction', 'construction'],
+ ['cemetery', 'cemetery'],
+ ['orchard', 'orchard'],
+ ['farmland', 'farmland'],
+ ['beach', 'dots'],
+ ['scrub', 'dots'],
+ ['meadow', 'dots']
+ ])
+ .enter()
+ .append('pattern')
+ .attr({
+ id: function (d) {
+ return 'pattern-' + d[0];
+ },
+ width: 32,
+ height: 32,
+ patternUnits: 'userSpaceOnUse'
+ });
+
+ patterns.append('rect')
+ .attr({
+ x: 0,
+ y: 0,
+ width: 32,
+ height: 32,
+ 'class': function (d) {
+ return 'pattern-color-' + d[0];
+ }
+ });
+
+ patterns.append('image')
+ .attr({
+ x: 0,
+ y: 0,
+ width: 32,
+ height: 32
+ })
+ .attr('xlink:href', function (d) {
+ return context.imagePath('pattern/' + d[1] + '.png');
+ });
+
+ defs.selectAll()
+ .data([12, 18, 20])
+ .enter().append('clipPath')
+ .attr('id', function (d) {
+ return 'clip-square-' + d;
+ })
+ .append('rect')
+ .attr('x', 0)
+ .attr('y', 0)
+ .attr('width', function (d) {
+ return d;
+ })
+ .attr('height', function (d) {
+ return d;
+ });
+
+ var maki = [];
+ _.forEach(iD.data.featureIcons, function (dimensions, name) {
+ if (dimensions['12'] && dimensions['18'] && dimensions['24']) {
+ maki.push({key: 'maki-' + name + '-12', value: dimensions['12']});
+ maki.push({key: 'maki-' + name + '-18', value: dimensions['18']});
+ maki.push({key: 'maki-' + name + '-24', value: dimensions['24']});
+ }
+ });
+
+ defs.call(SpriteDefinition(
+ 'sprite',
+ context.imagePath('sprite.svg'),
+ d3.entries(iD.data.operations)));
+
+ defs.call(SpriteDefinition(
+ 'maki-sprite',
+ context.imagePath('maki-sprite.png'),
+ maki));
+ };
+};
diff --git a/js/id/svg/surface.js b/js/id/svg/surface.js
index cac731c69..3b11461dd 100644
--- a/js/id/svg/surface.js
+++ b/js/id/svg/surface.js
@@ -1,114 +1,5 @@
-iD.svg.Surface = function(context) {
- function autosize(image) {
- var img = document.createElement('img');
- img.src = image.attr('xlink:href');
- img.onload = function() {
- image.attr({
- width: img.width,
- height: img.height
- });
- };
- }
-
- function SpriteDefinition(id, href, data) {
- return function(defs) {
- defs.append('image')
- .attr('id', id)
- .attr('xlink:href', href)
- .call(autosize);
-
- defs.selectAll()
- .data(data)
- .enter().append('use')
- .attr('id', function(d) { return d.key; })
- .attr('transform', function(d) { return 'translate(-' + d.value[0] + ',-' + d.value[1] + ')'; })
- .attr('xlink:href', '#' + id);
- };
- }
-
- return function drawSurface(selection) {
- var defs = selection.append('defs');
-
- defs.append('marker')
- .attr({
- id: 'oneway-marker',
- viewBox: '0 0 10 10',
- refY: 2.5,
- refX: 5,
- markerWidth: 2,
- markerHeight: 2,
- orient: 'auto'
- })
- .append('path')
- .attr('d', 'M 5 3 L 0 3 L 0 2 L 5 2 L 5 0 L 10 2.5 L 5 5 z');
-
- var patterns = defs.selectAll('pattern')
- .data([
- // pattern name, pattern image name
- ['wetland', 'wetland'],
- ['construction', 'construction'],
- ['cemetery', 'cemetery'],
- ['orchard', 'orchard'],
- ['farmland', 'farmland'],
- ['beach', 'dots'],
- ['scrub', 'dots'],
- ['meadow', 'dots']])
- .enter()
- .append('pattern')
- .attr({
- id: function(d) { return 'pattern-' + d[0]; },
- width: 32,
- height: 32,
- patternUnits: 'userSpaceOnUse'
- });
-
- patterns.append('rect')
- .attr({
- x: 0,
- y: 0,
- width: 32,
- height: 32,
- 'class': function(d) { return 'pattern-color-' + d[0]; }
- });
-
- patterns.append('image')
- .attr({
- x: 0,
- y: 0,
- width: 32,
- height: 32
- })
- .attr('xlink:href', function(d) { return context.imagePath('pattern/' + d[1] + '.png'); });
-
- defs.selectAll()
- .data([12, 18, 20])
- .enter().append('clipPath')
- .attr('id', function(d) { return 'clip-square-' + d; })
- .append('rect')
- .attr('x', 0)
- .attr('y', 0)
- .attr('width', function(d) { return d; })
- .attr('height', function(d) { return d; });
-
- var maki = [];
- _.forEach(iD.data.featureIcons, function(dimensions, name) {
- if (dimensions['12'] && dimensions['18'] && dimensions['24']) {
- maki.push({key: 'maki-' + name + '-12', value: dimensions['12']});
- maki.push({key: 'maki-' + name + '-18', value: dimensions['18']});
- maki.push({key: 'maki-' + name + '-24', value: dimensions['24']});
- }
- });
-
- defs.call(SpriteDefinition(
- 'sprite',
- context.imagePath('sprite.svg'),
- d3.entries(iD.data.operations)));
-
- defs.call(SpriteDefinition(
- 'maki-sprite',
- context.imagePath('maki-sprite.png'),
- maki));
-
+iD.svg.Surface = function() {
+ return function (selection) {
var layers = selection.selectAll('.layer')
.data(['fill', 'shadow', 'casing', 'stroke', 'oneway', 'hit', 'halo', 'label']);
diff --git a/js/id/ui.js b/js/id/ui.js
index 678c55ca4..01f8ed6df 100644
--- a/js/id/ui.js
+++ b/js/id/ui.js
@@ -12,6 +12,10 @@ iD.ui = function(context) {
map.centerZoom([-77.02271, 38.90085], 20);
}
+ container.append('svg')
+ .attr('id', 'defs')
+ .call(iD.svg.Defs(context));
+
container.append('div')
.attr('id', 'sidebar')
.attr('class', 'col4')