我正在使用 d3 在地圖上繪制路線:
const width = 400;
const height = width / 2;
const projection = d3.geoEquirectangular()
.translate([width / 2, height / 2])
.scale((width - 1) / 2 / Math.pi);
const route_projection = d3.geoEquirectangular()
.translate([width / 2, height / 2])
.scale((width - 1) / 2 / Math.pi);
//.preclip(SOME CLIPPING FUNCTION)
const route_path = d3.geoPath()
.projection(route_projection);
const path = d3.geoPath()
.projection(projection);
const zoom = d3.zoom()
.extent([
[0, 0],
[width, height]
])
.translateExtent([
[0, 0],
[width, height]
])
.scaleExtent([1, Infinity])
.on("zoom", zoomed);
let svg = d3.select('#map')
.append("svg")
.attr("width", width)
.attr("height", height);
svg.call(zoom);
svg.append("rect")
.attr("class", "background")
.attr("fill", "#b4dcfc")
.attr("width", width)
.attr("height", height);
let g = svg.append('g');
let geojson = {}
let curve = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"population": 200
},
"geometry": {
"type": "LineString",
"coordinates": [
[-56.12, -35.50],
[47.81, -25.37],
[78.71, 7.73]
]
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-56.12, -35.50]
},
"properties": {
"name": "Dinagat Islands"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [47.81, -25.37]
},
"properties": {
"name": "Dinagat Islands"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [78.71, 7.73]
},
"properties": {
"name": "Dinagat Islands"
}
}
]
}
function createMap() {
projection.fitSize([width, height], geojson);
route_projection.fitSize([width, height], geojson);
g
.attr("id", "dmas")
.selectAll("path")
.data(geojson.features)
.enter()
.append("path")
.attr("fill", "white")
.attr("stroke", "#222")
.attr("stroke-width", 1)
.attr("vector-effect", "non-scaling-stroke")
.attr("d", path);
g.append("path")
.datum(curve)
.attr("id", "route")
.attr("d", route_path)
.attr("fill", "none")
.attr("stroke", 'red')
.attr("stroke-width", 2)
.attr("vector-effect", "non-scaling-stroke")
.attr("stroke-opacity", 1);
}
function zoomed(transform) {
g
.selectAll('path')
.attr('transform', transform.transform)
// .attr('stroke-width', 2/transform.transform.k)
}
d3.json("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-50m.json")
.then(function(data) {
geojson = topojson.feature(data, data.objects.countries);
createMap();
})
<script src="https://unpkg.com/[email protected]/dist/d3-geo-polygon.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/topojson.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<div id="map"></div>
在 上route_projection,我想使用預剪輯將紅色路線的最大緯度限制在 -40 度以上的緯度,因此它最終會成為從南美洲到南非的直線。
像這樣:

我怎樣才能做到這一點?
uj5u.com熱心網友回復:
剪切功能不會達到正確的效果,因為它會剪切您的功能,而不是強迫它們遵循該線。
相反,我們可以將您的投影與地理變換結合起來,以強制線遵守投影空間內的規則:
const limit = d3.geoTransform({
point: function(x,y) {
this.stream.point(x, Math.min(y, projection([0,-36])[1]));
}
});
const route_projection = {
stream: function(s) {
return projection.stream(limit.stream(s));
}
};
const route_path = d3.geoPath()
.projection(route_projection);
這意味著我們只需要一個 equirectangular 投影而不是兩個,我們只需將它與 geoTransform 流組合并將該組合流傳遞給第二個路徑生成器:
顯示代碼片段
const width = 400;
const height = width / 2;
const projection = d3.geoEquirectangular()
.translate([width / 2, height / 2])
.scale((width - 1) / 2 / Math.pi);
const limit = d3.geoTransform({
point: function(x,y) {
this.stream.point(x, Math.min(y, projection([0,-36])[1]));
}
});
const route_projection = {
stream: function(s) {
return projection.stream(limit.stream(s));
}
};
const route_path = d3.geoPath()
.projection(route_projection);
const path = d3.geoPath()
.projection(projection);
const zoom = d3.zoom()
.extent([
[0, 0],
[width, height]
])
.translateExtent([
[0, 0],
[width, height]
])
.scaleExtent([1, Infinity])
.on("zoom", zoomed);
let svg = d3.select('#map')
.append("svg")
.attr("width", width)
.attr("height", height);
svg.call(zoom);
svg.append("rect")
.attr("class", "background")
.attr("fill", "#b4dcfc")
.attr("width", width)
.attr("height", height);
let g = svg.append('g');
let geojson = {}
let curve = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"population": 200
},
"geometry": {
"type": "LineString",
"coordinates": [
[-56.12, -35.50],
[47.81, -25.37],
[78.71, 7.73]
]
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-56.12, -35.50]
},
"properties": {
"name": "Dinagat Islands"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [47.81, -25.37]
},
"properties": {
"name": "Dinagat Islands"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [78.71, 7.73]
},
"properties": {
"name": "Dinagat Islands"
}
}
]
}
function createMap() {
projection.fitSize([width, height], geojson);
g
.attr("id", "dmas")
.selectAll("path")
.data(geojson.features)
.enter()
.append("path")
.attr("fill", "white")
.attr("stroke", "#222")
.attr("stroke-width", 1)
.attr("vector-effect", "non-scaling-stroke")
.attr("d", path);
g.append("path")
.datum(curve)
.attr("id", "route")
.attr("d", route_path)
.attr("fill", "none")
.attr("stroke", 'red')
.attr("stroke-width", 2)
.attr("vector-effect", "non-scaling-stroke")
.attr("stroke-opacity", 1);
}
function zoomed(transform) {
g
.selectAll('path')
.attr('transform', transform.transform)
}
d3.json("https://cdn.jsdelivr.net/npm/world-atlas@2/countries-50m.json")
.then(function(data) {
geojson = topojson.feature(data, data.objects.countries);
createMap();
})
<script src="https://unpkg.com/[email protected]/dist/d3-geo-polygon.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/topojson.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<div id="map"></div>
哪個應該給出:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/375826.html
標籤:javascript d3.js
