D3 - 繪製散點圖

D3繪製散點圖

效果圖
在這裏插入圖片描述
數據來自:https://www.worldbank.org/

完整代碼(不含Initialize初始化數據的函數):

<script src="https://d3js.org/d3.v5.js"></script>
<script>

    let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
    let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    w *= 0.98;
    h *= 0.9;
    let T = new Array();
    let NAME = new Array();
    let RANGE = new Array();
    let Data = new Array();
    // [1] -> population of age range 0~14
    // [2] -> population of age range 15~64
    // [3] -> population of age range 65+

    initialize();
    //初始化數據

    // 內部空間
    let inner = {top: 50, right: 50, bottom: 50, left: 50};

    // 座標軸的定義
    let xScale = d3.scaleLinear()
        .domain([1960, 2018])
        .range([0, w - inner.left - inner.right])
        .nice();

    let xAxis = d3.axisBottom(xScale);

    let yScale = d3.scaleLinear()
        .domain([0, 100])
        .range([h - inner.top - inner.bottom, 0])
        .nice();

    let yAxis = d3.axisLeft(yScale);

    let svg = d3.select("body")
        .append("svg")
        .attr("width", w)
        .attr("height", h)
        .append("g");

    svg.append("g")
        .attr("transform", "translate(" + inner.left + "," + (h - inner.bottom) + ")")
        .call(xAxis);

    svg.append("g")
        .attr("transform", "translate(" + inner.left + "," + (inner.top) + ")")
        .call(yAxis);


    // 重畫某一條線上的數據
    function F(v, t) {
        svg.append("g")
            .selectAll("circle")
            .data(Data[t])
            .enter()
            .append("circle")
            .attr("fill", function (d) {
                if (d[0] === v) return T[d[0] - 1];
            })
            .attr("cx", function (d) {
                if (d[0] === v) return inner.left + xScale(d[1]);
            })
            .attr("cy", function (d) {
                if (d[0] === v) return inner.top + yScale(d[2]);
            })
            .attr("r", 2);
    }

    // 根據點擊次數處理效果
    function FF(v) {
        svg.selectAll("circle").remove();

        for (let k = 1; k <= 3; ++k) {
            for (let i = 1; i <= 13; ++i) {
                if (cnt[i] > 0 && cnt[i] % 2 === 1) {
                    if (ct[k] > 0 && ct[k] % 2 === 1) {
                        F(i, k);
                    }
                }
            }
        }
    }

    // 定義可選的國家的方塊
    let svg2 = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500);

    let cnt = new Array();
    let ct = new Array();
    for (i = 1; i <= 13; ++i) {
        cnt[i] = 0;
    }
    for (i = 1; i <= 3; ++i) ct[i] = 0;

    svg2.selectAll("rect")
        .data(NAME)
        .enter()
        .append("rect")
        .attr("y", function (d, i) {
            return i * 20;
        })
        .attr("x", function (d) {
            return 20;
        })
        .attr("width", 20)
        .attr("height", 20)
        .attr("fill", function (d, i) {
            return T[i];
        })
        .on("click", function (d, i) {
            cnt[i + 1]++;
            FF();
        });

    svg2.selectAll("text")
        .data(NAME)
        .enter()
        .append("text")
        .attr("transform", function (d, i) {
            return "translate(" + (40) + "," + (i * 20 + 15) + ")";
        })
        .attr("fill", 'black')
        .attr("font-size", 10)
        .text(function (d, i) {
            return NAME[i];
        });


    // 定義選擇的數據種類的方塊
    let svg3 = d3.select("body")
        .append("svg")
        .attr("width", 500)
        .attr("height", 500);

    svg3.selectAll("rect")
        .data(RANGE)
        .enter()
        .append("rect")
        .attr("y", function (d, i) {
            return 20;
        })
        .attr("x", function (d, i) {
            return 40 * i + 5;
        })
        .attr("width", 20)
        .attr("height", 20)
        .attr("fill", "red")
        .on("click", function (d, i) {
            ct[i + 1]++;
            FF();
        });

    svg3.selectAll("text")
        .data(RANGE)
        .enter()
        .append("text")
        .attr("text-anchor", "middle")
        .attr("transform", function (d, i) {
            return "translate(" + (i * 40 + 15) + "," + (60) + ")";
        })
        .attr("fill", 'black')
        .attr("font-size", 10)
        .text(function (d, i) {
            return RANGE[i];
        });
</script>

代碼解釋:

    let w = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
    let h = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    w *= 0.98;
    h *= 0.9;

獲得網頁頁面上的可視區域。

    // 座標軸的定義
    let xScale = d3.scaleLinear()
        .domain([1960, 2018])
        .range([0, w - inner.left - inner.right])
        .nice();

    let xAxis = d3.axisBottom(xScale);

    let yScale = d3.scaleLinear()
        .domain([0, 100])
        .range([h - inner.top - inner.bottom, 0])
        .nice();

    let yAxis = d3.axisLeft(yScale);

domain即值域,表示數據的範圍。其中的數據可以是一個區間,也可以是一個數組,可以是離散的數據。
range即映射範圍,設置刻度的輸出範圍值的指定數組。
nice修改規模域,使邊界延伸到最近的整數值。

    // 重畫某一條線上的數據
    function F(v, t) {
        svg.append("g")
            .selectAll("circle")
            .data(Data[t])
            .enter()
            .append("circle")
            .attr("fill", function (d) {
                if (d[0] === v) return T[d[0] - 1];
            })
            .attr("cx", function (d) {
                if (d[0] === v) return inner.left + xScale(d[1]);
            })
            .attr("cy", function (d) {
                if (d[0] === v) return inner.top + yScale(d[2]);
            })
            .attr("r", 2);
    }

以圓圈的形式繪製散點圖。cx,cy表示座標位置。r表示半徑大小。
藉助匿名函數來選擇滿足要求。

後面額外添加了兩個畫布,一個用來表示每個國家對應的顏色。顏色用矩形的形式呈現,後面添加文本。

    svg2.selectAll("rect")
        .data(NAME)
        .enter()
        .append("rect")
        .attr("y", function (d, i) {
            return i * 20;
        })
        .attr("x", function (d) {
            return 20;
        })
        .attr("width", 20)
        .attr("height", 20)
        .attr("fill", function (d, i) {
            return T[i];
        })
        .on("click", function (d, i) {
            cnt[i + 1]++;
            FF();
        });

矩形設置了點擊的事件處理,即點擊該矩形後顯示該國家的數據。

同時增添了一個svg3,用來選擇呈現哪一部分的數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章