0

I am new to d3.js. Trying to understand the cartogram example give in http://prag.ma/code/d3-cartogram/ . Here they gave example for USA map. I am trying the same for World Map to see how things works. My cartogram map has lines in between. My data has values for only few countries so I am setting the rest of the country's value as low or 0.

<!DOCTYPE html>
<html>
<head>
    <title>Cartograms with d3 &amp; TopoJSON</title>
    <meta charset="utf-8">
    <meta property="og:image" content="placeholder.png">
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="lib/colorbrewer.js"></script>
    <script src="lib/topojson.js"></script>
    <script src="cartogram.js"></script>
    <style type="text/css">

        body {
            font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
            font-size: 14px;
            line-height: 1.4em;
            padding: 0;
            margin: 0;
        }

        #container {
            width: 960px;
            margin: 20px auto;
        }

        h1 {
            font-size: 200%;
            margin: 0 0 15px 0;
        }

        h2 {
            font-size: 160%;
            margin: 0 0 10px 0;
        }

        p {
            margin: 0 0 10px;
        }

        form, form > * {
            margin: 0;
        }

        #status {
            color: #999;
        }

        #map-container {
            height: 700px;
            text-align: center;
            position: relative;
            margin: 20px 0;
        }

        #map {
            display: block;
            position: absolute;
            background: #fff;
            width: 100%;
            height: 100%;
            margin: 0;
        }

        path.state {
            stroke: #666;
            stroke-width: .5;
        }

        path.state:hover {
            stroke: #000;
        }

        form {
            font-size: 120%;
        }

        select {
            font-size: inherit;
        }

        #placeholder {
            position: absolute;
            z-index: -1;
            display: block;
            left: 0;
            top: 0;
        }

    </style>
</head>
<body>
<div id="container">
    <h1>Cartograms with d3 &amp; TopoJSON</h1>
    <form>
        <p>
            <label>Scale by <select id="field"></select></label>
            <span id="status"></span>
        </p>
    </form>
    <div id="map-container">
        <svg id="map"></svg>
    </div>


</div>
<script>


    var margin = 1,
            width = 970 - margin,
            height = 700 - margin;

    if (!document.createElementNS) {
        document.getElementsByTagName("form")[0].style.display = "none";
    }
   var percent = (function() {

                var fmt = d3.format(".2f");
                return function(n) { return fmt(n) + "%"; };
            })(),
            fields = [
                {name: "(no scale)", id: "none"},
                {name: "Internet_Users", id: "internet", key: "Internet_Users", format : percent},
                {name: "GDP", id: "gdp", key: "GDP"},
                {name: "Literacy_rates", id: "literacy", key: "Literacy_rates", format : percent},
                {name: "female_male", id: "fm", key: "female_male"},
                {name: "Population", id: "pop", key: "Population"},
            ],

            fieldsById = d3.nest()
                    .key(function(d) { return d.id; })
                    .rollup(function(d) { return d[0]; })
                    .map(fields),
            field = fields[0],
            colors = colorbrewer.RdYlBu[3]
                    .reverse()
                    .map(function(rgb) { return d3.hsl(rgb); });

    var body = d3.select("body"),
            stat = d3.select("#status");

    var fieldSelect = d3.select("#field")
            .on("change", function(e) {
                field = fields[this.selectedIndex];
                location.hash = "#" + [field.id]
            });

    fieldSelect.selectAll("option")
            .data(fields)
            .enter()
            .append("option")
            .attr("value", function(d) { return d.id; })
            .text(function(d) { return d.name; });

    var map = d3.select("#map").attr("width", width + margin)
                    .attr("height", height + margin),
            zoom = d3.behavior.zoom()
                    .translate([-38, 32])
                    .scale(.95)
                    .scaleExtent([0.5, 10.0])
                    .on("zoom", updateZoom),
            layer = map.append("g")
                    .attr("id", "layer"),
            states = layer.append("g")
                    .attr("id", "states")
                    .selectAll("path");

    updateZoom();

    function updateZoom() {
        var scale = zoom.scale();
        layer.attr("transform",
                "translate(" + zoom.translate() + ") " +
                "scale(" + [scale, scale] + ")");
    }

    var proj = d3.geo.mercator().scale(145).translate([width / 2, height / 1.5]),
            topology,
            geometries,
            rawData,

            dataById = {},
            carto = d3.cartogram()
                    .projection(proj)
                    .properties(function(d) {
                        return dataById[d.id];
                    })
                    .value(function(d) {
                        return +d.properties[field];


                    });

    window.onhashchange = function() {
        parseHash();
    };

    d3.json("data/world_countries_topo.json", function(topo) {
        topology = topo;
        //  console.log("T",topology)
        geometries = topology.objects.countries.geometries;

        d3.csv("data/parallel_score.csv", function(data) {
            rawData = data;
            dataById = d3.nest()
                    .key(function(d) { return d.Id; })
                    .rollup(function(d) { return d[0]; })
                    .map(data);
            init();
        });
    });

    function init() {
        var features = carto.features(topology, geometries),
                path = d3.geo.path()
                        .projection(proj);

        states = states.data(features)
                .enter()
                .append("path")
                .attr("class", "state")
                .attr("id", function(d) {
                    return d.Id;
                })
                .attr("fill", "#000")
                .attr("d", path);

        states.append("title");

        parseHash();
    }

    function reset() {
        stat.text("");
        body.classed("updating", false);

        var features = carto.features(topology, geometries),
                path = d3.geo.path()
                        .projection(proj);

        states.data(features)
                .transition()
                .duration(750)
                .ease("linear")
                .attr("fill", "#fafafa")
                .attr("d", path);

        states.select("title")
                .text(function(d) {

                    return d.Id;
                });
    }

    function update() {
        var start = Date.now();
        body.classed("updating", true);

        var key = field.key

        var  fmt = (typeof field.format === "function")
                        ? field.format
                        : d3.format(field.format || ","),
                value = function(d) {
                    if(d.properties == undefined){}

                    else {
                       return +d.properties[key];
                    }
                },
                values = states.data()
                        .map(value)
                        .filter(function(n) {
                            return !isNaN(n);
                        })
                        .sort(d3.ascending),
                lo = values[0],
                hi = values[values.length - 1];
        console.log("L",lo)
        console.log("H",hi)

        var color = d3.scale.linear()
                .range(colors)
                .domain(lo < 0
                        ? [lo, 0, hi]
                        : [lo, d3.mean(values), hi]);

        // normalize the scale to positive numbers
        var scale = d3.scale.linear()
                .domain([lo, hi])
                .range([1, 1000]);

        // tell the cartogram to use the scaled values
        carto.value(function(d) {
            if( value(d) == undefined) {
                return lo
            }

            else {
                console.log("SCale", (value(d)))
                return scale(value(d));
            }
        });

        // generate the new features, pre-projected
        var features = carto(topology, geometries).features;

        // update the data
        states.data(features)
                .select("title")
        /*.text(function(d) {
         return [d.properties.Id, fmt(value(d))].join(": ");
         });*/

        states.transition()
                .duration(750)
                .ease("linear")
                .attr("fill", function(d) {
                    if(d.properties == undefined){
                        return color(lo)
                    }
                    else {

                        return color(value(d));
                    }
                })
                .attr("d", carto.path);

        var delta = (Date.now() - start) / 1000;
        stat.text(["calculated in", delta.toFixed(1), "seconds"].join(" "));
        body.classed("updating", false);
    }

    var deferredUpdate = (function() {
        var timeout;
        return function() {
            var args = arguments;
            clearTimeout(timeout);
            stat.text("calculating...");
            return timeout = setTimeout(function() {
                update.apply(null, arguments);
            }, 10);
        };
    })();

    var hashish = d3.selectAll("a.hashish")
            .datum(function() {
                return this.href;
            });

    function parseHash() {
        var parts = location.hash.substr(1).split("/"),
                desiredFieldId = parts[0],

                field = fieldsById[desiredFieldId] || fields[0];

        fieldSelect.property("selectedIndex", fields.indexOf(field));

        if (field.id === "none") {

            reset();

        } else {


            deferredUpdate();
            location.replace("#" + [field.id].join("/"));

            hashish.attr("href", function(href) {
                return href + location.hash;
            });
        }
    }

</script>
</body>
</html>

Here is the link of my map: My Map

Can Someone please explain me why I am getting this line.

Thanks.

4

1 回答 1

0

大约一年前我们遇到了同样的问题,这是由于 topojson 文件中的弧从 180 或 360 移回 0,基本上环绕在地图的末端。

我们需要手动进入地图文件并使用 QGIS 对其进行编辑。

这解决了线的问题。

如果您使用 Cartogram 代码,您还会发现世界地图远比您需要的详细,因为无论如何您都会扭曲地图。如果您实时生成图表,那么您将面临代码延迟。

您也应该降低地图的复杂性。

这是我们用来在浏览器中创建实时六边形地图的 JSON 示例。

简化的世界地图 JSON

于 2015-04-23T23:27:07.253 回答