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,用來選擇呈現哪一部分的數據。