在任何图表点上获取坐标 [英] Get coords on any chart point
问题描述
我想创建一个函数,
返回配置文件的高度鼠标悬停
当我在我的.json中有信息时,很容易,例如这里指的是{d:1508,a :77}。我使用这个函数:
function mousemove(){
pre>
var x0 = x.invert (d3.mouse(this)[0]),
i = bisectDist(data,x0,1),
d0 = data [i-1],
d1 = data [i]
d = x0 - d0.distance> d1.distance - x0?d1:d0;
focus.attr(transform,translate(+ x(d.distance)+ y(d.altitude)+));
focus.select(text)text(d.altitude);
}
但是,如果可能的话,我也希望在两点相隔太远时计算高度。例如,我有此个人资料{d:1539,a:58},{d:1550,a: 158} 。所以,我返回d = 1539和d = 1550的高度,但是,我可以返回的高度为d = 1546感谢我的个人资料吗?
最好的问候,布拉茨Damien。
codepen.io/Onchman/pen/dNpeaP这里是codepen的代码,我不知道如何从外部ressource添加json,所以,尝试将其直接添加到JavaScript部分。
解决方案引用此answer 并将其应用于代码,您的
mousemove
函数将重写为:function mousemove(){
var mouse = d3.mouse
var beginning = 0,
end = areaPath.getTotalLength(),
target = null;
while(true){
target = Math.floor((beginning + end)/ 2);
pos = areaPath.getPointAtLength(target);
if((target === end || target === beginning)&& pos.x!== mouse [0]){
break;
}
if(pos.x> mouse [0])end = target;
else if(pos.x< mouse [0])begin = target;
else break; // position found
}
focus.attr(transform,translate(+ mouse [0] +,+ pos.y +)
focus.select(text)。text(y.invert(pos.y).toFixed(2));
}
完整运行代码:
<!DOCTYPE html>< html>< head> < script data-require =d3@4.0.0data-semver =4.0.0src =https://d3js.org/d3.v4.min.js>< / script> < style> body {font:10px sans-serif; } .axis path,.axis line {fill:none; stroke:#000; shape-rendering:crispEdges; } .axis text {font-family:Lato; font-size:13px;填充:黑色; } .grid path,.grid line {fill:none; stroke:rgba(0,0,0,0.25); shape-rendering:crispEdges; } .area {fill:darkorange; stroke:rgba(0,0,0,1); } .marker.client .marker-bg,.marker.client path {fill:rgba(255,127,0,0.8); stroke:rgba(255,127,0,0.8); stroke-width:3; } .marker.server .marker-bg,.marker.server path {fill:rgba(0,153,51,0.8);中风:rgba(0,153,51,0.8); stroke-width:3; } .marker path {fill:none; } .legend text,.marker text {fill:black; font-weight:bold; } .marker text {text-anchor:middle; } .overlay {fill:none; pointer-events:all; } .focus circle {fill:none;中风:钢蓝}< / style>< / head>< body> < script>函数配置文件(rawData){var margin = {top:20,right:20,bottom:60,left:50},width = 960 - margin.left - margin.right,height = 500 - margin.top - margin.bottom ,innerwidth = width - margin.left - margin.right,innerheight = height - margin.top - margin.bottom; var bisectDist = d3.bisector(function(d){return d.distance;})。 var x = d3.scaleLinear()。range([0,width]); var y = d3.scaleLinear()。range([height,0]); var xAxis = d3.axisBottom()。scale(x); var yAxis = d3.axisLeft()。scale(y); var area = d3.area()。x(function(d){return x(d.distance);})y0(height).y1(function(d){return y(d.altitude);})var svg = d3.select(body)。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 +)); //// d3.json('data.json' ,function(error,rawData){// if(error){// console.error(error); // return; //} var data = rawData.map(function(d){return {altitude:da,distance :dd};}); // data.sort(function(a,b){// return a.distance - b.distance; //}); x.domain(d3.extent {return d.distance;})); y.domain([0,d3.max(data,function(d){return d.altitude;})]); var x_grid = d3.axisBottom ).tickSize(-height).tickFormat(); var y_grid = d3.axisLeft()。scale(y).tickSize(-width).tickFormat(); var areaPath = svg.append('svg:path').datum(data).attr(class,area).attr(d,area).node svg.append(svg:g).attr(class,x axis).attr(transform,translate(0,+ height +)).call(xAxis).append text).attr(transform,translate(0,+ margin.top * 2 +)).attr(x,width - (margin.right + margin.left)).text Distance(km)); svg.append(svg:g).attr(class,y axis).call(yAxis).append(text).attr(transform,translate(70,0) .attr(transform,rotate(-90)).attr(y,-45).attr(dy,.71em).style(text-anchor,end) .text(Altitude(m)); svg.append(g).attr(class,x grid).attr(transform,translate(0,+ height +)).call(x_grid); svg.append(g).attr(class,y grid).call(y_grid); var focus = svg.append(g).attr(class,focus).style(display,none); focus.append(circle).attr(r,4.5); focus.append(text).attr(x,9).attr(dy,.35em); svg.append(rect).attr(class,overlay).attr(width,width).attr(height,height).on(mouseover,function style(display,null);}).on(mouseout,function(){focus.style(display,none);}).on(mousemove,mousemove);函数mousemove(){/ * var x0 = x.invert(d3.mouse(this)[0]),i = bisectDist(data,x0,1),d0 = data [i-1],d1 = data [i ],d = x0-d0.distance> d1.distance - x0? d1:d0; focus.attr(transform,translate(+ x(d.distance)+,+ y(d.altitude)+)); focus.select(text)。text(d.altitude); * / var mouse = d3.mouse(this); var beginning = 0,end = areaPath.getTotalLength(),target = null; while(true){target = Math.floor((beginning + end)/ 2); pos = areaPath.getPointAtLength(target); if((target === end || target === beginning)&& pos.x!== mouse [0]){break; } if(pos.x> mouse [0])end = target; else if(pos.x< mouse [0])begin = target; else break; // position found} focus.attr(transform,translate(+ mouse [0] +,+ pos.y +)); focus.select(text)。text(y.invert(pos.y).toFixed(2)); } var markerjson = [{id:1,name:Depart - Vielle-Aure,type:CP,description:Départ,icon:../ item_icons / iconCust / map-marker-checkpoint.svg,distance:1488,altitude:145},{id:2,name:CP1 - Col de Portet ,type:CP,description:1er CP,icon:../item_icons/iconCust/map-marker-checkpoint.svg,distance:1496 :37},{id:3,name:CP2-Artigues,type:CP,description:2èmeCP item4,name:CP3-Col De Sencours,item_icons / iconCust / map-marker-checkpoint.svg,distance:1504,altitude: ,type:CP,description:3èmeCP,icon:../item_icons/iconCust/map-marker-checkpoint.svg,distance:1512 :137},{id:5,name:CP4-Hautacam,type:CP,description:4èmeCP,icon:../ item_icons / iconCust / map-marker-checkpoint.svg,distance:1521,altitude:45}]; / * d3.json('markersjson',function(error,markerData){if(error){console.error(error); return;} * / / * markerData = markerjson; var markers = markerData.map ){return {id:marker.id,name:marker.name,type:marker.type,description:marker.description,icon:marker.icon,distance:marker.distance,};}); markers.forEach (marker,i){setTimeout(function(){setItem(marker,data,svg,innerheight,x,y);},1000 + 500 * i);}); * / //}); //}); } function setItem(marker,data,svg,innerheight,x,y){altitude = getAltitude(data,marker); var radius = 20,xPos = x(marker.distance) - radius - 3,yPosStart = innerheight - radius -3,yPosEnd = y(altitude) - radius * 2; var markerG = svg.append('g').attr('class','marker'+ marker.type.toLowerCase()).attr('transform','translate('+ xPos +','+ yPosStart + ')').attr('opacity',0); markerG.transition().duration(1000).attr('transform','translate('+ xPos +','+ yPosEnd +')'attr('opacity',1); markG.append(svg:image).attr('class','marker-bg').attr(xlink:href,cp-x_15_31.png).attr(x,2 ).attr(width,40).attr(height,40); markG.append('text').attr('x',radius).attr('y',radius * 0.9)markerG.append('text').attr('x',radius).attr ',radius * 1.5).attr(transform,translate(0,15)).text(marker.name); } function getAltitude(data,marker){var i = 0; while(i
p>
I wanted to create a function who return the altitude of the profile with a mouseover
When I have the informations in my .json, it's easy, here for exemple, the point refer to {"d": 1508, "a": 77"}. I use this function:
function mousemove() { var x0 = x.invert(d3.mouse(this)[0]), i = bisectDist(data, x0, 1), d0 = data[i - 1], d1 = data[i], d = x0 - d0.distance > d1.distance - x0 ? d1 : d0; focus.attr("transform", "translate(" + x(d.distance) + "," + y(d.altitude) + ")"); focus.select("text").text(d.altitude); }
But, I also would like, if possible, to calculate the altitude when I have 2 point too far apart. For exemple, I have this profile for {"d": 1539, "a": 58}, {"d": 1550, "a": 158}. So, I return the altitude for d=1539 and d=1550, but, can I return the altitude for d=1546 thanks to my profile?
Best Regards, Braz Damien.
codepen.io/Onchman/pen/dNpeaP Here is the code on codepen, I don't know how to add json from an external ressource, so, i tried to add it directly in the JavaScript part.
解决方案Referring to my code in this answer and applying it to your code, your
mousemove
function would be re-written like this:function mousemove() { var mouse = d3.mouse(this); var beginning = 0, end = areaPath.getTotalLength(), target = null; while (true){ target = Math.floor((beginning + end) / 2); pos = areaPath.getPointAtLength(target); if ((target === end || target === beginning) && pos.x !== mouse[0]) { break; } if (pos.x > mouse[0]) end = target; else if (pos.x < mouse[0]) beginning = target; else break; //position found } focus.attr("transform","translate(" + mouse[0] + "," + pos.y +")"); focus.select("text").text(y.invert(pos.y).toFixed(2)); }
Full running code:
<!DOCTYPE html> <html> <head> <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script> <style> body { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } .axis text { font-family: Lato; font-size: 13px; fill: black; } .grid path, .grid line { fill: none; stroke: rgba(0, 0, 0, 0.25); shape-rendering: crispEdges; } .area { fill: darkorange; stroke: rgba(0, 0, 0, 1); } .marker.client .marker-bg, .marker.client path { fill: rgba(255, 127, 0, 0.8); stroke: rgba(255, 127, 0, 0.8); stroke-width: 3; } .marker.server .marker-bg, .marker.server path { fill: rgba(0, 153, 51, 0.8); stroke: rgba(0, 153, 51, 0.8); stroke-width: 3; } .marker path { fill: none; } .legend text, .marker text { fill: black; font-weight: bold; } .marker text { text-anchor: middle; } .overlay { fill: none; pointer-events: all; } .focus circle { fill: none; stroke: steelblue; } </style> </head> <body> <script> function profile(rawData) { var margin = { top: 20, right: 20, bottom: 60, left: 50 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom, innerwidth = width - margin.left - margin.right, innerheight = height - margin.top - margin.bottom; var bisectDist = d3.bisector(function(d) { return d.distance; }).left; var x = d3.scaleLinear().range([0, width]); var y = d3.scaleLinear().range([height, 0]); var xAxis = d3.axisBottom().scale(x); var yAxis = d3.axisLeft().scale(y); var area = d3.area().x(function(d) { return x(d.distance); }).y0(height).y1(function(d) { return y(d.altitude); }) var svg = d3.select("body").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 + ")"); // // d3.json('data.json', function(error, rawData) { // if (error) { // console.error(error); // return; // } var data = rawData.map(function(d) { return { altitude: d.a, distance: d.d }; }); // data.sort(function(a, b) { // return a.distance - b.distance; // }); x.domain(d3.extent(data, function(d) { return d.distance; })); y.domain([0, d3.max(data, function(d) { return d.altitude; })]); var x_grid = d3.axisBottom().scale(x).tickSize(-height).tickFormat(""); var y_grid = d3.axisLeft().scale(y).tickSize(-width).tickFormat(""); var areaPath = svg.append('svg:path') .datum(data) .attr("class", "area") .attr("d", area) .node(); svg.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("transform", "translate(0," + margin.top * 2 + ")") .attr("x", width - (margin.right + margin.left)) .text("Distance (km)"); svg.append("svg:g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "translate(70,0)") .attr("transform", "rotate(-90)") .attr("y", -45).attr("dy", ".71em") .style("text-anchor", "end") .text("Altitude (m)"); svg.append("g") .attr("class", "x grid") .attr("transform", "translate(0," + height + ")") .call(x_grid); svg.append("g") .attr("class", "y grid") .call(y_grid); var focus = svg.append("g") .attr("class", "focus") .style("display", "none"); focus.append("circle") .attr("r", 4.5); focus.append("text") .attr("x", 9) .attr("dy", ".35em"); svg.append("rect") .attr("class", "overlay") .attr("width", width) .attr("height", height) .on("mouseover", function() { focus.style("display", null); }) .on("mouseout", function() { focus.style("display", "none"); }) .on("mousemove", mousemove); function mousemove() { /* var x0 = x.invert(d3.mouse(this)[0]), i = bisectDist(data, x0, 1), d0 = data[i - 1], d1 = data[i], d = x0 - d0.distance > d1.distance - x0 ? d1 : d0; focus.attr("transform", "translate(" + x(d.distance) + "," + y(d.altitude) + ")"); focus.select("text").text(d.altitude); */ var mouse = d3.mouse(this); var beginning = 0, end = areaPath.getTotalLength(), target = null; while (true){ target = Math.floor((beginning + end) / 2); pos = areaPath.getPointAtLength(target); if ((target === end || target === beginning) && pos.x !== mouse[0]) { break; } if (pos.x > mouse[0]) end = target; else if (pos.x < mouse[0]) beginning = target; else break; //position found } focus.attr("transform","translate(" + mouse[0] + "," + pos.y +")"); focus.select("text").text(y.invert(pos.y).toFixed(2)); } var markerjson = [{ "id": "1", "name": "Depart - Vielle-Aure", "type": "CP", "description": "Départ", "icon": "../item_icons/iconCust/map-marker-checkpoint.svg", "distance": "1488", "altitude": "145" }, { "id": "2", "name": "CP1 - Col de Portet", "type": "CP", "description": "1er CP", "icon": "../item_icons/iconCust/map-marker-checkpoint.svg", "distance": "1496", "altitude": "37" }, { "id": "3", "name": "CP2 - Artigues", "type": "CP", "description": "2ème CP", "icon": "../item_icons/iconCust/map-marker-checkpoint.svg", "distance": "1504", "altitude": "145" }, { "id": "4", "name": "CP3 - Col De Sencours", "type": "CP", "description": "3ème CP", "icon": "../item_icons/iconCust/map-marker-checkpoint.svg", "distance": "1512", "altitude": "137" }, { "id": "5", "name": "CP4 - Hautacam", "type": "CP", "description": "4ème CP", "icon": "../item_icons/iconCust/map-marker-checkpoint.svg", "distance": "1521", "altitude": "45" }]; /* d3.json('markersjson', function(error, markerData) { if (error) { console.error(error); return; } */ /* markerData = markerjson; var markers = markerData.map(function(marker) { return { id: marker.id, name: marker.name, type: marker.type, description: marker.description, icon: marker.icon, distance: marker.distance, }; }); markers.forEach(function(marker, i) { setTimeout(function() { setItem(marker, data, svg, innerheight, x, y); }, 1000 + 500 * i); }); */ // }); //}); } function setItem(marker, data, svg, innerheight, x, y) { altitude = getAltitude(data, marker); var radius = 20, xPos = x(marker.distance) - radius - 3, yPosStart = innerheight - radius - 3, yPosEnd = y(altitude) - radius * 2; var markerG = svg.append('g') .attr('class', 'marker ' + marker.type.toLowerCase()) .attr('transform', 'translate(' + xPos + ', ' + yPosStart + ')') .attr('opacity', 0); markerG.transition() .duration(1000) .attr('transform', 'translate(' + xPos + ', ' + yPosEnd + ')') .attr('opacity', 1); markerG.append("svg:image") .attr('class', 'marker-bg') .attr("xlink:href", "cp-x_15_31.png") .attr("x", "2") .attr("width", "40") .attr("height", "40"); markerG.append('text') .attr('x', radius) .attr('y', radius * 0.9) markerG.append('text') .attr('x', radius) .attr('y', radius * 1.5) .attr("transform", "translate(0,15)") .text(marker.name); } function getAltitude(data, marker) { var i = 0; while (i < data.length) { if (data[i].distance == marker.distance) { return data[i].altitude; } else { if (i < data.length) { if ((data[i].distance < marker.distance) && (marker.distance < data[i + 1].distance)) { return ((data[i].altitude + data[i + 1].altitude) / 2) } } else { if ((data[i - 1].distance < marker.distance) && (marker.distance < data[i].distance)) { return ((data[i - 1].altitude + data[i].altitude) / 2) } } } i++; } } function removeItem(marker, svg, innerheight, x) { markerG.clear; } var profilejson = [{ "d": 1488, "a": 145 }, { "d": 1489, "a": 132 }, { "d": 1490, "a": 70 }, { "d": 1491, "a": 115 }, { "d": 1492, "a": 44 }, { "d": 1493, "a": 117 }, { "d": 1494, "a": 9 }, { "d": 1495, "a": 64 }, { "d": 1496, "a": 37 }, { "d": 1497, "a": 145 }, { "d": 1498, "a": 14 }, { "d": 1499, "a": 86 }, { "d": 1500, "a": 119 }, { "d": 1501, "a": 200 }, { "d": 1502, "a": 23 }, { "d": 1503, "a": 85 }, { "d": 1504, "a": 145 }, { "d": 1505, "a": 49 }, { "d": 1506, "a": 145 }, { "d": 1507, "a": 58 }, { "d": 1509, "a": 124 }, { "d": 1510, "a": 69 }, { "d": 1511, "a": 14 }, { "d": 1512, "a": 137 }, { "d": 1513, "a": 45 }, { "d": 1514, "a": 114 }, { "d": 1515, "a": 186 }, { "d": 1516, "a": 219 }, { "d": 1517, "a": 199 }, { "d": 1518, "a": 223 }, { "d": 1519, "a": 28 }, { "d": 1520, "a": 185 }, { "d": 1521, "a": 45 }, { "d": 1522, "a": 63 }, { "d": 1523, "a": 18 }, { "d": 1524, "a": 144 }, { "d": 1525, "a": 17 }, { "d": 1526, "a": 99 }, { "d": 1527, "a": 214 }, { "d": 1528, "a": 237 }, { "d": 1530, "a": 194 }, { "d": 1531, "a": 186 }, { "d": 1532, "a": 19 }, { "d": 1533, "a": 200 }, { "d": 1534, "a": 23 }, { "d": 1535, "a": 185 }, { "d": 1536, "a": 45 }, { "d": 1537, "a": 249 }, { "d": 1538, "a": 145 }, { "d": 1539, "a": 58 }, { "d": 1550, "a": 158 }]; profile(profilejson); /* $.ajax({ url: 'profilejson', method: 'GET', success: function(data) { console.log("data =", data); profile(data); }, error: function(data) { console.log("err" + data) } }); */ </script> </body> </html>
这篇关于在任何图表点上获取坐标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!