Skip to content

Instantly share code, notes, and snippets.

@mbostock

mbostock/.block

Last active Feb 8, 2016
Embed
What would you like to do?
Fancy Markers
license: gpl-3.0

The default display for GeoJSON points in Polymaps is a 4.5px-radius circle. In this example, I show how to create more traditional pin-style markers for points. This is implemented using a “load” event handler which replaces the default circles with custom path elements.

The marker outline is courtesy of Dmitry Baranovskiy; he has graciously provided over 100 free vector icons to choose from. Of course, there’s no requirement to use vector icons. You could replace the circles with image elements instead, if you prefer raster. But the nice thing about vectors is that we can color them dynamically based on the data, as we do here by generating three categorical color gradients.

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://cdn.rawgit.com/simplegeo/polymaps/v2.3.0/polymaps.min.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/simplegeo/polymaps/v2.3.0/lib/raphaeljs/icons.js"></script>
<script type="text/javascript" src="https://cdn.rawgit.com/simplegeo/polymaps/v2.3.0/lib/crimespotting/crimespotting.js"></script>
<style type="text/css">
@import url("https://cdn.rawgit.com/simplegeo/polymaps/v2.3.0/examples/example.css");
html, body {
height: 100%;
background: #E6E6E6;
}
svg {
display: block;
}
.layer use {
stroke: #ccc;
stroke-opacity: .5;
}
</style>
</head>
<body>
<script type="text/javascript">
var po = org.polymaps;
var svg = document.body.appendChild(po.svg("svg")),
defs = svg.appendChild(po.svg("defs"));
/* Create three linear gradients for each category. */
defs.appendChild(gradient("#D90000", "#A30000")).setAttribute("id", "gradient-violent");
defs.appendChild(gradient("#23965E", "#1A7046")).setAttribute("id", "gradient-property");
defs.appendChild(gradient("#3489BA", "#27678B")).setAttribute("id", "gradient-quality");
/* Create a marker path. */
defs.appendChild(icons.marker()).setAttribute("id", "marker");
var map = po.map()
.container(svg)
.center({lat: 37.787, lon: -122.228})
.zoomRange([10, 16])
.add(po.interact());
map.add(po.image()
.url(po.url("http://{S}tile.cloudmade.com"
+ "/1a1b06b230af4efdbb989ea99e9841af" // http://cloudmade.com/register
+ "/998/256/{Z}/{X}/{Y}.png")
.hosts(["a.", "b.", "c.", ""])));
map.add(po.geoJson()
.url(crimespotting("http://oakland.crimespotting.org"
+ "/crime-data"
+ "?count=100"
+ "&format=json"
+ "&bbox={B}"
+ "&dstart=2010-04-01"
+ "&dend=2010-04-01"))
.on("load", load)
.clip(false)
.scale("fixed")
.zoom(12));
/* Post-process the GeoJSON points and replace them with markers! */
function load(e) {
e.features.sort(function(a, b) {
return b.data.geometry.coordinates[1] - a.data.geometry.coordinates[1];
});
for (var i = 0; i < e.features.length; i++) {
var f = e.features[i],
d = f.data,
c = f.element,
p = c.parentNode,
u = f.element = po.svg("use");
u.setAttributeNS(po.ns.xlink, "href", "#marker");
u.setAttribute("transform", c.getAttribute("transform"));
u.setAttribute("fill", "url(#gradient-" + crimespotting.categorize(d) + ")");
p.removeChild(c);
p.appendChild(u);
}
}
/* Helper method for constructing a linear gradient. */
function gradient(a, b) {
var g = po.svg("linearGradient");
g.setAttribute("x1", 0);
g.setAttribute("y1", 1);
g.setAttribute("x2", 0);
g.setAttribute("y2", 0);
var s0 = g.appendChild(po.svg("stop"));
s0.setAttribute("offset", "0%");
s0.setAttribute("stop-color", a);
var s1 = g.appendChild(po.svg("stop"));
s1.setAttribute("offset", "100%");
s1.setAttribute("stop-color", b);
return g;
}
</script>
<span id="copy">
&copy; 2010
<a href="http://www.cloudmade.com/">CloudMade</a>,
<a href="http://www.openstreetmap.org/">OpenStreetMap</a> contributors,
<a href="http://creativecommons.org/licenses/by-sa/2.0/">CCBYSA</a>.
</span>
</body>
</html>
@RandomEtc

This comment has been minimized.

Copy link

@RandomEtc RandomEtc commented Oct 15, 2010

Looks like Firefox doesn't display defs if you use "url(#foo)" in the use element's href. It works without the url() part as far as I can tell.

@mbostock

This comment has been minimized.

Copy link
Owner Author

@mbostock mbostock commented Oct 15, 2010

Uh, you're right. Looks like the url() part isn't needed for that parameter. XLink is hard!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment