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?
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]
});
}
}
});
});
#map {
height: 512px;
width: 1024px;
}
<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>
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
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]
});
}
}
});
});
#map {
height: 512px;
width: 1024px;
}
<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>