javascript - D3.js 放大面积图,如果 y 域取负值,则行为怪异
问题描述
我一直在尝试用缩放做一个面积图,除非我给 Y 域一个负值,否则效果很好。如果我不尝试沿 y 轴缩放,它看起来很棒
我已经尝试使用 y 的最小值作为 y0 并且修复了渲染(它看起来很糟糕,并且它在没有价值的地方渲染了 X)。
// set the dimensions and margins of the graph
let margin = {
top: 0,
right: 0,
bottom: 30,
left: 30
},
width = 440 - margin.left - margin.right,
height = 240 - margin.top - margin.bottom;
// append the svg object to the body of the page
let svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/dimitriiBirsan/RandomNumbersYear1970-2031/main/testing%20negative%20numbers.csv",
// When reading the csv, I must format variables:
function(d) {
return {
date: d3.timeParse("%m/%d/%Y")(d.date),
value: d.value
}
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
let x = d3.scaleTime()
.domain(d3.extent(data, function(d) {
return +d.date;
}))
.range([0, width]);
let xAxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(4));
// Add Y axis
let y = d3.scaleLinear()
.domain(d3.extent(data, function(d) {
return +d.value;
}))
.range([height, 0]);
let yAxis = svg.append("g")
.call(d3.axisLeft(y));
function make_x_gridlines(x) {
return d3.axisBottom(x)
}
function make_y_gridlines(y) {
return d3.axisLeft(y)
}
// Add a clipPath : everything out of this area won't be drawn
let clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("x", 0)
.attr("y", 0);
// Add the area
let line = svg.append('g')
.attr("clip-path", "url(#clip)")
line.append("path")
.datum(data)
.attr("class", "polyArea")
.attr("fill", "blue")
.attr("opacity", 0.7)
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.area()
.x(function(d) {
return x(d.date)
})
.y0(y(0))
.y1(function(d) {
return y(d.value)
})
.curve(d3.curveStepAfter)
.defined((d, i) => (i != null))
);
let zoom = d3.zoom()
.scaleExtent([1, 50]) // This control how much you can unzoom (x0.5) and zoom (x20)
.translateExtent([
[0, 0],
[width, height]
])
.extent([
[0, 0],
[width, height]
])
.on("zoom", updateChart);
// This adds an invisible rect on top of the chart area. This rect can recover pointer events: necessary to understand when the user zoom
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.attr('transform', 'translate(' + margin.top + ')')
.call(zoom);
function updateChart() {
// recover the new scale
let newX = d3.event.transform.rescaleX(x);
let newY = d3.event.transform.rescaleY(y);
// update axes with these new boundaries
xAxis.call(d3.axisBottom(newX).ticks(5))
yAxis.call(d3.axisLeft(newY))
// update location
svg
.select('.polyArea')
.attr("d", d3.area()
.x(function(d) {
return newX(d.date)
})
.y0(y(0))
.y1(function(d) {
return newY(d.value)
})
.curve(d3.curveStepAfter)
.defined((d, i) => (i != null)))
}
})
.grid line {
stroke: grey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width 0;
}
<main>
<div id="my_dataviz">
</div>
</main>
<script src="https://d3js.org/d3.v4.js"></script>
解决方案
当您缩放时,您忘记使用newY(0)
而不是y(0)
现在,零线是它应该在的位置,而不是您开始时的位置
// set the dimensions and margins of the graph
let margin = {
top: 0,
right: 0,
bottom: 30,
left: 30
},
width = 440 - margin.left - margin.right,
height = 240 - margin.top - margin.bottom;
// append the svg object to the body of the page
let svg = d3.select("#my_dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv("https://raw.githubusercontent.com/dimitriiBirsan/RandomNumbersYear1970-2031/main/testing%20negative%20numbers.csv",
// When reading the csv, I must format variables:
function(d) {
return {
date: d3.timeParse("%m/%d/%Y")(d.date),
value: d.value
}
},
// Now I can use this dataset:
function(data) {
// Add X axis --> it is a date format
let x = d3.scaleTime()
.domain(d3.extent(data, function(d) {
return +d.date;
}))
.range([0, width]);
let xAxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).ticks(4));
// Add Y axis
let y = d3.scaleLinear()
.domain(d3.extent(data, function(d) {
return +d.value;
}))
.range([height, 0]);
let yAxis = svg.append("g")
.call(d3.axisLeft(y));
function make_x_gridlines(x) {
return d3.axisBottom(x)
}
function make_y_gridlines(y) {
return d3.axisLeft(y)
}
// Add a clipPath : everything out of this area won't be drawn
let clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("x", 0)
.attr("y", 0);
// Add the area
let line = svg.append('g')
.attr("clip-path", "url(#clip)")
line.append("path")
.datum(data)
.attr("class", "polyArea")
.attr("fill", "blue")
.attr("opacity", 0.7)
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.area()
.x(function(d) {
return x(d.date)
})
.y0(y(0))
.y1(function(d) {
return y(d.value)
})
.curve(d3.curveStepAfter)
.defined((d, i) => (i != null))
);
let zoom = d3.zoom()
.scaleExtent([1, 50]) // This control how much you can unzoom (x0.5) and zoom (x20)
.translateExtent([
[0, 0],
[width, height]
])
.extent([
[0, 0],
[width, height]
])
.on("zoom", updateChart);
// This adds an invisible rect on top of the chart area. This rect can recover pointer events: necessary to understand when the user zoom
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.attr('transform', 'translate(' + margin.top + ')')
.call(zoom);
function updateChart() {
// recover the new scale
let newX = d3.event.transform.rescaleX(x);
let newY = d3.event.transform.rescaleY(y);
// update axes with these new boundaries
xAxis.call(d3.axisBottom(newX).ticks(5))
yAxis.call(d3.axisLeft(newY))
// update location
svg
.select('.polyArea')
.attr("d", d3.area()
.x(function(d) {
return newX(d.date)
})
.y0(newY(0))
.y1(function(d) {
return newY(d.value)
})
.curve(d3.curveStepAfter)
.defined((d, i) => (i != null)))
}
})
.grid line {
stroke: grey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width 0;
}
<main>
<div id="my_dataviz">
</div>
</main>
<script src="https://d3js.org/d3.v4.js"></script>
推荐阅读
- git - 本地 Git 无法在配置中使用“ssh://”解析主机名,并且在没有密码的情况下要求输入密码
- sql - 使用子查询返回匹配行以在另一个表中创建列表?
- java - 如何测试 MapStruct 映射器实现并模拟其依赖项
- mysql - 如何在 SQL 中将 where 条件用于新创建的列以计数使用的 group by
- javascript - CKEditor 和 Jinja 模板(控制台错误)
- r - 从两个人一起处理一个问题的数据框实例中提取,加上时间和问题名称
- java - 如何在 android studio 中添加 Recycler 视图
- sharepoint - 身份验证后的 SharePoint 2019 随机问题
- swift - 如何接受类类型的数组作为参数
- amazon-web-services - 如何在 ECS 服务上设置 desiredCount?