はじめに
自治体などでは、自治体が保有する道路の位置を表示した図面を道路網図として公開しています。その際、道路の起点から終点までの位置がわかるよう、アイコンを設定しています。
今回も、SLD利用しますが、SLDでは、始点と終点のアイコンを設定できるような定義が用意されていないため、SLDのベンダーオプション(Vendor Option)を利用し、SLDReader本体をカスタマイズして、ラインの最後尾の頂点にアイコンを追加してみました。
ラインの最後尾の頂点にアイコンを追加する例
l_road.txt
SLDのベンダーオプション(Vendor Option)に、アイコンのパスと、サイズの要素を追加しています。あと、UOMの対応もできたので、UOMをLineSymbolizerの属性に追加しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?xml version="1.0" encoding="utf-16" standalone="no"?> <StyledLayerDescriptor version="1.0.0" xsi:schemaLocation="http://www.opengis.net/sld StyledLayerDescriptor.xsd" xmlns="http://www.opengis.net/sld" xmlns:ogc="http://www.opengis.net/ogc" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <NamedLayer> <Name>l_trans_road_emg</Name> <UserStyle> <Title>道路網図</Title> <FeatureTypeStyle> <Rule> <Name>0</Name> <Title>市道1級</Title> <LineSymbolizer uom="http://www.opengeospatial.org/se/units/metre"> <Stroke> <CssParameter name="stroke">#ff0000</CssParameter> <CssParameter name="stroke-width">12</CssParameter> </Stroke> <VendorOption name="endcap-href">/OpenLayersSample/SLDReader/images/Action_Debug_Start.svg</VendorOption> <VendorOption name="endcap-size">0.5</VendorOption> </LineSymbolizer> </Rule> </FeatureTypeStyle> </UserStyle> </NamedLayer> </StyledLayerDescriptor> |
sldreader.js
SLDReader本体をカスタマイズします。ベンダーオプションのアイコンのパスと、サイズの要素、UOMの値を取り込んでいます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
var SymbParsers = { // 省略 LineSymbolizer: function (node, obj, prop) { addPropArray(node, obj, prop); obj[prop.toLowerCase()][0].uom = node.getAttribute('uom'); return; }, // 省略 }; function lineStyle(symbolizer) { if (symbolizer.stroke && symbolizer.stroke.graphicstroke) { return getGraphicStrokeStyle(symbolizer); } var strokeStyle = new style.Style({ stroke: getSimpleStroke(symbolizer.stroke), }); if(symbolizer.uom){ strokeStyle.uom_ = symbolizer.uom; } if(symbolizer.vendoroptions){ if(symbolizer.vendoroptions.endcapHref){ strokeStyle.endcapHref_ = symbolizer.vendoroptions.endcapHref; strokeStyle.endcapSize_ = symbolizer.vendoroptions.endcapSize; } } return strokeStyle; } |
jsコード
ベンダーオプションのアイコンのパスと、サイズの要素から新たにstyleを生成し、
既存のstyleの最後尾に追加します。
また、この際、矢印の向きが正しい向きになるよう、最後尾の頂点とその前の頂点から
角度を計算し、rotationに設定しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
function createDynamicStyleFunction(sldUrl) { const sldText = getText(sldUrl); const sldObject = SLDReader.Reader(sldText); const sldLayer = SLDReader.getLayer(sldObject); const sldStyle = SLDReader.getStyle(sldLayer); const featureTypeStyle = sldStyle.featuretypestyles[0]; const olStyleFunction = SLDReader.createOlStyleFunction(featureTypeStyle); const dynamicStyleFunction = (feature, resolution) => { let styles = olStyleFunction(feature, resolution); let addStyles = []; styles.forEach((style) => { const stroke = style.getStroke(); if(stroke){ if(style.uom_){ stroke.getWidth = () =>{ return stroke.width_ / resolution; } } if(style.endcapHref_){ var coordinates = feature.getGeometry().getCoordinates(); var lastCoord = coordinates[coordinates.length - 1]; var preCoord = coordinates[coordinates.length - 2]; const dx = lastCoord[0] - preCoord[0]; const dy = lastCoord[1] - preCoord[1]; const rotation = Math.atan2(dy, dx); var addStyle = new ol.style.Style({ geometry: new ol.geom.Point(lastCoord), image: new ol.style.Icon({ src: style.endcapHref_, color: stroke.color_, anchor: [0.5, 0.5], rotateWithView: true, rotation: -rotation, }) }); const newScale = style.endcapSize_ / resolution; addStyle.getImage().setScale(newScale); addStyles.push(addStyle); } } }); if(addStyles){ styles = styles.concat(addStyles); } return styles; }; return dynamicStyleFunction; } |
カスタマイズ後の地図

拡大すると、アイコン及びラインのサイズも大きくなります。

まとめ
ラインの頂点にアイコンを追加する機能は、QGISなど、GISでは一般的な機能ですが、SLDの標準機能で対応できなかったことは残念でした。一応、SLDのベンダーオプション(Vendor Option)を利用したり、SLDReader本体のカスタマイズで対応しましたが、カスタマイズ箇所が多く、スマートなやり方ではないので、引き続き、別の方法も調査してみます。