英文:
How to give href to text element in d3js with zoom function
问题
我有一个带有缩放功能的d3.js图表。图表上有一些标签,我希望这些标签可以像href链接一样可点击。似乎href与缩放功能发生了冲突。只有href或缩放中的一个有效。两者不能一起工作。只有当我注释掉缩放代码时,href才有效。只有当我注释掉href代码时,缩放才有效。如何使href和缩放同时有效?
var margin = {top: 10, right: 10, bottom: 20, left: 40},
width = 450 - margin.left - margin.right,
height = 380 - margin.top - margin.bottom;
let data = [
[95,'0.7142914222463218','#0000FF','(535/535)',0,"www.a.net"],
[97,'1.5753396297416553','#00FF00','(267/267)',0,"www.b.net"],
[97,'3.965827978600963','#808080','(14/14)',0,"www.c.net"],
[100,'5.340348252548648','#FFAFAF','(7/8)',0,"www.d.net"],
[100,'5.699038509168024','#FFAFAF','(1/8)',0,"www.e.net"],
[77,'19.506535109626878','#FF0000','(5/5)',0,"www.f.net"],
[77,'19.506535109626878','#FF0000','(2/2)',42,"www.g.net"]
];
var SVG = d3.select("body")
.append("svg")
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("xlink", "http://www.w3.org/1999/xlink")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
SVG.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Add X axis
var x = d3.scaleLinear()
.domain([1, 120])
.range([ 0, width ]);
var xAxis = SVG.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 39])
.range([ height, 0 ]);
var yAxis = SVG.append("g")
.call(d3.axisLeft(y));
// Add a clipPath: everything out of this area won't be drawn.
var clip = SVG.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width )
.attr("height", height )
.attr("x", 0)
.attr("y", 0);
// Create the scatter variable: where both the circles and the brush take place
var scatter = SVG.append('g')
.attr("clip-path", "url(#clip)")
scatter
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d[0]); } )
.attr("cy", function (d) { return y(d[1]); } )
.attr("r", 5)
.style("fill", function (d) { return "black"; } )
.style("opacity", 0.5);
scatter.selectAll("a")
.data(data)
.enter().append("a")
//.attr({"xlink:href": "#"})
.on("click", function() { window.open("https://google.com"); })
.append("text")
.attr("x", (d) => x(d[0])+d[4])
.attr("y", (d) => y(d[1]))
.text((d) => d[3])
.style("fill", (d) => d[2]);
// Set the zoom and Pan features: how much you can zoom, on which part, and what to do when there is a zoom
var zoom = d3.zoom()
.scaleExtent([.5, 1000]) // This control how much you can unzoom (x0.5) and zoom (x20)
.extent([[0, 0], [width, height]])
.on("zoom", updateChart);
// This add 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.left + ',' + margin.top + ')')
.call(zoom);
// now the user can zoom and it will trigger the function called updateChart
// A function that updates the chart when the user zoom and thus new boundaries are available
function updateChart() {
// recover the new scale
var newX = d3.event.transform.rescaleX(x);
var newY = d3.event.transform.rescaleY(y);
// update axes with these new boundaries
xAxis.call(d3.axisBottom(newX))
yAxis.call(d3.axisLeft(newY))
// update circle position
scatter
.selectAll("circle")
.attr('cx', function(d) {return newX(d[0])})
.attr('cy', function(d) {return newY(d[1])});
scatter.selectAll("text")
.attr("x", (d) => newX(d[0])+d[4])
.attr("y", (d) => newY(d[1]))
}
//})
<head>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
</head>
<body></body>
英文:
I have a d3 js chart with zoom function. There are some labels on the chart. I want those labels to be clickable like href links. It looks like href is interfering with zoom function. Only either of href or zoom is working. Both are not working together. Only if I comment zoom code, href is working. And only if I comment href code, zoom is working. How to make both href and zoom working together?
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
var margin = {top: 10, right: 10, bottom: 20, left: 40},
width = 450 - margin.left - margin.right,
height = 380 - margin.top - margin.bottom;
let data = [
[95,'0.7142914222463218','#0000FF','(535/535)',0,"www.a.net"],[97,'1.5753396297416553','#00FF00','(267/267)',0,"www.b.net"],[97,'3.965827978600963','#808080','(14/14)',0,"www.c.net"],[100,'5.340348252548648','#FFAFAF','(7/8)',0,"www.d.net"],[100,'5.699038509168024','#FFAFAF','(1/8)',0,"www.e.net"],[77,'19.506535109626878','#FF0000','(5/5)',0,"www.f.net"],[77,'19.506535109626878','#FF0000','(2/2)',42,"www.g.net"]]
var SVG = d3.select("body")
.append("svg")
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("xlink", "http://www.w3.org/1999/xlink")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
SVG.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Add X axis
var x = d3.scaleLinear()
.domain([1, 120])
.range([ 0, width ]);
var xAxis = SVG.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 39])
.range([ height, 0]);
var yAxis = SVG.append("g")
.call(d3.axisLeft(y));
// Add a clipPath: everything out of this area won't be drawn.
var 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);
// Create the scatter variable: where both the circles and the brush take place
var scatter = SVG.append('g')
.attr("clip-path", "url(#clip)")
scatter
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d[0]); } )
.attr("cy", function (d) { return y(d[1]); } )
.attr("r", 5)
.style("fill", function (d) { "black"; } )
.style("opacity", 0.5);
scatter.selectAll("a")
.data(data)
.enter().append("a")
//.attr({"xlink:href": "#"})
.on("click", function() { window.open("https://google.com"); })
.append("text")
.attr("x", (d) => x(d[0])+d[4])
.attr("y", (d) => y(d[1]))
.text((d) => d[3])
.style("fill", (d) => d[2]);
// Set the zoom and Pan features: how much you can zoom, on which part, and what to do when there is a zoom
var zoom = d3.zoom()
.scaleExtent([.5, 1000]) // This control how much you can unzoom (x0.5) and zoom (x20)
.extent([[0, 0], [width, height]])
.on("zoom", updateChart);
// This add 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.left + ',' + margin.top + ')')
.call(zoom);
// now the user can zoom and it will trigger the function called updateChart
// A function that updates the chart when the user zoom and thus new boundaries are available
function updateChart() {
// recover the new scale
var newX = d3.event.transform.rescaleX(x);
var newY = d3.event.transform.rescaleY(y);
// update axes with these new boundaries
xAxis.call(d3.axisBottom(newX))
yAxis.call(d3.axisLeft(newY))
// update circle position
scatter
.selectAll("circle")
.attr('cx', function(d) {return newX(d[0])})
.attr('cy', function(d) {return newY(d[1])});
scatter.selectAll("text")
.attr("x", (d) => newX(d[0])+d[4])
.attr("y", (d) => newY(d[1]))
}
//})
<!-- language: lang-html -->
<head>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
</head>
<body></body>
<!-- end snippet -->
答案1
得分: 1
以下是您要翻译的内容:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
var margin = {top: 10, right: 10, bottom: 20, left: 40},
width = 450 - margin.left - margin.right,
height = 380 - margin.top - margin.bottom;
let data = [
[95,'0.7142914222463218','#0000FF','(535/535)',0,"www.a.net"],[97,'1.5753396297416553','#00FF00','(267/267)',0,"www.b.net"],[97,'3.965827978600963','#808080','(14/14)',0,"www.c.net"],[100,'5.340348252548648','#FFAFAF','(7/8)',0,"www.d.net"],[100,'5.699038509168024','#FFAFAF','(1/8)',0,"www.e.net"],[77,'19.506535109626878','#FF0000','(5/5)',0,"www.f.net"],[77,'19.506535109626878','#FF0000','(2/2)',42,"www.g.net"]]
var SVG = d3.select("body")
.append("svg")
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("xlink", "http://www.w3.org/1999/xlink")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
SVG.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Add X axis
var x = d3.scaleLinear()
.domain([1, 120])
.range([ 0, width ]);
var xAxis = SVG.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 39])
.range([ height, 0 ]);
var yAxis = SVG.append("g")
.call(d3.axisLeft(y));
// Add a clipPath: everything out of this area won't be drawn.
var clip = SVG.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width )
.attr("height", height )
.attr("x", 0)
.attr("y", 0);
// Create the scatter variable: where both the circles and the brush take place
var scatter = SVG.append('g')
.attr("clip-path", "url(#clip)")
scatter
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d[0]); } )
.attr("cy", function (d) { return y(d[1]); } )
.attr("r", 5)
.style("fill", function (d) { "black"; } )
.style("opacity", 0.5);
scatter.selectAll(".textg")
.data(data)
.enter().append("g")
.attr('class','textg')
.style('cursor','pointer')
//.attr({"xlink:href": "#"})
.on("click", function() { window.open("https://google.com"); })
.append("text")
// .attr({x: (d) => x(d[0])+d[4], y: (d) => y(d[1])})
.attr("x", (d) => x(d[0])+d[4])
.attr("y", (d) => y(d[1]))
.text((d) => d[3])
.style("fill", (d) => d[2]);
// Set the zoom and Pan features: how much you can zoom, on which part, and what to do when there is a zoom
var zoom = d3.zoom()
.scaleExtent([.5, 1000]) // This control how much you can unzoom (x0.5) and zoom (x20)
.extent([[0, 0], [width, height]])
.on("zoom", updateChart);
// This add 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.left + ',' + margin.top + ')')
.call(zoom);
scatter.raise()
// now the user can zoom and it will trigger the function called updateChart
// A function that updates the chart when the user zoom and thus new boundaries are available
function updateChart() {
// recover the new scale
var newX = d3.event.transform.rescaleX(x);
var newY = d3.event.transform.rescaleY(y);
// update axes with these new boundaries
xAxis.call(d3.axisBottom(newX))
yAxis.call(d3.axisLeft(newY))
// update circle position
scatter
.selectAll("circle")
.attr('cx', function(d) {return newX(d[0])})
.attr('cy', function(d) {return newY(d[1])});
scatter.selectAll("text")
.attr("x", (d) => newX(d[0])+d[4])
.attr("y", (d) => newY(d[1]))
scatter.raise()
}
//})
<!-- language: lang-html -->
<head>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
</head>
<body></body>
<!-- end snippet -->
请注意,上述内容包括HTML和JavaScript代码,已根据您的要求进行翻译。如果您需要进一步的帮助,请随时提问。
英文:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
var margin = {top: 10, right: 10, bottom: 20, left: 40},
width = 450 - margin.left - margin.right,
height = 380 - margin.top - margin.bottom;
let data = [
[95,'0.7142914222463218','#0000FF','(535/535)',0,"www.a.net"],[97,'1.5753396297416553','#00FF00','(267/267)',0,"www.b.net"],[97,'3.965827978600963','#808080','(14/14)',0,"www.c.net"],[100,'5.340348252548648','#FFAFAF','(7/8)',0,"www.d.net"],[100,'5.699038509168024','#FFAFAF','(1/8)',0,"www.e.net"],[77,'19.506535109626878','#FF0000','(5/5)',0,"www.f.net"],[77,'19.506535109626878','#FF0000','(2/2)',42,"www.g.net"]]
var SVG = d3.select("body")
.append("svg")
.attr("xmlns", "http://www.w3.org/2000/svg")
.attr("xlink", "http://www.w3.org/1999/xlink")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
SVG.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
// Add X axis
var x = d3.scaleLinear()
.domain([1, 120])
.range([ 0, width ]);
var xAxis = SVG.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 39])
.range([ height, 0]);
var yAxis = SVG.append("g")
.call(d3.axisLeft(y));
// Add a clipPath: everything out of this area won't be drawn.
var 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);
// Create the scatter variable: where both the circles and the brush take place
var scatter = SVG.append('g')
.attr("clip-path", "url(#clip)")
scatter
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function (d) { return x(d[0]); } )
.attr("cy", function (d) { return y(d[1]); } )
.attr("r", 5)
.style("fill", function (d) { "black"; } )
.style("opacity", 0.5);
scatter.selectAll(".textg")
.data(data)
.enter().append("g")
.attr('class','textg')
.style('cursor','pointer')
//.attr({"xlink:href": "#"})
.on("click", function() { window.open("https://google.com"); })
.append("text")
// .attr({x: (d) => x(d[0])+d[4], y: (d) => y(d[1])})
.attr("x", (d) => x(d[0])+d[4])
.attr("y", (d) => y(d[1]))
.text((d) => d[3])
.style("fill", (d) => d[2]);
// Set the zoom and Pan features: how much you can zoom, on which part, and what to do when there is a zoom
var zoom = d3.zoom()
.scaleExtent([.5, 1000]) // This control how much you can unzoom (x0.5) and zoom (x20)
.extent([[0, 0], [width, height]])
.on("zoom", updateChart);
// This add 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.left + ',' + margin.top + ')')
.call(zoom);
scatter.raise()
// now the user can zoom and it will trigger the function called updateChart
// A function that updates the chart when the user zoom and thus new boundaries are available
function updateChart() {
// recover the new scale
var newX = d3.event.transform.rescaleX(x);
var newY = d3.event.transform.rescaleY(y);
// update axes with these new boundaries
xAxis.call(d3.axisBottom(newX))
yAxis.call(d3.axisLeft(newY))
// update circle position
scatter
.selectAll("circle")
.attr('cx', function(d) {return newX(d[0])})
.attr('cy', function(d) {return newY(d[1])});
scatter.selectAll("text")
.attr("x", (d) => newX(d[0])+d[4])
.attr("y", (d) => newY(d[1]))
scatter.raise()
}
//})
<!-- language: lang-html -->
<head>
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
</head>
<body></body>
<!-- end snippet -->
Hello, i think your problem is that d3.zoom
is putting e rect to capture mouse events.
So one solution is to put the <g/>
on top of the rect so you can click your elements.
Luckily d3 has an easy way to bring an element to the top:
scatter.raise()
Click doesn't work on sniper because you can't open a new window on snippet sandbox, however you can see the cursor change on text over
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论