0

我是一名社会科学人士,越来越多地从事数据可视化的网络编程,如果这个问题很愚蠢,我深表歉意。我正在研究一个 polymaps 实现,以随着时间的推移可视化国家级数据。我读入 json 时态数据和 geojson 世界地图,并吐出一个分位数的叶绿素地图,该地图在每月的条目上进行迭代。其核心是一个国家格式化函数,它将一个 colorbrewer 类绑定到国家 geojson 对象(见下文)。这适用于动画部分。问题是我正在使用自定义 d3 图层,该图层显示当前显示的数据的日期充当鼠标悬停控件以停止动画并选择日期或在动画结束后选择日期。它通过创建一个空白 svg 元素来实现这一点,该元素使用 d3.scale() 函数将鼠标输入四舍五入为与所需月份索引匹配的整数。我已经在加载时预先加载了所有其他计算,因此鼠标悬停时唯一发生的事情是 svg 类的更改(这与 Tom Carden 在 Bostock 的 d3 页面上的丰富国家实现基本相同。不幸的是,这仍然会很快使浏览器过载。还有另一种我完全想念的方法吗?我承认我是geojson的新手,所以也许有办法在geojson对象的类属性中构造一个类数组?非常感谢您的帮助。

            function foo(local, geojson){
                for(var x=0;x<geojson.length;x++){
                    var n = geojson[x].data.properties.name;
                    n$(geojson[x].element)
                        .attr("class", geojson[x].data.formats[local])
                        .add("svg:title");
                }
            }

编辑:我在下面添加完整的脚本。

<meta charset="utf-8">
<script src="scripts/d3.v3.js"></script>
<script src="scripts/polymaps.js"></script>
<script src="scripts/nns.js"></script>

<script>
    //Polymaps namespace
    var po = org.polymaps;

    //Chart dimensions
    var margin = {top: 20, right: 20, bottom: 20, left: 20};
    var w = 960 - margin.right;
    var h = 500 - margin.top - margin.bottom;

    // Create the map object, add it to #map div
    var map = po.map()
        .container(d3.select("#map").append("svg:svg").attr("width", w + margin.left + margin.right).attr("height",h +margin.top + margin.bottom).node())
        .center({lat: 28, lon: 0})
        .zoom(1.85)
        .zoomRange([1.5, 4.5])
        .add(po.interact());

    // Add the CloudMade image tiles as a base layer…
    map.add(po.image()
        .url(po.url("http://{S}tile.cloudmade.com"
        + "/1a1b06b230af4efdbb989ea99e9841af" // http://cloudmade.com/register
        + "/20760/256/{Z}/{X}/{Y}.png")
        .hosts(["a.", "b.", "c.", ""])));

    //Import contribution data
    d3.json("assets/contributionsTCC1990-1991.json", function(data){
        //find length of json data object and loop over it at interval
        var dataLength = Object.keys(data).length;

        //Create date  key/value array using construtor
        function date_array_constructor() {
            var dateArray = {};
                for(var i = 0; i < dataLength; i++) {
                    var d = i + 1;
                    dateArray[d] =  data[i].date;
                }
            return dateArray;
        }
        var dateArray = date_array_constructor();

        // Insert  date label/control layer and add SVG elements that take on attributes determined by load function
        var labelLayer = d3.select("#map svg").insert("svg:g");
        map.add(po.geoJson()
            .url("assets/world.json")
            .tile(false)
            .zoom(3)
            .on("load", load));
        map.container().setAttribute("class", "Blues");
        map.add(po.compass()
            .pan("none"));

        function find_max(data, dataLength) {
            var max = 0;
            for(var i in data) {
                if(data[i] > max) {
                    max = data[i] + 1;
                }
            }
            return max;
        }

        function max_array_constructor(data, dataLength) {
            var maxArray = {};
            for(var i=0;i<dataLength;i++) {
                var d = i+1;
                maxArray[d] = find_max(data[i].contributions);
            }
            return maxArray;
        }
        var maxArray = max_array_constructor(data, dataLength);

        function contribution_array_constructor(data, dataLength, tccName, feature) {
            var contributions = {};
            //iterate over date entries
            for(var i=0;i<dataLength;i++) {
                //contribution iterator
                contributions[i+1] = 0;
                for(x in data[i].contributions){
                    if(x == tccName) {
                        contributions[i+1] = data[i].contributions[x];
                    }
                }
            }
            return contributions;
        }


        function format_array_constructor(data, dataLength, maxArray, feature) {
            var formats = {};
            // console.log(feature.data.contributions);
            //iterate over date entries
            for(var i=0;i<dataLength;i++) {
                var percentile = feature.data.contributions[i+1] / maxArray[i+1];
                if(percentile != 0){
                    var v = "q" + ((~~(percentile*7)) + 2) + "-" + 9;
                }else{
                    var v = "countries";
                }
                formats[i+1] = v;
            }
            return formats;
        }


        ///////////////////////////////
        //load function
        ///////////////////////////////
        function load(e) {
            //Bind geojson and json
            var geojson = e.features;
            console.log(geojson);
            geojson.dates = dateArray;
            for(var x = 0; x < geojson.length; x++) {
                // var tccID = geojson[x].data.id;
                var tccName = geojson[x].data.properties.name;
                geojson[x].data.contributions = contribution_array_constructor(data, dataLength, tccName, geojson[x]);
                geojson[x].data.formats = format_array_constructor(data, dataLength, maxArray, geojson[x]);
            }


            //Insert date label
            var dateLabel = labelLayer.append("text")
                .attr("class", "date label")
                .attr("text-anchor", "end")
                .attr("x", w-670)
                .attr("y", h )
                .text(dateArray[1]);

            //Add interactive overlay for date label
            var box = dateLabel.node().getBBox();

            var overlay = labelLayer.append("rect")
                .attr("class", "overlay")
                .attr("x", box.x)
                .attr("y", box.y)
                .attr("opacity",0)
                .attr("width", box.width)
                .attr("height", box.height)
                .on("mouseover",enable_interaction);


            function country_class_constructor(local, geojson){
                for(var x=0;x<geojson.length;x++){
                    var n = geojson[x].data.properties.name;
                    n$(geojson[x].element)
                        .attr("class", geojson[x].data.formats[local])
                        .add("svg:title");
                }
            }

            function foo(local, geojson){
                for(var x=0;x<geojson.length;x++){
                    var n = geojson[x].data.properties.name;
                    n$(geojson[x].element)
                        .attr("class", geojson[x].data.formats[local])
                        .add("svg:title");
                }
            }

            //incrementor function
            function incrementor(local, geojson, dateArray) {
                setTimeout(function() {
                    //set date label to current iteration
                    d3.transition(dateLabel).text(dateArray[local]);
                    //construct country classes
                    country_class_constructor(local, geojson);
                    // console.log(geojson);
                }, 500*local);
            }

            ///////////////////////////////
            //Increment on load
            ///////////////////////////////
            country_class_constructor(1, geojson)
            for(var i=1; i< dataLength; i++) {
                //Set incrementer as local variable
                var local = i+1;
                var timer = incrementor(local, geojson, dateArray);
            }


            ///////////////////////////////
            //interaction element
            ///////////////////////////////
            function enable_interaction(){
                var dateScale = d3.scale.linear()
                    .domain([1,Object.keys(dateArray).length])
                    .range([box.x + 10, box.x + box.width - 10])
                    .clamp(true);

            timer = null;


                overlay
                    .on("mouseover", mouse_over)
                    .on("mouseout",mouse_out)
                    .on("mousemove",mouse_move)
                    .on("touchmove",mouse_move);

                function mouse_over() {
                    dateLabel.classed("active", true);
                }

                function mouse_out() {
                    dateLabel.classed("active", false);
                }

                function mouse_move() {
                    update_map(dateScale.invert(d3.mouse(this)[0]),data);
                    // displayYear(dateScale.invert(d3.mouse(this)[0]));
                }

                function update_map(userInput) {
                    var date = Math.floor(userInput);
                    d3.transition(dateLabel).text(dateArray[date]);
                    // console.log(date);
                    // country_class_constructor(date, geojson);
                    foo(date, geojson);
                }
            }
        }
    });
</script>

编辑 2:我忘了添加 JSON 格式。两个月的数据见下图:

[
{"date":"11/90",
 "contributions":{
    "Algeria":7,
    "Argentina":39,
    "Australia":41,
    "Austria":967,
    "Bangladesh":5,
    "Belgium":4,
    "Brazil":27,
    "Canada":1002,
    "Chile":7,
    "China":5,
    "Colombia":12,
    "Czech Republic":6,
    "Denmark":374,
    "Ecuador":21,
    "Fiji":719,
    "Finland":992,
    "France":525,
    "Germany":13,
    "Ghana":892,
    "Hungary":15,
    "India":40,
    "Indonesia":5,
    "Ireland":814,
    "Italy":79,
    "Jordan":6,
    "Kenya":7,
    "Malaysia":15,
    "Nepal":851,
    "Netherlands":15,
    "New Zealand":22,
    "Nigeria":2,
    "Norway":924,
    "Poland":165,
    "Republic of the Congo":6,
    "Russia":35,
    "Senegal":4,
    "Serbia":17,
    "Spain":63,
    "Sweden":738,
    "Switzerland":5,
    "Turkey":2,
    "United Kingdom":769,
    "United States":33,
    "Uruguay":10,
    "Venezuela":23,
    "Zambia":6
 }
},
{"date":"12/90",
 "contributions":{
    "Algeria":7,
    "Argentina":39,
    "Australia":41,
    "Austria":967,
    "Bangladesh":5,
    "Belgium":4,
    "Brazil":27,
    "Canada":1002,
    "Chile":7,
    "China":5,
    "Colombia":12,
    "Czech Republic":6,
    "Denmark":374,
    "Ecuador":21,
    "Fiji":719,
    "Finland":992,
    "France":525,
    "Germany":13,
    "Ghana":892,
    "Hungary":15,
    "India":40,
    "Indonesia":5,
    "Ireland":814,
    "Italy":79,
    "Jordan":6,
    "Kenya":7,
    "Malaysia":15,
    "Nepal":851,
    "Netherlands":15,
    "New Zealand":22,
    "Nigeria":2,
    "Norway":924,
    "Poland":165,
    "Republic of the Congo":6,
    "Russia":35,
    "Senegal":4,
    "Serbia":17,
    "Spain":63,
    "Sweden":738,
    "Switzerland":5,
    "Turkey":2,
    "United Kingdom":769,
    "United States":33,
    "Uruguay":10,
    "Venezuela":23,
    "Zambia":6
 }
}

]

4

1 回答 1

1

经过数小时的调试,结果是 nns.js 库给我带来了问题。动画的每次迭代都在创建一组新的 DOM 对象,这些对象开始在 25,000 处最大化浏览器。解决方案是使用 nss 创建初始状态,然后使用以下函数更改每个 svg 元素的类。

function country_class_constructor(local, geojson){
                for(var x=0;x<geojson.length;x++){
                    var n = geojson[x].data.properties.name;
                    element = document.getElementById(n);
                    element.className["animVal"] = geojson[x].data.formats[local];
                    element.className["baseVal"] = geojson[x].data.formats[local];
}
于 2013-05-02T20:44:43.533 回答