我在D3中是新手。我正在尝试根据一组国家绘制棒棒糖图表。在html页面上,我放置了一些按钮,允许用户根据国家所属的大陆来更改国家/地区的选择。
加载页面后,图表已成功呈现,但单击按钮后出现错误。
例如,当我单击“亚洲”按钮时,图表可以显示该线,但圆圈缺失。
当我单击“概述”按钮并尝试查看国家的概述时,图表仅显示了我刚才看到的亚洲国家/地区的线。其他国家的电话不见了,他们的圈子也没了。
我正在遵循this example尝试使用.enter和.exit函数更新图表,但如示例所示,我无法更新图表。
数据集:
par_code,continent,country,date_1,camp_1,date_2,camp_2,date_3,camp_3
P027,Asia,China,09/05/2018,BBB,14/12/2018,AAA,,
P030,Asia,India,09/05/2018,BBB,18/09/2018,AAA,26/10/2018,CCC
P038,North America,United States,09/05/2018,BBB,14/12/2018,AAA,,
P042,Asia,Indonesia,09/05/2018,BBB,14/12/2018,AAA,,
P056,South America,Brazil,09/05/2018,BBB,14/12/2018,AAA,,
P058,Asia,Pakistan,09/05/2018,BBB,24/06/2018,AAA,28/11/2018,CCC
P059,Africa,Nigeria,09/05/2018,BBB,27/06/2018,AAA,,
P092,Asia,Bangladesh,09/05/2018,BBB,14/12/2018,AAA,,
P115,Europe,Russia,09/05/2018,AAA,13/05/2018,CCC,,
P134,Asia,Japan,09/05/2018,BBB,01/07/2018,AAA,13/12/2018,CCC
P154,North America,Mexico,09/05/2018,BBB,14/12/2018,AAA,,
P166,Asia,Philippines,09/05/2018,BBB,26/10/2018,FFF,,
P167,Asia,Vietnam,09/05/2018,BBB,12/12/2018,AAA,,
P168,Africa,Ethiopia,09/05/2018,BBB,25/10/2018,DDD,,
P170,Europe,Germany,09/05/2018,BBB,10/05/2018,EEE,,
P176,Africa,Egypt,09/05/2018,BBB,19/09/2018,AAA,,
P177,Asia,Iran,09/05/2018,BBB,12/12/2018,AAA,,
P180,Asia,Turkey,09/05/2018,AAA,25/10/2018,DDD,,
P182,Africa,Democratic Republic of the Congo,09/05/2018,BBB,25/10/2018,DDD,,
P183,Asia,Thailand,09/05/2018,BBB,12/12/2018,AAA,,
P184,Europe,France,09/05/2018,BBB,12/12/2018,AAA,,
P193,Europe,United Kingdom,09/05/2018,BBB,12/06/2018,CCC,,
P194,Europe,Italy,09/05/2018,BBB,12/06/2018,CCC,,
P197,Asia,Myanmar,09/05/2018,BBB,12/06/2018,CCC,,
P199,Africa,South Africa,09/05/2018,BBB,12/06/2018,CCC,,
P200,Asia,South Korea,09/05/2018,BBB,12/06/2018,CCC,,
P201,Europe,Spain,09/05/2018,BBB,12/06/2018,CCC,,
P202,Europe,Ukraine,09/05/2018,BBB,12/06/2018,CCC,,
P203,South America,Colombia,09/05/2018,AAA,12/05/2018,CCC,,
P204,Africa,Tanzania,09/05/2018,BBB,12/06/2018,CCC,,
P206,Africa,Sudan,09/05/2018,BBB,12/06/2018,CCC,,
P207,Africa,Kenya,09/05/2018,BBB,12/06/2018,CCC,,
P209,South America,Argentina,09/05/2018,AAA,12/05/2018,CCC,,
P210,Europe,Poland,09/05/2018,BBB,12/06/2018,CCC,,
P213,Africa,Algeria,09/05/2018,BBB,12/06/2018,CCC,,
P215,North America,Canada,09/05/2018,BBB,12/06/2018,CCC,,
P216,Asia,Iraq,09/05/2018,BBB,12/06/2018,CCC,,
P217,Africa,Morocco,09/05/2018,BBB,12/06/2018,CCC,,
P218,Africa,Uganda,09/05/2018,BBB,12/06/2018,CCC,,
P220,South America,Peru,09/05/2018,BBB,12/06/2018,CCC,,
P221,South America,Venezuela,09/05/2018,BBB,12/06/2018,CCC,,
P222,Asia,Malaysia,09/05/2018,BBB,12/06/2018,CCC,,
我用于更新图表的HTML页面上的按钮:
<button onclick="updateChart('Overview')">Overview</button>
<button onclick="updateChart('Asia')">Asia</button>
<button onclick="updateChart('Africa')">Africa</button>
<button onclick="updateChart('Europe')">Europe</button>
<button onclick="updateChart('North America')">North America</button>
<button onclick="updateChart('South America')">South America</button>
完整的js代码:
const margin = { top: 20, right: 20, bottom: 50, left: 85 };
const width = 900;
const height = 700;
const svg = d3.select('#lollipop')
.append('svg')
.attr('width', width)
.attr('height', height)
.attr('viewBox', '0 0 ' + Math.min(width, height) + ' ' + Math.min(width,
height))
.attr('preserveAspectRatio', 'xMinYMin')
const g = svg.append('g')
.attr('transform', `translate(${margin.left}, ${margin.top})`);
const parseTime = d3.timeParse("%d/%m/%Y");
const xScale = d3.scaleTime()
.range([0, (width - margin.right - margin.left)]);
const yScale = d3.scaleBand()
.range([0, (height - margin.bottom - margin.top)])
.padding(1);
function x_gridlines() {
return d3.axisTop(xScale)
.ticks(5)
}
const beginDate = parseTime("01/05/2018");
let transTime = 100;
let duration;
let latestDate;
let dates = [];
let parsedDates;
d3.csv('../data/lollipop.csv')
.then(data => {
data.forEach(d => {
d.continent = d.continent;
d.country = d.country;
d.camp_1 = d.camp_1;
d.camp_2 = d.camp_2;
d.camp_3 = d.camp_3;
// determine latest date for x-axis
for (let i = 1; i <= 3; i++) {
const date = `date_${i}`;
if (d[date] !== '') {
if (dates.indexOf(d[date]) === -1) {
dates.push(d[date]);
}
}
}
d.date_1 = parseTime(d.date_1);
d.date_2 = parseTime(d.date_2);
d.date_3 = parseTime(d.date_3);
if (d.date_3) {
duration = d.date_3 - d.date_1;
} else {
duration = d.date_2 - d.date_1;
}
d.duration = duration;
});
parsedDates = dates.map(date => parseTime(date));
latestDate = d3.max(parsedDates);
// sort MP list according to duration
data.sort((a, b) => {
return a.duration - b.duration;
})
let jumpList = data.map(d => d.country);
console.log(jumpList);
xScale.domain([beginDate, latestDate]);
yScale.domain(jumpList);
// grid
g.append('g')
.attr('class', 'grid')
.attr('transform', 'translate(0,0)')
.call(x_gridlines()
.tickSize(-height + margin.bottom + margin.top)
.tickFormat('')
)
// define axes
g.append('g')
.attr('class', 'axis, x-axis')
.call(d3.axisTop(xScale)
.ticks(5)
.tickFormat(d3.timeFormat('%b %Y')));
g.append('g')
.attr('class', 'axis, y-axis')
.call(d3.axisLeft(yScale));
// add lines
const timeline = g.selectAll('.timeline')
.data(data, d => d.par_code);
timeline.enter()
.append('line')
.attr('class', 'timeline')
.attr('x1', d => xScale(d.date_1))
.attr('y1', d => yScale(d.country))
.attr('x2', d => {
if (d.date_3) {
return xScale(d.date_3);
} else if (d.date_2) {
return xScale(d.date_2);
}
})
.attr('y2', d => yScale(d.country))
.attr('stroke', 'grey');
// add circles
for (let i = 1; i <= 3; i++) {
const date = `date_${i}`;
const camp = `camp_${i}`;
g.selectAll('.circle')
.data(data, d => d.par_code)
.enter()
.append('circle')
.attr('class', 'time-circle')
.attr('cx', d => xScale(d[date]))
.attr('cy', d => yScale(d.country))
.attr('r', '3')
.style('fill', d => campColor(d[camp]));
}
})
function updateChart(area) {
d3.csv('../data/lollipop.csv')
.then(data => {
if (area === 'Asia') {
data = data.filter(d => d.continent === 'Asia');
} else if (area === 'Europe') {
data = data.filter(d => d.continent === 'Europe');
} else if (area === 'South America') {
data = data.filter(d => d.continent === 'South America');
} else if (area === 'Africa') {
data = data.filter(d => d.continent === 'Africa');
} else if (area === 'North America') {
data = data.filter(d => d.continent === 'North America');
} else {
data = data;
}
data.forEach(d => {
d.continent = d.continent;
d.country = d.country;
d.camp_1 = d.camp_1;
d.camp_2 = d.camp_2;
d.camp_3 = d.camp_3;
// determine latest date for x-axis
for (let i = 1; i <= 3; i++) {
const date = `date_${i}`;
if (d[date] !== '') {
if (dates.indexOf(d[date]) === -1) {
dates.push(d[date]);
}
}
}
d.date_1 = parseTime(d.date_1);
d.date_2 = parseTime(d.date_2);
d.date_3 = parseTime(d.date_3);
if (d.date_3) {
duration = d.date_3 - d.date_1;
} else {
duration = d.date_2 - d.date_1;
}
d.duration = duration;
});
// sort MP list according to duration
data.sort((a, b) => {
return a.duration - b.duration;
})
// latestDate = d3.max(parsedDates);
// console.log(latestDate);
let jumpList = data.map(d => d.country);
yScale.domain(jumpList);
g.select('.y-axis')
.transition()
.duration(transTime)
.call(d3.axisLeft(yScale));
// change lines position
let timeline = g.selectAll('.timeline').data(data);
timeline.exit().remove();
timeline.enter()
.append('line');
timeline.transition()
.attr('x1', (d) => xScale(d.date_1))
.attr('y1', (d) => yScale(d.country))
.attr('x2', (d) => {
if (d.date_3) {
return xScale(d.date_3);
} else if (d.date_2) {
return xScale(d.date_2);
}
})
.attr('y2', (d) => yScale(d.country))
.attr('stroke', 'grey');
let newCircles = g.selectAll('.time-circle').data(data);
newCircles.exit().remove();
newCircles.enter()
.append('circle')
// change circles position
for (let i = 1; i <= 3; i++) {
const date = `date_${i}`;
const camp = `camp_${i}`;
newCircles.transition()
.duration(transTime)
.attr('cx', d => {
return xScale(d[date])
})
.attr('cy', d => yScale(d.country))
.attr('r', '3')
.style('fill', d => {
return campColor(d[camp])
});
}
})
}
const campColor = (camp) => {
if (camp === 'AAA') {
return 'rgba(237,28,36,1)'
} else if (camp === 'BBB') {
return 'rgba(0,0,128,1)'
} else if (camp === 'CCC') {
return 'rgba(0,144,0,1)'
} else if (camp === 'DDD') {
return 'rgba(254,223,0,1)'
} else if (camp === 'EEE') {
return 'rgba(26,26,26,1)'
} else if (camp === 'FFF') {
return 'rgba(237,28,36,0.67)'
} else if (camp === 'GGG') {
return 'rgba(237,28,36,0.33)'
} else {
return 'rgba(255,165,0,1)';
}
}
我知道由于功能太相似而无法加载和更新同一张图表,这看起来很愚蠢,但这是我到目前为止所知道的。
因此,除了向我展示如何正确地用圆圈更新图表外,我还需要有关如何更好地重组代码的帮助。
我先谢谢你。