在 Openlayers 中,如何根据通过相同坐标的次数来缩放 MultiLineString 的笔划宽度?
In Openlayers, how can I scale the stroke width of a MultiLineString based on the number of times the same coordinates are passed through?
我的 MultiLineString 目前的样式如下:
'MultiLineString': new Style({
stroke: new Stroke({
color: 'green',
width: 1
})
}),
我的 MultiLineString 的坐标看起来像这样:
[
[[3, 8], [4, 10], [5, 12]],
[[2, 4], [3, 8], [4, 10]]
]
数据中存在一些重叠。我想缩放数据重叠处的线宽,以帮助说明该线被多次覆盖。我猜我需要使用 RenderFunction(),但我很难理解下一步该做什么。
如有任何帮助,我们将不胜感激。
我提出的解决方案是利用库 Turf 中名为 lineOverlap
的函数。请参阅该函数的文档 here。该函数接受两个线段和 returns 一个 FeatureCollection
,其中有重叠的 LineSegment
。
import * as turf from '@turf/turf';
import GeoJSON from 'ol/format/GeoJSON.js';
const routes = [
turf.lineString([[1,2],[3,4],[5,6]]),
turf.lineString([[3,4],[5,6],[7,8]])
];
let overlapping = turf.lineOverlap(routes[0], routes[1]);
let format = new GeoJSON();
// convert to a format readable by OverLayers
let lines = format.readFeatures(overlapping);
// lines will only ever have a length of 1 or 0
if(lines.length) {
// this adds an attribute onto the feature which I then read in the styling function
lines[0].set('size', 2);
lines[0].getGeometry().transform('EPSG:4326', 'EPSG:3857');
vectorSource.addFeature(lines[0]);
}
在扩大 size
的同时添加多层迭代应该会产生预期的效果。
是的,可以使用 Turf 来完成,但 Turf 仅适用于 EPSG:4326 坐标,在 EPSG:4326 中重叠的内容在 EPSG:3857 中显示时不一定重叠,反之亦然,例如 [[0,50],[5,55],[10,60]] 在转换为 EPSG:3857 时不是一条直线,而 [[0,50],[10,60]]是。转换还会引入非常小的舍入差异。尽管非常小,但任何差异都会阻止检测到重叠(并且使用 Turf 的 km 公差设置可能会产生误报)。此示例执行额外的迭代,并向您的 MultiLineString 添加一个额外的组件以测试较长线段的顶点之间的交点。在四舍五入到 12 个位置后,在 EPSG:4326 中检测到重叠(现实世界中的分数值即使这样也可能不起作用)但是如果你放大到足够大,你可以看到它是 EPSG:3857 中的一条平行线。真正需要的是一个基于 Turf lineOverlap 源的函数,它可以处理任何坐标并处理适合这些坐标的毫米公差。
var transformR = function(coordinates, output, dimensions) {
var dims = dimensions || 2;
for (var i=0; i<coordinates.length; i+=dims) {
coordinates[i] = Math.round(coordinates[i]*1e12)/1e12;
coordinates[i+1] = Math.round(coordinates[i+1]*1e12)/1e12;
}
return coordinates;
}
var style = function(feature) {
switch(feature.getGeometry().getType()) {
case 'MultiLineString':
var increment = 2;
var styles = [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'green',
width: increment
})
})
];
var overlaps = [];
var format = new ol.format.GeoJSON();
var geometry = feature.getGeometry().clone().transform(map.getView().getProjection(), 'EPSG:4326');
geometry.applyTransform(transformR); // round transformed coordinates
var linestrings = geometry.getLineStrings();
for (var i=0; i<linestrings.length-1; i++) {
for (var j=i+1; j<linestrings.length; j++) {
var line1 = format.writeFeatureObject(new ol.Feature(linestrings[i]));
var line2 = format.writeFeatureObject(new ol.Feature(linestrings[j]));
var overlapping = turf.lineOverlap(line1, line2).features;
overlapping.forEach(function(overlap){ overlaps.push(overlap.geometry.coordinates); });
}
}
overlaps.forEach(function(overlap){
var width = increment;
var line = turf.lineString(overlap);
for (var i=0; i<linestrings.length; i++) {
var line1 = format.writeFeatureObject(new ol.Feature(linestrings[i]));
var overlapping = turf.lineOverlap(line, line1).features;
if (overlapping.length > 0 && JSON.stringify(overlapping[0].geometry.coordinates) == JSON.stringify(overlap)) {
width += increment;
}
}
styles.push(
new ol.style.Style({
geometry: new ol.geom.LineString(overlap).transform('EPSG:4326', map.getView().getProjection()),
stroke: new ol.style.Stroke({
color: 'green',
width: width
})
})
);
});
return styles;
}
}
var multiline = new ol.Feature(new ol.geom.MultiLineString([
[[6, 14], [2, 6]],
[[3, 8], [4, 10], [5, 12]],
[[2, 4], [3, 8], [4, 10]]
]));
var source = new ol.source.Vector();
var map = new ol.Map({
layers: [
new ol.layer.Vector({
source: source,
style: style
})
],
target: 'map',
view: new ol.View()
});
multiline.getGeometry().transform('EPSG:4326', map.getView().getProjection());
source.addFeature(multiline);
map.getView().fit(multiline.getGeometry());
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://npmcdn.com/@turf/turf@5.1.6/turf.min.js"></script>
<div id="map" class="map"></div>
我的 MultiLineString 目前的样式如下:
'MultiLineString': new Style({
stroke: new Stroke({
color: 'green',
width: 1
})
}),
我的 MultiLineString 的坐标看起来像这样:
[
[[3, 8], [4, 10], [5, 12]],
[[2, 4], [3, 8], [4, 10]]
]
数据中存在一些重叠。我想缩放数据重叠处的线宽,以帮助说明该线被多次覆盖。我猜我需要使用 RenderFunction(),但我很难理解下一步该做什么。
如有任何帮助,我们将不胜感激。
我提出的解决方案是利用库 Turf 中名为 lineOverlap
的函数。请参阅该函数的文档 here。该函数接受两个线段和 returns 一个 FeatureCollection
,其中有重叠的 LineSegment
。
import * as turf from '@turf/turf';
import GeoJSON from 'ol/format/GeoJSON.js';
const routes = [
turf.lineString([[1,2],[3,4],[5,6]]),
turf.lineString([[3,4],[5,6],[7,8]])
];
let overlapping = turf.lineOverlap(routes[0], routes[1]);
let format = new GeoJSON();
// convert to a format readable by OverLayers
let lines = format.readFeatures(overlapping);
// lines will only ever have a length of 1 or 0
if(lines.length) {
// this adds an attribute onto the feature which I then read in the styling function
lines[0].set('size', 2);
lines[0].getGeometry().transform('EPSG:4326', 'EPSG:3857');
vectorSource.addFeature(lines[0]);
}
在扩大 size
的同时添加多层迭代应该会产生预期的效果。
是的,可以使用 Turf 来完成,但 Turf 仅适用于 EPSG:4326 坐标,在 EPSG:4326 中重叠的内容在 EPSG:3857 中显示时不一定重叠,反之亦然,例如 [[0,50],[5,55],[10,60]] 在转换为 EPSG:3857 时不是一条直线,而 [[0,50],[10,60]]是。转换还会引入非常小的舍入差异。尽管非常小,但任何差异都会阻止检测到重叠(并且使用 Turf 的 km 公差设置可能会产生误报)。此示例执行额外的迭代,并向您的 MultiLineString 添加一个额外的组件以测试较长线段的顶点之间的交点。在四舍五入到 12 个位置后,在 EPSG:4326 中检测到重叠(现实世界中的分数值即使这样也可能不起作用)但是如果你放大到足够大,你可以看到它是 EPSG:3857 中的一条平行线。真正需要的是一个基于 Turf lineOverlap 源的函数,它可以处理任何坐标并处理适合这些坐标的毫米公差。
var transformR = function(coordinates, output, dimensions) {
var dims = dimensions || 2;
for (var i=0; i<coordinates.length; i+=dims) {
coordinates[i] = Math.round(coordinates[i]*1e12)/1e12;
coordinates[i+1] = Math.round(coordinates[i+1]*1e12)/1e12;
}
return coordinates;
}
var style = function(feature) {
switch(feature.getGeometry().getType()) {
case 'MultiLineString':
var increment = 2;
var styles = [
new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'green',
width: increment
})
})
];
var overlaps = [];
var format = new ol.format.GeoJSON();
var geometry = feature.getGeometry().clone().transform(map.getView().getProjection(), 'EPSG:4326');
geometry.applyTransform(transformR); // round transformed coordinates
var linestrings = geometry.getLineStrings();
for (var i=0; i<linestrings.length-1; i++) {
for (var j=i+1; j<linestrings.length; j++) {
var line1 = format.writeFeatureObject(new ol.Feature(linestrings[i]));
var line2 = format.writeFeatureObject(new ol.Feature(linestrings[j]));
var overlapping = turf.lineOverlap(line1, line2).features;
overlapping.forEach(function(overlap){ overlaps.push(overlap.geometry.coordinates); });
}
}
overlaps.forEach(function(overlap){
var width = increment;
var line = turf.lineString(overlap);
for (var i=0; i<linestrings.length; i++) {
var line1 = format.writeFeatureObject(new ol.Feature(linestrings[i]));
var overlapping = turf.lineOverlap(line, line1).features;
if (overlapping.length > 0 && JSON.stringify(overlapping[0].geometry.coordinates) == JSON.stringify(overlap)) {
width += increment;
}
}
styles.push(
new ol.style.Style({
geometry: new ol.geom.LineString(overlap).transform('EPSG:4326', map.getView().getProjection()),
stroke: new ol.style.Stroke({
color: 'green',
width: width
})
})
);
});
return styles;
}
}
var multiline = new ol.Feature(new ol.geom.MultiLineString([
[[6, 14], [2, 6]],
[[3, 8], [4, 10], [5, 12]],
[[2, 4], [3, 8], [4, 10]]
]));
var source = new ol.source.Vector();
var map = new ol.Map({
layers: [
new ol.layer.Vector({
source: source,
style: style
})
],
target: 'map',
view: new ol.View()
});
multiline.getGeometry().transform('EPSG:4326', map.getView().getProjection());
source.addFeature(multiline);
map.getView().fit(multiline.getGeometry());
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<script src="https://npmcdn.com/@turf/turf@5.1.6/turf.min.js"></script>
<div id="map" class="map"></div>