block by nivas8292 bec8b161587cb62e9fda

World Map with Zoom slider and Zoom and Pan options

Full Screen

index.html

<html>
    <head>
        <style>
            path {
                stroke:white;
                stroke-width: 0.5px;
                fill:#EBEBE0;
            }

            #float-button-group {
                position:fixed;
                left:10;
                opacity:0.5;
            }

            #float-button-group:hover {
                opacity:1;
            }

            #map {
                background: skyblue;
                width: 965px;
                height: 505px;
                border: 3px solid steelblue;
            }

            #map-zoomer {
                position:absolute;
                writing-mode: bt-lr;
                -webkit-appearance: slider-vertical;
                width: 8px;
                height: 100px;
                padding: 0 5px;
                position: absolute;
                top:110px;
                left:22px;
            }
        </style>
    </head>
    <body>
        <div id="map">
            <div class="btn-group-vertical" role="group" aria-label="..." id="float-button-group">
                <button type="button" class="btn btn-default" id="zoom-in"><span class="glyphicon glyphicon-zoom-in" aria-hidden="true"></span></button>
                <button type="button" class="btn btn-default" id="zoom-out"><span class="glyphicon glyphicon-zoom-out" aria-hidden="true"></span></button>
                <button type="button" class="btn btn-default" id="reset"><span class="glyphicon glyphicon-screenshot" aria-hidden="true"></span></button>
            </div>
            <input type="range" value="1" min="1" max="8" orient="vertical" id="map-zoomer"/>
        </div>
        <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
        <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
        <script src="//d3js.org/d3.v3.min.js"></script>
        <script src="//d3js.org/topojson.v0.min.js"></script>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
        <script>
            var width = d3.select('#map').node().getBoundingClientRect().width,
                    height = d3.select('#map').node().getBoundingClientRect().height;

            var center = [width / 2, height / 2];

            var projection = d3.geo.mercator()
                    .center([0, 10]);
            
            var svg = d3.select("#map")
                    .append("svg")
                    .attr("width", width)
                    .attr("height", height);

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

            var g = svg.append("g");

            d3.json("world-110m2.json", function (error, topology) {
                g.selectAll("path")
                        .data(topojson.object(topology, topology.objects.countries).geometries)
                        .enter()
                        .append("path")
                        .attr("d", path);

                d3.csv("cities.csv", function (error, cities) {

                    svg.selectAll("circle")
                            .data(cities)
                            .enter()
                            .append("circle")
                            .attr("cx", function (d) {
                                return projection([d.lon, d.lat])[0];
                            })
                            .attr("cy", function (d) {
                                return projection([d.lon, d.lat])[1];
                            })
                            .attr("r", 5)
                            .style("fill", "red");
                });
            });

            var zoom = d3.behavior.zoom()
                    .scaleExtent([1, 8])
                    .on("zoom", function () {
                        g.attr("transform", "translate(" + d3.event.translate.join(",") + ") scale(" + d3.event.scale + ")");
                        g.selectAll("path")
                                .attr("d", path.projection(projection));
                        
                        svg.selectAll("circle")
                                .attr("transform", "translate(" + d3.event.translate.join(",") + ") scale(" + d3.event.scale + ")")
                                .transition()
                                .attr("r", 5 / d3.event.scale);
                        d3.select("#map-zoomer").node().value = zoom.scale();
                    });
            svg.call(zoom);

            d3.select('#zoom-in').on('click', function () {
                var scale = zoom.scale(), extent = zoom.scaleExtent(), translate = zoom.translate();
                var x = translate[0], y = translate[1];
                var factor = 1.2;

                var target_scale = scale * factor;

                if (scale === extent[1]) {
                    return false;
                }
                var clamped_target_scale = Math.max(extent[0], Math.min(extent[1], target_scale));
                if (clamped_target_scale != target_scale) {
                    target_scale = clamped_target_scale;
                    factor = target_scale / scale;
                }
                x = (x - center[0]) * factor + center[0];
                y = (y - center[1]) * factor + center[1];

                zoom.scale(target_scale).translate([x, y]);

                g.transition().attr("transform", "translate(" + zoom.translate().join(",") + ") scale(" + zoom.scale() + ")");
                g.selectAll("path")
                        .attr("d", path.projection(projection));

                svg.selectAll("circle")
                        .transition()
                        .attr("transform", "translate(" + zoom.translate().join(",") + ") scale(" + zoom.scale() + ")")
                        .attr("r", 5 / zoom.scale());

                d3.select("#map-zoomer").node().value = zoom.scale();
            });

            d3.select('#zoom-out').on('click', function () {
                var scale = zoom.scale(), extent = zoom.scaleExtent(), translate = zoom.translate();
                var x = translate[0], y = translate[1];
                var factor = 1 / 1.2;

                var target_scale = scale * factor;

                if (scale === extent[0]) {
                    return false;
                }
                var clamped_target_scale = Math.max(extent[0], Math.min(extent[1], target_scale));
                if (clamped_target_scale != target_scale) {
                    target_scale = clamped_target_scale;
                    factor = target_scale / scale;
                }
                x = (x - center[0]) * factor + center[0];
                y = (y - center[1]) * factor + center[1];

                zoom.scale(target_scale).translate([x, y]);

                g.transition()
                        .attr("transform", "translate(" + zoom.translate().join(",") + ") scale(" + zoom.scale() + ")");
                g.selectAll("path")
                        .attr("d", path.projection(projection));

                svg.selectAll("circle")
                        .transition()
                        .attr("transform", "translate(" + zoom.translate().join(",") + ") scale(" + zoom.scale() + ")")
                        .attr("r", 5 / zoom.scale());
                d3.select("#map-zoomer").node().value = zoom.scale();
            });

            d3.select('#reset').on('click', function () {
                zoom.translate([0, 0]);
                zoom.scale(1);
                g.transition().attr("transform", "translate(" + zoom.translate().join(",") + ") scale(" + zoom.scale() + ")");
                g.selectAll("path")
                        .attr("d", path.projection(projection))

                svg.selectAll("circle")
                        .transition()
                        .attr("transform", "translate(" + zoom.translate().join(",") + ") scale(" + zoom.scale() + ")")
                        .transition()
                        .attr("r", 5 / zoom.scale());
                d3.select("#map-zoomer").node().value = zoom.scale();
            });

            d3.select('#map-zoomer').on("change", function () {
                var scale = zoom.scale(), extent = zoom.scaleExtent(), translate = zoom.translate();
                var x = translate[0], y = translate[1];
                var target_scale = +this.value;
                var factor = target_scale / scale;

                var clamped_target_scale = Math.max(extent[0], Math.min(extent[1], target_scale));
                if (clamped_target_scale != target_scale) {
                    target_scale = clamped_target_scale;
                    factor = target_scale / scale;
                }
                x = (x - center[0]) * factor + center[0];
                y = (y - center[1]) * factor + center[1];

                zoom.scale(target_scale).translate([x, y]);

                g.transition()
                        .attr("transform", "translate(" + zoom.translate().join(",") + ") scale(" + zoom.scale() + ")");
                g.selectAll("path")
                        .attr("d", path.projection(projection));

                svg.selectAll("circle")
                        .transition()
                        .attr("transform", "translate(" + zoom.translate().join(",") + ") scale(" + zoom.scale() + ")")
                        .attr("r", 5 / zoom.scale());
            });
        </script>
    </body>

</html>

cities.csv

code,city,country,lat,lon
ZNZ,ZANZIBAR,TANZANIA,-6.13,39.31
TYO,TOKYO,JAPAN,35.68,139.76
AKL,AUCKLAND,NEW ZEALAND,-36.85,174.78
BKK,BANGKOK,THAILAND,13.75,100.48
DEL,DELHI,INDIA,29.01,77.38
SIN,SINGAPORE,SINGAPOR,1.36,103.75
BSB,BRASILIA,BRAZIL,-15.67,-47.43
RIO,RIO DE JANEIRO,BRAZIL,-22.90,-43.24
YTO,TORONTO,CANADA,43.64,-79.40
IPC,EASTER ISLAND,CHILE,-27.11,-109.36
SEA,SEATTLE,USA,47.61,-122.33