还努力在绘图的 Mapbox 中绘制箭头。
我使用与 @guidout 答案类似的方法来手动构建箭头,但使用单个 geojson 层(这避免了使用多个跟踪的性能问题)。
我正在使用 geojson MultiLineString 层。
geojson MultiLineString 具有以下格式(来自维基百科):
{
"type": "MultiLineString",
"coordinates": [
[[10, 10], [20, 20], [10, 40]], <-- each of this can be used to draw an arrow
[[40, 40], [30, 30], [40, 20], [30, 10]]
]
}
Code:
function rotate(a, theta) {
return [a[0]*Math.cos(theta) - a[1]*Math.sin(theta), a[0]*Math.sin(theta) + a[1]*Math.cos(theta)];
}
function createArrow(a, b) {
// a: source point
// b: destination point
var angle = Math.atan2(a[1]-b[1], a[0]-b[0]);
var v = [b[0]-a[0], b[1]-a[1]] // get direction vector
var m = Math.sqrt(Math.pow(v[0], 2) + Math.pow(v[1], 2)) // module
var u = [v[0]/m, v[1]/m] // get unitary vector in the direction
var k = 0.2 // how far to place the arrow end
var newb = [b[0]-u[0]*k, b[1]-u[1]*k] // place the arrow end a bit before the destination
var s1 = rotate([0.02, 0.02], angle) // "sides" of the arrow. Applied to a base vector in left direction <--, and rotated to match the correct angle
var s2 = rotate([0.02, -0.02], angle)
return [a, newb, [newb[0]+s1[0], newb[1]+s1[1]], newb, [newb[0]+s2[0], newb[1]+s2[1]]]
}
//...
var arrows = sourceDestinationPairs.map(x => createArrow(x[0], x[1]));
var mapboxLayer = {
'sourcetype': 'geojson',
'source': {
"type": "MultiLineString",
"coordinates": arrows
},
'below': '', 'type': 'line',
'color': 'grey', 'opacity': 1,
'line': {'width': 2}
}
layout.mapbox.layers.push(mapboxLayer)
// ...
Plotly.plot('mapDiv', data, layout)
缺点:
- 必须手动构建箭头
- 缩放也会缩放箭头
- 箭头中存在轻微变形,具体取决于投影如何缩放经度与纬度坐标比(默认 Mapbox 墨卡托投影可接受)