Hello World

D3 Example

This example demonstrates a MapJam street map being used in D3.

<!DOCTYPE html>
<html>
<head>

<title>MapJam for Developers</title>
<meta charset="utf-8">
<meta name="ROBOTS" content="NOINDEX, NOFOLLOW">

<style>
    body {
        margin: 0;
    }
    .map {
        position:absolute;
        top:0;
        bottom:0;
        width:100%;
    }
    .layerWater,
    .layerRoads,
    .layerlanduses {
        position: absolute;
    }
    .tileWater,
    .tileRoad,
    .tilelanduse {
        position: absolute;
        width: 256px;
        height: 256px;
    }
    .tileWater path {
        stroke: none;
    }
    .tileRoad path {
        fill: none;
        stroke: #ccb;
        stroke-linejoin: round;
        stroke-linecap: round;
    }
    .tileRoad .mainroads {
        stroke: #776;
    }
    .tileRoad .minorroads {
        stroke: #ccb;
    }
    .tileRoad .motorways {
        stroke: #f39;
        stroke-width: 1.5px;
    }
    .tileRoad .railways {
        stroke: #7de;
    }
    .info {
        position: absolute;
        bottom: 10px;
        left: 10px;
        font-family: sans-serif;
    }
    .tileWater .ocean {
        stroke: none;
        fill: #ededed;
    }

    .tilelanduse {
        stroke: none;
        fill: #04f7da;
        opacity: 0.2;
    }

    .tileWater .lake,
    .tileWater .reservoir,
    .tileWater .riverbank,
    .tileWater .water,
    .tileWater .basin,
    .tileWater .dam {
        fill: #218bec;
    }
</style>
</head>

<body>
    <script src="https://d3js.org/d3.v3.min.js"></script>
    <script src="https://d3js.org/d3.geo.tile.v0.min.js"></script>
    <script>
        var access_token = "insert-auth-token-here";

        var p = 2,
            drawlanduses = true;
        var width = Math.max(960, window.innerWidth),
            height = Math.max(500, window.innerHeight),
            prefix = prefixMatch(["webkit", "ms", "Moz", "O"]);

        var tile = d3.geo.tile()
            .size([width, height]);

        var scaleFactor = 6  // no real zooms levels: 1 approx street level; 2 approx neighbourhood; 6 large city level (e.g. SF) 
        var projection = d3.geo.mercator()
            .scale((1 << 21) / scaleFactor)
            .translate([-width / 2, -height / 2]); // just temporary

        var tileProjection = d3.geo.mercator();

        var tilePath = d3.geo.path()
            .projection(tileProjection);

        var zoom = d3.behavior.zoom()
            .scale(projection.scale() * 2 * Math.PI)
            //** note geocoordinates here are lng/lat!
            .translate(projection([-122.35265, 37.77254]).map(function(x) { return -x; }))
            .on("zoom", zoomed);

        var map = d3.select("body").append("div")
            .attr("class", "map")
            .style("width", width + "px")
            .style("height", height + "px")
            .call(zoom)
            .on("mousemove", mousemoved);

        var layerWater = map.append("div")
            .attr("class", "layerWater");

        var layerRoads = map.append("div")
            .attr("class", "layerRoads");

        var layerlanduses = map.append("div")
            .attr("class", "layerlanduses");

        var info = map.append("div")
            .attr("class", "info");

        zoomed();

        function zoomed() {
            var tiles = tile
                .scale(zoom.scale())
                .translate(zoom.translate())
                ();

            projection
                .scale(zoom.scale() / p / Math.PI)
                .translate(zoom.translate());

            var imageWater = layerWater
                .style(prefix + "transform", matrix3d(tiles.scale, tiles.translate))
                .selectAll(".tileWater")
                .data(tiles, function (d) {
                    return d;
                });

            imageWater.exit()
                .each(function (d) {
                    this._xhr.abort();
                })
                .remove();

            imageWater.enter().append("svg")
                .attr("class", "tileWater")
                .style("left", function (d) {
                    return d[0] * 256 + "px";
                })
                .style("top", function (d) {
                    return d[1] * 256 + "px";
                })
                .each(function (d) {
                    var svg = d3.select(this),
                        openStreetMapType = 'water', //'vectiles-land-usages', //'vectiles-landuses', //'vectiles-highroad'
                        url = "https://tiles-" + ["a", "b", "c"][(d[0] * 31 + d[1]) % 3] + ".mapjam.com/" + openStreetMapType + "/" + d[2] + "/" + d[0] + "/" + d[1] + ".json" + "?access_token=" + access_token;
                    this._xhr = d3.json(url, function (error, json) {
                        var k = Math.pow(2, d[2]) * 256; // size of the world in pixels

                        tilePath.projection()
                            .translate([k / 2 - d[0] * 256, k / 2 - d[1] * 256]) // [0°,0°] in pixels
                        .scale(k / 2 / Math.PI);

                        svg.selectAll("path")
                            .data(json.features.sort(function (a, b) {
                                return a.properties.sort_key - b.properties.sort_key;
                            }))
                            .enter().append("path")
                            .attr("class", function (d) {
                                return d.properties.kind;
                            })
                            .attr("d", tilePath);
                    });
                });


            var imageRoads = layerRoads
                .style(prefix + "transform", matrix3d(tiles.scale, tiles.translate))
                .selectAll(".tileRoad")
                .data(tiles, function (d) {
                    return d;
                });

            imageRoads.exit()
                .each(function (d) {
                    this._xhr.abort();
                })
                .remove();

            imageRoads.enter().append("svg")
                .attr("class", "tileRoad")
                .style("left", function (d) {
                    return d[0] * 256 + "px";
                })
                .style("top", function (d) {
                    return d[1] * 256 + "px";
                })
                .each(function (d) {
                    var svg = d3.select(this),
                        openStreetMapType = "road",
                        url = "https://tiles-" + ["a", "b", "c", "d"][(d[0] * 41 + d[1]) % 4] + ".mapjam.com/" + openStreetMapType + "/" + d[2] + "/" + d[0] + "/" + d[1] + ".json" + "?access_token=" + access_token;
                    this._xhr = d3.json(url, function (error, json) {
                        var k = Math.pow(2, d[2]) * 256; // size of the world in pixels

                        tilePath.projection()
                            .translate([k / 2 - d[0] * 256, k / 2 - d[1] * 256]) // [0°,0°] in pixels
                        .scale(k / 2 / Math.PI);

                        svg.selectAll("path")
                            .data(json.features.sort(function (a, b) {
                                return a.properties.sort_key - b.properties.sort_key;
                            }))
                            .enter().append("path")
                            .attr("class", function (d) {
                                return d.properties.class;
                            })
                            .attr("d", tilePath);
                    });
                });

            if (drawlanduses) {
                var imagelanduses = layerlanduses
                    .style(prefix + "transform", matrix3d(tiles.scale, tiles.translate))
                    .selectAll(".tilelanduse")
                    .data(tiles, function (d) {
                        return d;
                    });

                imagelanduses.exit()
                    .each(function (d) {
                        this._xhr.abort();
                    })
                    .remove();

                imagelanduses.enter().append("svg")
                    .attr("class", "tilelanduse")
                    .style("left", function (d) {
                        return d[0] * 256 + "px";
                    })
                    .style("top", function (d) {
                        return d[1] * 256 + "px";
                    })
                    .each(function (d) {
                        var svg = d3.select(this),
                            openStreetMapType = 'landuse',
                            url = "https://tiles-" + ["a", "b", "c"][(d[0] * 31 + d[1]) % 3] + ".mapjam.com/" + openStreetMapType + "/" + d[2] + "/" + d[0] + "/" + d[1] + ".json" + "?access_token=" + access_token;
                        this._xhr = d3.json(url, function (error, json) {
                            var k = Math.pow(2, d[2]) * 256; // size of the world in pixels

                            tilePath.projection()
                                .translate([k / 2 - d[0] * 256, k / 2 - d[1] * 256]) // [0°,0°] in pixels
                            .scale(k / 2 / Math.PI);

                            svg.selectAll("path")
                                .data(json.features.sort(function (a, b) {
                                    return a.properties.sort_key - b.properties.sort_key;
                                }))
                                .enter().append("path")
                                .attr("class", function (d) {
                                    return d.properties.class;
                                })
                                .attr("d", tilePath);
                        });
                    });
            }
        }

        function mousemoved() {
            info.text(formatLocation(projection.invert(d3.mouse(this)), zoom.scale()));
        }

        function matrix3d(scale, translate) {
            var k = scale / 256,
                r = scale % 1 ? Number : Math.round;
            return "matrix3d(" + [k, 0, 0, 0, 0, k, 0, 0, 0, 0, k, 0, r(translate[0] * scale), r(translate[1] * scale), 0, 1] + ")";
        }

        function prefixMatch(p) {
            var i = -1,
                n = p.length,
                s = document.body.style;
            while (++i < n)
                if (p[i] + "Transform" in s) return "-" + p[i].toLowerCase() + "-";
            return "";
        }

        function formatLocation(p, k) {
            var format = d3.format("." + Math.floor(Math.log(k) / 2 - 2) + "f");
            return (p[1] < 0 ? format(-p[1]) + "°S" : format(p[1]) + "°N") + " " + (p[0] < 0 ? format(-p[0]) + "°W" : format(p[0]) + "°E");
        }
    </script>

</body>

</html>