英文:
OpenLayers: How can I move the shortest distance to fit an extent?
问题
以下是您要翻译的内容:
点击蓝色圆圈,地图将移动很远,蓝色圆圈将从地图的右边出现。
这个移动很奇怪。蓝色圆圈只需要向右移动一小段距离。
发生这种情况的原因是蓝色圆圈在首次出现时位于世界之外(-180经度至180经度)。fit操作指定了坐标范围为-180至180。
我认为如果我能提供一个考虑地图当前位置的范围来进行适配操作,那么这个问题可能会得到解决。我尝试过查看各种函数,如获取视图的投影,但它包含预期的值[-180,-90,180,90],并没有指示我实际上正在查看超出这个范围的内容。
我该如何使其工作?
请注意,代码部分不进行翻译。
英文:
Click on the blue circle, the map will move a long distance and the blue circle will appear from the right edge of the map.
This movement is strange. The blue circle should only need to move a short distance to the right.
The reason why this is happening is because the blue circle, when it first appears, is outside of the world ( -180 longitude - 180 longitude ). The fit operation specifies coordinates with -180 - 180.
I figure I could get this to work if I could provide an extent to fit to that took into account the current position of the map. I have tried looking at various functions like getting the projection of then view, but it contains the expected values of [-180, -90, 180, 90] and doesn't indicate I am actually viewing outside of that.
How can I get this to work?
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
function createPoints(points, groupName) {
const features = [];
for (const [i, point] of points.entries()) {
const feature = {
type: "Feature",
geometry: {
type: "Point",
coordinates: point
},
properties: {
id: `${groupName} index ${i}`,
groupName
}
};
features.push(feature);
}
const json = {
type: "FeatureCollection",
features
};
return json;
}
const thePoints = createPoints(
[
[50, 33],
[50, 33],
[50, 33],
[50, 33]
],
"thePoints"
);
const styles = {
Point: new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({ color: "red" })
}),
stroke: new ol.style.Stroke({
color: "hsla(0, 50%, 100%, 1.0)",
width: 5
}),
fill: new ol.style.Fill({
color: "hsla(0, 50%, 50%, 1.0)"
})
})
};
const styleFunction = function (feature) {
const featureType = feature.getGeometry().getType();
return styles[featureType];
};
const vectorSource = new ol.source.Vector({
features: new ol.format.GeoJSON({
featureProjection: "EPSG:4326" // 4326 3857
}).readFeatures(thePoints)
});
const cluster = new ol.source.Cluster({
distance: 30,
minDistance: 10,
source: vectorSource
});
const styleCache = {};
const vectorLayer = new ol.layer.Vector({
source: cluster,
style: function (feature) {
const size = feature.get("features").length;
let style = styleCache[size];
if (!style) {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
stroke: new ol.style.Stroke({
color: "#fff"
}),
fill: new ol.style.Fill({
color: "#3399CC"
})
}),
text: new ol.style.Text({
text: size.toString(),
fill: new ol.style.Fill({
color: "#fff"
})
})
});
styleCache[size] = style;
}
return style;
},
zIndex: 5,
properties: {
name: "big"
}
});
const map = new ol.Map({
target: "map",
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer
],
view: new ol.View({
projection: "EPSG:4326",
center: [-210, 0],
zoom: 1
})
});
map.on("click", (e) => {
vectorLayer.getFeatures(e.pixel).then((clickedFeatures) => {
if (clickedFeatures.length) {
// Get clustered Coordinates
const features = clickedFeatures[0].get("features");
if (features.length > 1) {
const extent = ol.extent.boundingExtent(
features.map((r) => r.getGeometry().getCoordinates())
);
const currentZoom = map.getView().getZoom();
map.getView().fit(extent, {
duration: 2000,
maxZoom: currentZoom,
padding: [50, 50, 50, 50]
});
}
}
});
});
<!-- language: lang-css -->
#map {
height: 512px;
width: 1024px;
}
<!-- language: lang-html -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/dist/ol.min.js"></script>
<div id="map"></div>
<!-- end snippet -->
答案1
得分: 1
你需要计算你点击的包装世界的偏移量,然后将特性的范围按照这个世界宽度的数量进行偏移。
map.on("click", (e) => {
vectorLayer.getFeatures(e.pixel).then((clickedFeatures) => {
if (clickedFeatures.length) {
// 获取集群坐标
const features = clickedFeatures[0].get("features");
if (features.length > 1) {
const extent = ol.extent.boundingExtent(
features.map((r) => r.getGeometry().getCoordinates())
);
const currentZoom = map.getView().getZoom();
const projectionExtent = map.getView().getProjection().getExtent();
const projectionWidth = ol.extent.getWidth(projectionExtent);
const clickedWorld = Math.floor(
(e.coordinate[0] - projectionExtent[0]) / projectionWidth
);
extent[0] += clickedWorld * projectionWidth;
extent[2] += clickedWorld * projectionWidth;
map.getView().fit(extent, {
duration: 2000,
maxZoom: currentZoom,
padding: [50, 50, 50, 50]
});
}
}
});
});
这段代码描述了如何在地图上点击某个位置后,计算包含点击的特性集群范围,并将地图视图调整到该范围,以便它完全可见。
英文:
You would need to calculate the offset of the wrapped world you clicked on, then offset the features extent by that number of world widths
<!-- begin snippet: js hide: false console: true babel: null -->
<!-- language: lang-js -->
function createPoints(points, groupName) {
const features = [];
for (const [i, point] of points.entries()) {
const feature = {
type: "Feature",
geometry: {
type: "Point",
coordinates: point
},
properties: {
id: `${groupName} index ${i}`,
groupName
}
};
features.push(feature);
}
const json = {
type: "FeatureCollection",
features
};
return json;
}
const thePoints = createPoints(
[
[50, 33],
[50, 33],
[50, 33],
[50, 33]
],
"thePoints"
);
const styles = {
Point: new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
fill: new ol.style.Fill({ color: "red" })
}),
stroke: new ol.style.Stroke({
color: "hsla(0, 50%, 100%, 1.0)",
width: 5
}),
fill: new ol.style.Fill({
color: "hsla(0, 50%, 50%, 1.0)"
})
})
};
const styleFunction = function (feature) {
const featureType = feature.getGeometry().getType();
return styles[featureType];
};
const vectorSource = new ol.source.Vector({
features: new ol.format.GeoJSON({
featureProjection: "EPSG:4326" // 4326 3857
}).readFeatures(thePoints)
});
const cluster = new ol.source.Cluster({
distance: 30,
minDistance: 10,
source: vectorSource
});
const styleCache = {};
const vectorLayer = new ol.layer.Vector({
source: cluster,
style: function (feature) {
const size = feature.get("features").length;
let style = styleCache[size];
if (!style) {
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
stroke: new ol.style.Stroke({
color: "#fff"
}),
fill: new ol.style.Fill({
color: "#3399CC"
})
}),
text: new ol.style.Text({
text: size.toString(),
fill: new ol.style.Fill({
color: "#fff"
})
})
});
styleCache[size] = style;
}
return style;
},
zIndex: 5,
properties: {
name: "big"
}
});
const map = new ol.Map({
target: "map",
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer
],
view: new ol.View({
projection: "EPSG:4326",
center: [-210, 0],
zoom: 1
})
});
map.on("click", (e) => {
vectorLayer.getFeatures(e.pixel).then((clickedFeatures) => {
if (clickedFeatures.length) {
// Get clustered Coordinates
const features = clickedFeatures[0].get("features");
if (features.length > 1) {
const extent = ol.extent.boundingExtent(
features.map((r) => r.getGeometry().getCoordinates())
);
const currentZoom = map.getView().getZoom();
const projectionExtent = map.getView().getProjection().getExtent();
const projectionWidth = ol.extent.getWidth(projectionExtent);
const clickedWorld = Math.floor(
(e.coordinate[0] - projectionExtent[0]) / projectionWidth
);
extent[0] += clickedWorld * projectionWidth;
extent[2] += clickedWorld * projectionWidth;
map.getView().fit(extent, {
duration: 2000,
maxZoom: currentZoom,
padding: [50, 50, 50, 50]
});
}
}
});
});
<!-- language: lang-css -->
#map {
height: 512px;
width: 1024px;
}
<!-- language: lang-html -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/7.3.0/dist/ol.min.js"></script>
<div id="map"></div>
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论