简体   繁体   中英

OpenLayers 3: Offset stroke style

I have LineString features styled by a single stroke. Some of these features represent two things, so in addition to the initial stroke color, I would like to have a parallel line next to it in a different color. This would be a no-brainer if ol/style/Stroke had an offset property like ol/style/Image does, but sadly, it does not. If I created offset geometries for those features, they wouldn't be visible from a zoomed out level. What are my options?

You can offset the geometries based on resolution

 var style = function(feature, resolution) { var colors = ['green', 'yellow', 'red']; var width = 4; var styles = []; for (var line = 0; line < colors.length; line++) { var dist = width * resolution * (line - (colors.length-1)/2); var geom = feature.getGeometry(); var coords = []; var counter = 0; geom.forEachSegment(function(from, to) { var angle = Math.atan2(to[1] - from[1], to[0] - from[0]); var newFrom = [ Math.sin(angle) * dist + from[0], -Math.cos(angle) * dist + from[1] ]; var newTo = [ Math.sin(angle) * dist + to[0], -Math.cos(angle) * dist + to[1] ]; coords.push(newFrom); coords.push(newTo); if (coords.length > 2) { var intersection = math.intersect(coords[counter], coords[counter+1], coords[counter+2], coords[counter+3]); coords[counter+1] = (intersection) ? intersection : coords[counter+1]; coords[counter+2] = (intersection) ? intersection : coords[counter+2]; counter += 2; } }); styles.push( new ol.style.Style({ geometry: new ol.geom.LineString(coords), stroke: new ol.style.Stroke({ color: colors[line], width: width }) }) ); } return styles; }; var raster = new ol.layer.Tile({ source: new ol.source.OSM() }); var source = new ol.source.Vector(); var vector = new ol.layer.Vector({ source: source, style: style }); var map = new ol.Map({ layers: [raster, vector], target: 'map', view: new ol.View({ center: [-11000000, 4600000], zoom: 4 }) }); map.addInteraction(new ol.interaction.Draw({ source: source, type: 'LineString' })); 
 html, body, .map { margin: 0; padding: 0; width: 100%; height: 100%; } 
 <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://cdnjs.cloudflare.com/ajax/libs/mathjs/5.4.1/math.min.js"></script> <div id="map" class="map"></div> 

The intersect test prevents effects like this on sharp angles

在此处输入图片说明

For each each segment of the feature geometry the style function calculates parallel segments set to be 4 pixels apart regardless of the resolution (in this case line width and spacing are the same) for the styling geometries centered around the original segment (eg if three colors the center style line would follow the original and the outer style lines are offset by +/- 4, if two colors each lines would be offset by +/- 2) Initially the parallel segments are the same length as the original but need to be increased at outside angles or reduced at inside angles so math.intersect is used to find the point where they should join to form a continuous line. Finally for each color the completed linestring is used as the geometry for the color's style, and an array containing each style is returned.

Here is a second example where instead of simple colors and fixed width each offset line has its own width and stroke pattern.

 var white = [255, 255, 255, 1]; var blue = [0, 153, 255, 1]; var width = 3; var pointStyle = new ol.style.Style({ image: new ol.style.Circle({ radius: width * 2, fill: new ol.style.Fill({ color: blue }), stroke: new ol.style.Stroke({ color: white, width: width / 2 }) }), zIndex: Infinity }); var style = function(feature, resolution) { var widths = [10, 10]; var strokes = [ [ { width: 4, color: '#7af500' }, { width: 4, color: '#55aa00', lineDash: [7,9] } ], [ { width: 2, color: 'black' }, { width: 8, color: 'black', lineDash: [2,14], lineCap: 'butt' } ] ]; var styles = [pointStyle]; var totalWidth = 0 for (var line = 0; line < widths.length; line++) { totalWidth += widths[line]; } var width = 0; for (var line = 0; line < widths.length; line++) { var dist = (width + widths[line]/2 - totalWidth/2) * resolution; width += widths[line]; var geom = feature.getGeometry(); if (geom.forEachSegment) { var coords = []; var counter = 0; geom.forEachSegment(function(from, to) { var angle = Math.atan2(to[1] - from[1], to[0] - from[0]); var newFrom = [ Math.sin(angle) * dist + from[0], -Math.cos(angle) * dist + from[1] ]; var newTo = [ Math.sin(angle) * dist + to[0], -Math.cos(angle) * dist + to[1] ]; coords.push(newFrom); coords.push(newTo); if (coords.length > 2) { var intersection = math.intersect(coords[counter], coords[counter+1], coords[counter+2], coords[counter+3]); coords[counter+1] = (intersection) ? intersection : coords[counter+1]; coords[counter+2] = (intersection) ? intersection : coords[counter+2]; counter += 2; } }); strokes[line].forEach( function(stroke) { styles.push( new ol.style.Style({ geometry: new ol.geom.LineString(coords), stroke: new ol.style.Stroke(stroke) }) ); }); } } return styles; }; var raster = new ol.layer.Tile({ source: new ol.source.OSM() }); var source = new ol.source.Vector(); var vector = new ol.layer.Vector({ source: source, style: style }); var map = new ol.Map({ layers: [raster, vector], target: 'map', view: new ol.View({ center: [-11000000, 4600000], zoom: 4 }) }); map.addInteraction(new ol.interaction.Draw({ source: source, style: style, type: 'LineString' })); 
 html, body, .map { margin: 0; padding: 0; width: 100%; height: 100%; } 
 <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://cdnjs.cloudflare.com/ajax/libs/mathjs/5.4.1/math.min.js"></script> <div id="map" class="map"></div> 

I have a version of this that works - but not when I zoom the chart.

Lines separates on zoom

I plot lines on the chart (from the database) and use our function to draw the lines.

I tried to insert code here but my functions in the javascript are not run. How do I use functions in code snipplets?

 function print_my_string( my_string ) { console.log( my_string ); }
 html, body, .map { margin: 0; padding: 0; width: 100%; height: 100%; }
 <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://cdnjs.cloudflare.com/ajax/libs/mathjs/5.4.1/math.min.js"></script> <div id="map" class="map"></div> // How do I use the java-script (Include before called... <script>print_my_string( "Hello" );</script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM