我想创建一个函数谁 return the altitude of the profile with a mouseover
当我在.json中有信息时,这很容易,这里的例子是指{{d':1508,“a”:77“}。我使用这个函数:
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);
}
但是,如果可能的话,我也希望在我有2点相距太远的情况下计算高度。例如,我有this profile for {"d": 1539, "a": 58}, {"d": 1550, "a": 158}。所以,我返回高度为d = 1539和d = 1550,但是,由于我的个人资料,我可以返回高度为d = 1546吗?
最诚挚的问候,Braz Damien。
codepen.io/Onchman/pen/dNpeaP这是codepen上的代码,我不知道如何从外部ressource添加json,所以,我试着直接在JavaScript部分添加它。
答案 0 :(得分:0)
参考此answer中的代码并将其应用于您的代码,您的mousemove
函数将重写为:
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));
}
完整运行代码:
<!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>