From 6e0925003c9f604479806ebb4ce53814df6fc43e Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Fri, 15 Mar 2013 13:57:08 -0400 Subject: [PATCH] add Maki icons to areas --- js/id/renderer/map.js | 2 +- js/id/svg/labels.js | 124 ++++++++++++++++++++++++++++++++++-------- js/id/svg/surface.js | 4 +- 3 files changed, 103 insertions(+), 27 deletions(-) diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index c33d30b8b..ba860fe8c 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -19,7 +19,7 @@ iD.Map = function(context) { lines = iD.svg.Lines(projection), areas = iD.svg.Areas(roundedProjection), midpoints = iD.svg.Midpoints(roundedProjection), - labels = iD.svg.Labels(roundedProjection), + labels = iD.svg.Labels(roundedProjection, context), tail = iD.ui.Tail(), surface, tilegroup; diff --git a/js/id/svg/labels.js b/js/id/svg/labels.js index db61b91e9..dde6c6644 100644 --- a/js/id/svg/labels.js +++ b/js/id/svg/labels.js @@ -1,4 +1,4 @@ -iD.svg.Labels = function(projection) { +iD.svg.Labels = function(projection, context) { // Replace with dict and iterate over entities tags instead? var label_stack = [ @@ -30,16 +30,21 @@ iD.svg.Labels = function(projection) { ]; var default_size = 12; + var font_sizes = label_stack.map(function(d) { - var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]); - var m = style && style.cssText.match("font-size: ([0-9]{1,2})px;"); + var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]), + m = style && style.cssText.match("font-size: ([0-9]{1,2})px;"); if (m) return parseInt(m[1], 10); + style = iD.util.getStyle('text.' + d[0]); m = style && style.cssText.match("font-size: ([0-9]{1,2})px;"); if (m) return parseInt(m[1], 10); + return default_size; }); + var iconSize = 18; + var pointOffsets = [ [15, -11, 'start'], // right [10, -11, 'start'], // unused right now @@ -49,20 +54,34 @@ iD.svg.Labels = function(projection) { var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25, 75, 20, 80, 15, 95, 10, 90, 5, 95]; + + var noIcons = ['building', 'landuse', 'natural']; + function blacklisted(preset) { + return _.any(noIcons, function(s) { + return preset.id.indexOf(s) >= 0; + }); + } + function get(array, prop) { return function(d, i) { return array[i][prop]; }; } var textWidthCache = {}; + function textWidth(text, size, elem) { var c = textWidthCache[size]; if (!c) c = textWidthCache[size] = {}; - if (c[text]) return c[text]; - else if (elem) { + + if (c[text]) { + return c[text]; + + } else if (elem) { c[text] = elem.getComputedTextLength(); return c[text]; + + } else { + return size / 3 * 2 * text.length; } - else return size / 3 * 2 * text.length; } function drawLineLabels(group, entities, filter, classes, labels) { @@ -150,7 +169,6 @@ iD.svg.Labels = function(projection) { texts.attr('x', get(labels, 'x')) .attr('y', get(labels, 'y')) - .attr('transform', get(labels, 'transform')) .style('text-anchor', get(labels, 'textAnchor')) .text(function(d) { return name(d); }) .each(function(d, i) { textWidth(name(d), labels[i].height, this); }); @@ -159,6 +177,45 @@ iD.svg.Labels = function(projection) { return texts; } + function drawAreaHalos(group, entities, filter, classes, labels) { + entities = entities.filter(hasText); + labels = labels.filter(hasText); + return drawPointHalos(group, entities, filter, classes, labels); + + function hasText(d, i) { + return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y'); + } + } + + function drawAreaLabels(group, entities, filter, classes, labels) { + entities = entities.filter(hasText); + labels = labels.filter(hasText); + return drawPointLabels(group, entities, filter, classes, labels); + + function hasText(d, i) { + return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y'); + } + } + + function drawAreaIcons(group, entities, filter, classes, labels) { + + var icons = group.selectAll('use') + .filter(filter) + .data(entities, iD.Entity.key); + + icons.enter() + .append('use') + .attr('xlink:href', function(d) { + return '#maki-' + context.presets().match(d, context.graph()).icon + '-18'; + }) + .attr('clip-path', 'url(#clip-square-18)') + .attr('class', 'icon'); + + icons.attr('transform', get(labels, 'transform')); + + icons.exit().remove(); + } + function reverse(p) { var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]); return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > - Math.PI/2); @@ -280,13 +337,18 @@ iD.svg.Labels = function(projection) { // Split entities into groups specified by label_stack for (i = 0; i < entities.length; i++) { entity = entities[i]; - if (!name(entity)) continue; - if (hidePoints && entity.geometry(graph) === 'point') continue; - for (k = 0; k < label_stack.length; k ++) { - if (entity.geometry(graph) === label_stack[k][0] && - entity.tags[label_stack[k][1]]) { - labelable[k].push(entity); - break; + var geometry = entity.geometry(graph), + preset = geometry === 'area' && context.presets().match(entity, graph), + icon = preset && !blacklisted(preset) && preset.icon; + + if ((name(entity) || icon) && !(hidePoints && geometry === 'point')) { + + for (k = 0; k < label_stack.length; k ++) { + if (entity.geometry(graph) === label_stack[k][0] && + entity.tags[label_stack[k][1]]) { + labelable[k].push(entity); + break; + } } } } @@ -308,7 +370,7 @@ iD.svg.Labels = function(projection) { var font_size = font_sizes[k]; for (i = 0; i < labelable[k].length; i ++) { entity = labelable[k][i]; - var width = textWidth(name(entity), font_size), + var width = name(entity) && textWidth(name(entity), font_size), p; if (entity.geometry(graph) === 'point') { p = getPointLabel(entity, width, font_size); @@ -372,16 +434,29 @@ iD.svg.Labels = function(projection) { var path = d3.geo.path().projection(projection), centroid = path.centroid(entity.asGeoJSON(graph, true)), extent = entity.extent(graph), - entitywidth = projection(extent[1])[0] - projection(extent[0])[0]; + entitywidth = projection(extent[1])[0] - projection(extent[0])[0], + rect; + + if (entitywidth < 20) return; + + var iconX = centroid[0] - (iconSize/2), + iconY = centroid[1] - (iconSize/2), + textOffset = iconSize + 5; - if (entitywidth < width + 20) return; var p = { - x: centroid[0], - y: centroid[1], - textAnchor: 'middle', - height: height + transform: 'translate(' + iconX + ',' + iconY + ')' }; - var rect = new RTree.Rectangle(p.x - width/2, p.y, width, height); + + if (width && entitywidth >= width + 20) { + p.x = centroid[0]; + p.y = centroid[1] + textOffset; + p.textAnchor = 'middle'; + p.height = height; + rect = new RTree.Rectangle(p.x - width/2, p.y, width, height + textOffset); + } else { + rect = new RTree.Rectangle(iconX, iconY, iconSize, iconSize); + } + if (tryInsert(rect, entity.id)) return p; } @@ -404,8 +479,9 @@ iD.svg.Labels = function(projection) { pointHalos = drawPointHalos(halo, labelled.point, filter, 'pointlabel-halo', positions.point), linesHalos = drawLineHalos(halo, labelled.line, filter, 'linelabel-halo', positions.line), lines = drawLineLabels(label, labelled.line, filter, 'pathlabel', positions.line), - areas = drawPointLabels(label, labelled.area, filter, 'arealabel', positions.area), - areaHalos = drawPointHalos(halo, labelled.area, filter, 'arealabel-halo', positions.area); + areas = drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area), + areaHalos = drawAreaHalos(halo, labelled.area, filter, 'arealabel-halo', positions.area), + areaIcons = drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area); }; }; diff --git a/js/id/svg/surface.js b/js/id/svg/surface.js index 0c93aa24a..c5d071004 100644 --- a/js/id/svg/surface.js +++ b/js/id/svg/surface.js @@ -80,7 +80,7 @@ iD.svg.Surface = function() { .attr('xlink:href', function(d) { return 'img/pattern/' + d[1] + '.png'; }); defs.selectAll() - .data([12, 20]) + .data([12, 18, 20]) .enter().append('clipPath') .attr('id', function(d) { return 'clip-square-' + d; }) .append('rect') @@ -113,7 +113,7 @@ iD.svg.Surface = function() { }); defs.selectAll() - .data(sprites("feature-icons.css", /^\.(feature-[a-z0-9-]+-12)$/)) + .data(sprites("feature-icons.css", /^\.(feature-[a-z0-9-]+-(12|18))$/)) .enter().append('use') .attr('id', function(d) { return d.id; }) .attr('transform', function(d) { return "translate(" + d.x + "," + d.y + ")"; })