- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个形状——用 D3 的区域生成器创建——有四个不同的区域。我有一个函数:draw_graph(region, data),它将形状区域和数据集作为输入。该函数用一个矩形包围该区域,并根据数据集在矩形内填充一个散点图。
我的问题是 draw_graph 仅在调用它的前两次填充图形。它会在每次调用时正确生成 x 轴和 y 轴以及封闭矩形。但它只填充了拳头两个图表。区域的顺序无关紧要。只有调用函数的顺序
Draw_graph 以前只填充它绘制的第一个图形。然后我从使用随机生成的数组作为数据切换到使用硬编码数组。使用硬编码数组,该函数开始填充前两个图。然后我切换回使用随机生成的数组并且行为没有恢复。
这是我的代码的链接。 draw_graph 函数从第 99 行开始:
这是一个正在运行的片段:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://unpkg.com/d3@5.9.1/dist/d3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
//add svg
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500)
.attr('stoke', 'red');
//////////////GENERATEs AREA/////////////
// //Append a defs
var defs = svg.append("defs");
//Append a linearGradient element to the defs and give it a unique id
var linearGradient = defs.append("linearGradient")
.attr("id", "linear-gradient");
//Horizontal gradient
linearGradient
.attr("x1", "10%")
.attr("y1", "0%")
.attr("x2", "90%")
.attr("y2", "0%");
linearGradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#eff3ff");
linearGradient.append("stop")
.attr("offset", "25%")
.attr("stop-color", "#bdd7e7");
linearGradient.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#6baed6");
linearGradient.append("stop")
.attr("offset", "75%")
.attr("stop-color", "#3182bd");
linearGradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#08519c")
.attr("stop-opacity", .8);
var xScale = d3.scaleLinear()
.domain([0, 8])
.range([0, +innerWidth])
var heightScale = d3.scaleLinear()
.domain([0,4])
.range([(3/4) * innerHeight, 50])
//generate area points
var areaX = [... Array(9).keys()].map(xScale)
var areaY1 = [.75, .74, 1.25, 1.24, 1.75, 1.74, 2, 2.31, 2.39].map(e => e * (innerHeight/9))
var areaY0 = areaY1.map(e => innerHeight - e)
//zip points into an array of arrays. areaPoints = [[areaX, areaY1, areaY0]...]
var zip = (...rows) => [...rows[0]].map((_,c) => rows.map(row => row[c]));
var areaPoints = zip(areaX, areaY1, areaY0);
//creat and array of objects from the areaPoints array of arrays.
var points = []
areaPoints.forEach(a => points.push({x:a[0], heigh:a[1], low:a[2]}))
//areaGenerator
var areaGenerator = d3.area()
.x(d => +d.x)
.y0(d => +d.low)
.y1(d => +d.heigh)
.curve(d3.curveCardinal);
//render the area from the points array of objects
var area = areaGenerator(points);
d3.select('svg')
.append('path')
.attr('d', area)
.attr('fill', "url(#linear-gradient)");
function draw_graph(region, data){
var yTrans = points[region]['heigh'] - points[0]['heigh']
var width = points[2]['x']
var height = points[region]['low'] - points[region]['heigh']
var xAxisTrans = yTrans + height + 40
// the rectangle
var rect = svg.append('rect')
.attr('x', points[0]['x'])
.attr('y', points[0]['heigh'])
.attr('height',height)
.attr('width', width)
.attr('stroke', 'red')
.attr('fill', 'none')
.attr("transform",
`translate(${points[region]['x']},${yTrans})`)//<-- translate the
//graph domain
var dom = data
// x and y scales
var xScale = d3.scaleLinear()
.domain(d3.extent(dom))
.range([0, width])
var yScale = d3.scalePoint()
.domain(dom)
.range([0, height])
// x and Y axis
var xAxis = d3.axisBottom(xScale)
var yAxis = d3.axisLeft(yScale)
// x and y Axis Groups
var xAxisG = svg.append('g')
.call(xAxis)
.attr("transform",
`translate(${points[region]['x']},${xAxisTrans})`)
var yAxisG = svg.append('g')
.call(yAxis)
.attr("transform",
`translate(${points[region]['x']},${points[region]['heigh']})`)
//render data as points
svg.selectAll('circle').data(dom).enter()
.append('circle')
.attr('cx', d => xScale(d))
.attr('cy', d => yScale(d) + 40)
.attr('r', 5)
.attr("transform",
`translate(${points[region]['x']},${yTrans})`)//<--translate points into rectangle
}
//Draw 4 graphs from 4 random arrays
const com = [...Array(10)].map(_=>Math.ceil(Math.random()*40))
const vom = [...Array(50)].map(_=>Math.ceil(Math.random()*40))
const zom = [...Array(20)].map(_=>Math.ceil(Math.random()*40))
const jom = [...Array(20)].map(_=>Math.ceil(Math.random()*40))
draw_graph(0, com)//<--draw over the 1st region
draw_graph(4, vom)//<--draw over the 3rd region
draw_graph(2, zom)//<--draw over the 2nd region
draw_graph(6, jom)//<--draw over the 4th region
</script>
</body>
我的计划是使用四个单独的数据集调用 draw_graph 四次(每个区域调用一次背景形状)。期望的效果是背景形状的每个区域都有自己的散点图。目前我的数据集是随机生成的数组。
最佳答案
您的代码的问题是您要选择所有圆圈并将数据绑定(bind)到它们:
svg.selectAll('circle')
.data(dom)
.enter()
//etc...
这可以通过选择 null
轻松解决:
svg.selectAll(null)
.data(dom)
.enter()
//etc...
这是您的代码,仅进行了更改:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://unpkg.com/d3@5.9.1/dist/d3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
//add svg
var svg = d3.select("body").append("svg")
.attr("width", 960)
.attr("height", 500)
.attr('stoke', 'red');
//////////////GENERATEs AREA/////////////
// //Append a defs
var defs = svg.append("defs");
//Append a linearGradient element to the defs and give it a unique id
var linearGradient = defs.append("linearGradient")
.attr("id", "linear-gradient");
//Horizontal gradient
linearGradient
.attr("x1", "10%")
.attr("y1", "0%")
.attr("x2", "90%")
.attr("y2", "0%");
linearGradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", "#eff3ff");
linearGradient.append("stop")
.attr("offset", "25%")
.attr("stop-color", "#bdd7e7");
linearGradient.append("stop")
.attr("offset", "50%")
.attr("stop-color", "#6baed6");
linearGradient.append("stop")
.attr("offset", "75%")
.attr("stop-color", "#3182bd");
linearGradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", "#08519c")
.attr("stop-opacity", .8);
var xScale = d3.scaleLinear()
.domain([0, 8])
.range([0, +innerWidth])
var heightScale = d3.scaleLinear()
.domain([0,4])
.range([(3/4) * innerHeight, 50])
//generate area points
var areaX = [... Array(9).keys()].map(xScale)
var areaY1 = [.75, .74, 1.25, 1.24, 1.75, 1.74, 2, 2.31, 2.39].map(e => e * (innerHeight/9))
var areaY0 = areaY1.map(e => innerHeight - e)
//zip points into an array of arrays. areaPoints = [[areaX, areaY1, areaY0]...]
var zip = (...rows) => [...rows[0]].map((_,c) => rows.map(row => row[c]));
var areaPoints = zip(areaX, areaY1, areaY0);
//creat and array of objects from the areaPoints array of arrays.
var points = []
areaPoints.forEach(a => points.push({x:a[0], heigh:a[1], low:a[2]}))
//areaGenerator
var areaGenerator = d3.area()
.x(d => +d.x)
.y0(d => +d.low)
.y1(d => +d.heigh)
.curve(d3.curveCardinal);
//render the area from the points array of objects
var area = areaGenerator(points);
d3.select('svg')
.append('path')
.attr('d', area)
.attr('fill', "url(#linear-gradient)");
function draw_graph(region, data){
var yTrans = points[region]['heigh'] - points[0]['heigh']
var width = points[2]['x']
var height = points[region]['low'] - points[region]['heigh']
var xAxisTrans = yTrans + height + 40
// the rectangle
var rect = svg.append('rect')
.attr('x', points[0]['x'])
.attr('y', points[0]['heigh'])
.attr('height',height)
.attr('width', width)
.attr('stroke', 'red')
.attr('fill', 'none')
.attr("transform",
`translate(${points[region]['x']},${yTrans})`)//<-- translate the
//graph domain
var dom = data
// x and y scales
var xScale = d3.scaleLinear()
.domain(d3.extent(dom))
.range([0, width])
var yScale = d3.scalePoint()
.domain(dom)
.range([0, height])
// x and Y axis
var xAxis = d3.axisBottom(xScale)
var yAxis = d3.axisLeft(yScale)
// x and y Axis Groups
var xAxisG = svg.append('g')
.call(xAxis)
.attr("transform",
`translate(${points[region]['x']},${xAxisTrans})`)
var yAxisG = svg.append('g')
.call(yAxis)
.attr("transform",
`translate(${points[region]['x']},${points[region]['heigh']})`)
//render data as points
svg.selectAll(null).data(dom).enter()
.append('circle')
.attr('cx', d => xScale(d))
.attr('cy', d => yScale(d) + 40)
.attr('r', 5)
.attr("transform",
`translate(${points[region]['x']},${yTrans})`)//<--translate points into rectangle
}
//Draw 4 graphs from 4 random arrays
const com = [...Array(10)].map(_=>Math.ceil(Math.random()*40))
const vom = [...Array(50)].map(_=>Math.ceil(Math.random()*40))
const zom = [...Array(20)].map(_=>Math.ceil(Math.random()*40))
const jom = [...Array(20)].map(_=>Math.ceil(Math.random()*40))
draw_graph(0, com)//<--draw over the 1st region
draw_graph(4, vom)//<--draw over the 3rd region
draw_graph(2, zom)//<--draw over the 2nd region
draw_graph(6, jom)//<--draw over the 4th region
</script>
</body>
要了解有关 selection.selectAll(null)
的更多信息,请查看此处:Selecting null: what is the reason behind 'selectAll(null)' in D3.js? .另外,请注意最后一部分,我在这里解释说,如果您打算进行更新选择,则不应使用 selection.selectAll(null)
。在这种情况下,相应地选择足够的圈子。
关于javascript - 如何在背景元素上投影多个散点图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55449707/
我是一名优秀的程序员,十分优秀!