This should be an easy one, but I am not sure where the information I need is found.
When clicking on the white dot as the app is run,
it will log a coordinate like [750,216.66666666666666]
.
Now, move the white dot to the left until it wraps around and appears on the right.
it will log a coordinate like [-59.16853932584246,178.55640684382806]
.
The X coordinate is wrong.
If the white dot was instead moved to the right to approximately the same spot,
clicking on it will log a coordinate like [1449.9848745225447,166.78267751332552]
, which is what I need.
I need to know how to get the translation factor so I can apply it to the X coordinate and get the correct number.
How can I obtain that translation factor?
This factor cannot come from the click event. I need to be able to use information from the map itself.
If, for example, I move the white dot to the left until it wraps around and appears on the right and then I zoom in on the dot and click, it will log a coordinate like [-9708.575728449725, 88.81498717307477]. That is a large negative X coordinate.
What space is that coordinate in? i.e. what space does getPixelFromCoordinate
return a coordinate in? Is it a pixel on the canvas? Is it possible to simply get a canvas offset to convert it to the absolute div coordinate (what event.pixel
would contain)?
Again, I cannot use event.pixel
to get the coordinate as I need the coord outside of event handling. I need to start with a coordinate.
const osm = new ol.source.OSM();
osm.setTileGridForProjection(
"EPSG:4326",
ol.tilegrid.createXYZ({ extent: [-180, -90, 180, 90] })
);
const tileLayer = new ol.layer.Tile({ source: osm });
const coordinate = [-97, 38];
const point = new ol.Feature({
geometry: new ol.geom.Point(coordinate),
properties: {}
});
const layer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [point]
}),
style: (feature) => {
const properties = feature.getProperties();
let style;
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({ color: "#FFF" }),
stroke: new ol.style.Stroke({
color: "#FFF",
width: 2
})
})
});
return style;
}
});
const map = new ol.Map({
target: "map",
layers: [tileLayer, layer],
view: new ol.View({
projection: "EPSG:4326",
center: coordinate,
zoom: 2
}),
controls: ol.control.defaults.defaults({ attribution: false, zoom: false })
});
map.on("click", (event) => {
if (event.dragging) {
return;
}
const pixel = map.getPixelFromCoordinate(coordinate);
console.log(pixel);
});
ol.proj.get("EPSG:4326").setExtent([-180, -85, 180, 85]);
#map {
height: 500px;
width: 1500px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/dist/ol.min.js"></script>
<div id="map"></div>
Calculate which wrapped world you are clicking on, then adjust the feature coordinate by that number of world widths.
const osm = new ol.source.OSM();
osm.setTileGridForProjection(
"EPSG:4326",
ol.tilegrid.createXYZ({ extent: [-180, -90, 180, 90] })
);
const tileLayer = new ol.layer.Tile({ source: osm });
const coordinate = [-97, 38];
const point = new ol.Feature({
geometry: new ol.geom.Point(coordinate),
properties: {}
});
const layer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [point]
}),
style: (feature) => {
const properties = feature.getProperties();
let style;
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({ color: "#FFF" }),
stroke: new ol.style.Stroke({
color: "#FFF",
width: 2
})
})
});
return style;
}
});
const map = new ol.Map({
target: "map",
layers: [tileLayer, layer],
view: new ol.View({
projection: "EPSG:4326",
center: coordinate,
zoom: 2
}),
controls: ol.control.defaults.defaults({ attribution: false, zoom: false })
});
map.on("click", (event) => {
if (event.dragging) {
return;
}
const world = Math.floor((event.coordinate[0] + 180) / 360);
const pixel = map.getPixelFromCoordinate(
[coordinate[0] + 360 * world, coordinate[1]]
);
console.log(pixel);
});
ol.proj.get("EPSG:4326").setExtent([-180, -85, 180, 85]);
#map {
height: 500px;
width: 1500px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/dist/ol.min.js"></script>
<div id="map"></div>
Or use the view center to calculate the world:
const osm = new ol.source.OSM();
osm.setTileGridForProjection(
"EPSG:4326",
ol.tilegrid.createXYZ({ extent: [-180, -90, 180, 90] })
);
const tileLayer = new ol.layer.Tile({ source: osm });
const coordinate = [-97, 38];
const point = new ol.Feature({
geometry: new ol.geom.Point(coordinate),
properties: {}
});
const layer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [point]
}),
style: (feature) => {
const properties = feature.getProperties();
let style;
style = new ol.style.Style({
image: new ol.style.Circle({
radius: 10,
fill: new ol.style.Fill({ color: "#FFF" }),
stroke: new ol.style.Stroke({
color: "#FFF",
width: 2
})
})
});
return style;
}
});
const map = new ol.Map({
target: "map",
layers: [tileLayer, layer],
view: new ol.View({
projection: "EPSG:4326",
center: coordinate,
zoom: 2
}),
controls: ol.control.defaults.defaults({ attribution: false, zoom: false })
});
map.on("click", (event) => {
if (event.dragging) {
return;
}
const center = map.getView().getCenter();
let world = Math.floor((center[0] + 180) / 360);
const normalizedLon = center[0] - 360 * world;
if (normalizedLon - coordinate[0] < -180) {
world--;
} else if (normalizedLon - coordinate[0] > 180) {
world++;
}
const pixel = map.getPixelFromCoordinate(
[coordinate[0] + 360 * world, coordinate[1]]
);
console.log(pixel);
});
ol.proj.get("EPSG:4326").setExtent([-180, -85, 180, 85]);
#map {
height: 500px;
width: 1500px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/ol.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/10.2.1/dist/ol.min.js"></script>
<div id="map"></div>