openlayers v6 中的自定义网格/标线
Custom grid / graticule in openlayers v6
我正在尝试使用线之间的距离向我的地图添加网格(就像经纬网一样),我希望线标签保持在同一位置并在视图更改时更新网格。
我正在监听矢量图层上的预渲染事件并从 getVectorContext(event);
返回的 CanvasImmediateRenderer
中绘图,但我未能成功地将标签贴在顶部和左侧边框上。
非常感谢任何帮助。
看起来文本的行放置不适用于立即呈现。标签的单独点图会更好,您可以使用 event.framestate.extent
确定左侧或顶部坐标。
为顶部和侧面标签使用单独的样式,textAlign
'left'
或 'right'
视情况而定,并为顶部标签使用 Math.PI/2 旋转。
要强制渲染网格,请使用具有一个几乎不可见特征的专用层和一个无限渲染缓冲区,如下所示:
let grid = new VectorLayer({
source: new VectorSource({
features: [new Feature(new Point([0,0]))]
}),
style: new Style({
image: new CircleStyle({
radius: 0
})
}),
renderBuffer: Infinity,
});
// Listen to prerender event to render the grid
grid.on('prerender', function(event: RenderEvent) {
let unitSplit = .1; // every .1 m
let pxToUnit = view.getResolution();
let pxSplit = unitSplit / pxToUnit;
let [xmin, ymin, xmax, ymax] = event.frameState.extent
while (pxSplit * 2 < 100) {
unitSplit *= 2;
pxSplit = unitSplit / pxToUnit; // distance between two lines
}
let startX = Math.round(xmin / unitSplit) * unitSplit; // first line
let endX = Math.round(xmax / unitSplit) * unitSplit; // last line
let startY = Math.round(ymin / unitSplit) * unitSplit;
let endY = Math.round(ymax / unitSplit) * unitSplit;
let ctx = getVectorContext(event);
let lineStyle = new Style({ stroke: new Stroke({ color: "#444751", width: 1 }) });
ctx.setStyle(lineStyle);
// drawing lines
for (let i = startX; i <= endX; i = i + unitSplit) {
ctx.drawLineString(new LineString([[i, ymin], [i, ymax]])); // draw
}
for (let i = startY; i <= endY; i = i + unitSplit) {
ctx.drawLineString(new LineString([[xmin, i], [xmax, i]]));
}
let text = new Text({ fill: new Fill({ color: "#ffffff" }), font: "12px arial", textAlign: "left" })
// drawing labels
for (let i = startY; i <= endY; i = i + unitSplit) {
text.setText(`${(i / 1000).toFixed(2)} km`);
lineStyle.setText(text)
ctx.setStyle(lineStyle);
ctx.drawPoint(new Point([event.frameState.extent[0] + 10 * pxToUnit, i + pxToUnit]))
}
text.setRotation(Math.PI / 2)
for (let i = startX; i <= endX; i = i + unitSplit) {
text.setText(`${(i / 1000).toFixed(2)} km`);
lineStyle.setText(text)
ctx.setStyle(lineStyle);
ctx.drawPoint(new Point([i + pxToUnit, event.frameState.extent[3] - 10 * pxToUnit]))
}
}
我正在尝试使用线之间的距离向我的地图添加网格(就像经纬网一样),我希望线标签保持在同一位置并在视图更改时更新网格。
我正在监听矢量图层上的预渲染事件并从 getVectorContext(event);
返回的 CanvasImmediateRenderer
中绘图,但我未能成功地将标签贴在顶部和左侧边框上。
非常感谢任何帮助。
看起来文本的行放置不适用于立即呈现。标签的单独点图会更好,您可以使用 event.framestate.extent
确定左侧或顶部坐标。
为顶部和侧面标签使用单独的样式,textAlign
'left'
或 'right'
视情况而定,并为顶部标签使用 Math.PI/2 旋转。
要强制渲染网格,请使用具有一个几乎不可见特征的专用层和一个无限渲染缓冲区,如下所示:
let grid = new VectorLayer({
source: new VectorSource({
features: [new Feature(new Point([0,0]))]
}),
style: new Style({
image: new CircleStyle({
radius: 0
})
}),
renderBuffer: Infinity,
});
// Listen to prerender event to render the grid
grid.on('prerender', function(event: RenderEvent) {
let unitSplit = .1; // every .1 m
let pxToUnit = view.getResolution();
let pxSplit = unitSplit / pxToUnit;
let [xmin, ymin, xmax, ymax] = event.frameState.extent
while (pxSplit * 2 < 100) {
unitSplit *= 2;
pxSplit = unitSplit / pxToUnit; // distance between two lines
}
let startX = Math.round(xmin / unitSplit) * unitSplit; // first line
let endX = Math.round(xmax / unitSplit) * unitSplit; // last line
let startY = Math.round(ymin / unitSplit) * unitSplit;
let endY = Math.round(ymax / unitSplit) * unitSplit;
let ctx = getVectorContext(event);
let lineStyle = new Style({ stroke: new Stroke({ color: "#444751", width: 1 }) });
ctx.setStyle(lineStyle);
// drawing lines
for (let i = startX; i <= endX; i = i + unitSplit) {
ctx.drawLineString(new LineString([[i, ymin], [i, ymax]])); // draw
}
for (let i = startY; i <= endY; i = i + unitSplit) {
ctx.drawLineString(new LineString([[xmin, i], [xmax, i]]));
}
let text = new Text({ fill: new Fill({ color: "#ffffff" }), font: "12px arial", textAlign: "left" })
// drawing labels
for (let i = startY; i <= endY; i = i + unitSplit) {
text.setText(`${(i / 1000).toFixed(2)} km`);
lineStyle.setText(text)
ctx.setStyle(lineStyle);
ctx.drawPoint(new Point([event.frameState.extent[0] + 10 * pxToUnit, i + pxToUnit]))
}
text.setRotation(Math.PI / 2)
for (let i = startX; i <= endX; i = i + unitSplit) {
text.setText(`${(i / 1000).toFixed(2)} km`);
lineStyle.setText(text)
ctx.setStyle(lineStyle);
ctx.drawPoint(new Point([i + pxToUnit, event.frameState.extent[3] - 10 * pxToUnit]))
}
}