0

私は社会科学者であり、データ vis ワークのために Web プログラミングにますます興味を持っているので、この質問がばかげている場合は申し訳ありません。国レベルのデータを経時的に視覚化するポリマップの実装に取り​​組んでいます。json のテンポラル データと geojson の世界地図を読み込み、月ごとのエントリを繰り返す分位点クロロプレス マップを吐き出します。これの核心は、colorbrewer クラスを国 geojson オブジェクトにバインドする国フォーマット関数です (以下を参照)。これは、アニメーション部分の検索に機能します。問題は、現在表示されているデータの日付を表示するカスタム d3 レイヤーを使用していることです。アニメーションを停止して日付を選択するか、アニメーションが終わったら日付を選択するためのマウスオーバー コントロールとして機能します。これは、d3.scale() 関数を使用してマウス入力を目的の月のインデックスに一致する整数に丸める空の svg 要素を作成することによって行われます。ロード時に他のすべての計算をフロント ロードしたので、マウス オーバー時に発生するのは svg クラスの変更だけです (これは基本的に、Bostock の d3 ページでの Tom Carden の豊富な国の実装と同じです)。残念ながら、これでもブラウザはすぐに過負荷になります。私が完全に見逃しているこれを行う別の方法はありますか?私は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 形式を追加するのを忘れていました。2 か月間のデータについては、以下を参照してください。

[
{"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 に答える