处理Polymaps中的类属性赋值

时间:2013-04-24 15:09:42

标签: css d3.js javascript-objects geojson

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

            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
 }
}

1 个答案:

答案 0 :(得分:0)

经过数小时的调试,结果发现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];
}