From a868b7cba6e878d6d62320b82f6aa7665be4f0fb Mon Sep 17 00:00:00 2001 From: lolochristen Date: Mon, 23 Oct 2023 18:04:52 +0200 Subject: [PATCH 1/9] StyleOptions classes and callback for geojson styles --- .../Pages/GeoJsonDemo.razor | 22 +- src/OpenLayers.Blazor/Map.razor.cs | 46 +++- src/OpenLayers.Blazor/StyleOptions.cs | 235 ++++++++++++++++++ .../wwwroot/openlayers_interop.js | 138 ++++------ 4 files changed, 342 insertions(+), 99 deletions(-) create mode 100644 src/OpenLayers.Blazor/StyleOptions.cs diff --git a/src/OpenLayers.Blazor.Demo.Components/Pages/GeoJsonDemo.razor b/src/OpenLayers.Blazor.Demo.Components/Pages/GeoJsonDemo.razor index 28c1601..8b1d299 100644 --- a/src/OpenLayers.Blazor.Demo.Components/Pages/GeoJsonDemo.razor +++ b/src/OpenLayers.Blazor.Demo.Components/Pages/GeoJsonDemo.razor @@ -1,5 +1,8 @@ @page "/geojsondemo" @using System.Text.Json +@using OpenLayers.Blazor.Internal +@using Shape = OpenLayers.Blazor.Shape +@using System.ComponentModel.Design
@@ -11,7 +14,7 @@
- + @@ -27,4 +30,21 @@ var json = await HttpClient.GetFromJsonAsync("https://labs.karavia.ch/swiss-boundaries-geojson/geojson/2020/swissBOUNDARIES3D_1_3_TLM_LANDESGEBIET.geojson"); await _map.LoadGeoJson(json); } + + private StyleOptions GetShapeStyle(Shape shape) + { + return new StyleOptions() + { + Stroke = new StyleOptions.StrokeOptions() + { + Color = "red", + Width = 3, + LineDash = new double[] { 4 } + }, + Fill = new StyleOptions.FillOptions() + { + Color = shape.Properties["NAME"].ToString() == "Liechtenstein" ? "rgba(0, 255, 50, 0.5)" : "rgba(0, 0, 255, 0.3)" + } + }; + } } \ No newline at end of file diff --git a/src/OpenLayers.Blazor/Map.razor.cs b/src/OpenLayers.Blazor/Map.razor.cs index 3bd9a58..67d0210 100644 --- a/src/OpenLayers.Blazor/Map.razor.cs +++ b/src/OpenLayers.Blazor/Map.razor.cs @@ -455,10 +455,11 @@ public ValueTask SetZoomToExtent(ExtentType extent) /// Loads GeoJson data (https://geojson.org/) to the map /// /// GeoJson Data - /// - public ValueTask LoadGeoJson(JsonElement json, string? dataProjection = null) + /// Data projection of GeoJson + /// Raise events for new created features + public ValueTask LoadGeoJson(JsonElement json, string? dataProjection = null, bool? raiseEvents = true) { - return _module?.InvokeVoidAsync("MapOLLoadGeoJson", _mapId, json, dataProjection) ?? ValueTask.CompletedTask; + return _module?.InvokeVoidAsync("MapOLLoadGeoJson", _mapId, json, dataProjection, raiseEvents) ?? ValueTask.CompletedTask; } /// @@ -526,6 +527,19 @@ public async Task SetVisibleExtent(Extent extent) if (_module != null) await _module.InvokeVoidAsync("MapOLSetVisibleExtent", _mapId, extent); } + [JSInvokable] + public StyleOptions OnGetShapeStyle(Internal.Shape shape) + { +#if DEBUG + Console.WriteLine($"OnGetShapeStyle: {System.Text.Json.JsonSerializer.Serialize(shape)}"); +#endif + + return ShapeStyleCallback(new Shape(shape)); + } + + [Parameter] + public Func ShapeStyleCallback { get; set; } = DefaultShapeStyleCallback; + public Task SetDrawingSettings() { return SetDrawingSettings(EnableNewShapes, EnableEditShapes, EnableShapeSnap, NewShapeTemplate); @@ -544,6 +558,10 @@ public async Task SetDrawingSettings(bool newShapes, bool editShapes, bool shape } } + /// + /// Undo last drawing interaction + /// + /// public async Task Undo() { if (_module != null) await _module.InvokeVoidAsync("MapOLUndoDrawing", _mapId); @@ -587,4 +605,26 @@ public ValueTask UpdateShape(Shape shape) #endif return _module?.InvokeVoidAsync("MapOLUpdateShape", _mapId, shape.InternalFeature) ?? ValueTask.CompletedTask; } + + /// + /// Default Style Callback + /// + /// + /// + public static StyleOptions DefaultShapeStyleCallback(Shape shape) + { + return new StyleOptions() + { + Stroke = new StyleOptions.StrokeOptions() + { + Color = "blue", + Width = 3, + LineDash = new double[] { 4 } + }, + Fill = new StyleOptions.FillOptions() + { + Color = "rgba(0, 0, 255, 0.3)" + } + }; + } } \ No newline at end of file diff --git a/src/OpenLayers.Blazor/StyleOptions.cs b/src/OpenLayers.Blazor/StyleOptions.cs new file mode 100644 index 0000000..81aa179 --- /dev/null +++ b/src/OpenLayers.Blazor/StyleOptions.cs @@ -0,0 +1,235 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace OpenLayers.Blazor +{ + public class StyleOptions + { + public FillOptions? Fill { get; set; } + public ImageOptions? Image { get; set; } + + public StrokeOptions? Stroke { get; set; } + + public TextOptions? Text { get; set; } + + public CircleStyleOptions? Circle { get; set; } + + public IconStyleOptions? Icon { get; set; } + + public double? zIndex { get; set; } + + /// + /// https://openlayers.org/en/latest/apidoc/module-ol_style_Fill-Fill.html + /// + public class FillOptions + { + public string Color { get; set; } + } + + /// + /// https://openlayers.org/en/latest/apidoc/module-ol_style_Image-ImageStyle.html + /// + public class ImageOptions + { + public double Opactiy { get; set; } = 1; + public bool RotateWithView { get; set; } + public double? Rotation { get; set; } + public double? Scale { get; set; } + public double[]? Displacement { get; set; } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public DeclutterMode? DeclutterMode { get; set; } + } + + /// + /// see https://openlayers.org/en/latest/apidoc/module-ol_style_Stroke-Stroke.html + /// + public class StrokeOptions + { + public string Color { get; set; } + public string? LineCap { get; set; } + public string? LineJoin { get; set; } + public double[]? LineDash { get; set; } + public double? LineDashOffset { get; set; } + public double? MiterLimit { get; set; } + public double Width { get; set; } + } + + /// + /// https://openlayers.org/en/latest/apidoc/module-ol_style_Text-Text.html + /// + public class TextOptions + { + public string Font { get; set; } + public double? MaxAngle { get; set; } + public double? OffsetX { get; set; } + public double? OffsetY { get; set; } + public bool Overflow { get; set; } = false; + public string? Placement { get; set; } + public double? Repeat { get; set; } + public double? Scale { get; set; } + public bool? RotateWithView { get; set; } + public double? Rotation { get; set; } + public string Text { get; set; } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public CanvasTextAlign? TextAlign { get; set; } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public TextJustify? Justify { get; set; } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public CanvasTextBaseline? TextBaseline { get; set; } + + public FillOptions? Fill { get; set; } + public StrokeOptions? Stroke { get; set; } + public FillOptions? BackgroundFill { get; set; } + public StrokeOptions? BackgroundStroke { get; set; } + public List Padding { get; set; } = new List { 0, 0, 0, 0 }; + } + + public enum TextPlacement + { + Point, + Line + } + + public enum CanvasTextAlign + { + Left, + Right, + Center, + End, + Start + } + + public enum TextJustify + { + Left, + Center, + Right + } + + public enum CanvasTextBaseline + { + Bottom, + Top, + Middle, + Alphabetic, + Hanging, + Ideographic + } + + /// + /// https://openlayers.org/en/latest/apidoc/module-ol_style_Image-ImageStyle.html + /// + public abstract class ImageStyleOptions + { + public double? Opacity { get; set; } + public bool? RotateWithView { get; set; } + public double? Rotation { get; set; } + public double? Scale { get; set; } + public double[]? Displacement { get; set; } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public DeclutterMode? DeclutterMode { get; set; } + } + + public enum DeclutterMode + { + Declutter, + Obstacle, + None + } + + public class IconStyleOptions : ImageStyleOptions + { + public List Anchor { get; set; } = new List { 0.5, 0.5 }; + + [JsonConverter(typeof(JsonStringEnumConverter))] + public IconOrigin AnchorOrigin { get; set; } = IconOrigin.TopLeft; + + [JsonConverter(typeof(JsonStringEnumConverter))] + public IconAnchorUnits AnchorXUnits { get; set; } = IconAnchorUnits.Fraction; + + [JsonConverter(typeof(JsonStringEnumConverter))] + public IconAnchorUnits AnchorYUnits { get; set; } = IconAnchorUnits.Fraction; + + public string Color { get; set; } + + public string CrossOrigin { get; set; } + + // public object Img { get; set; } // You can specify the type based on the actual image object types you plan to use + public double[]? Displacement { get; set; } + public double Opacity { get; set; } = 1; + public double? Width { get; set; } + public double? Height { get; set; } + public double Scale { get; set; } = 1; + public bool RotateWithView { get; set; } = false; + public double Rotation { get; set; } = 0; + public List Offset { get; set; } = new List { 0, 0 }; + + [JsonConverter(typeof(JsonStringEnumConverter))] + public IconOrigin OffsetOrigin { get; set; } = IconOrigin.TopLeft; + + public string Size { get; set; } + public string Source { get; set; } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public DeclutterMode? DeclutterMode { get; set; } + } + + public enum IconOrigin + { + BottomLeft, + BottomRight, + TopLeft, + TopRight + } + + public enum IconAnchorUnits + { + Fraction, + Pixels + } + + /// + /// https://openlayers.org/en/latest/apidoc/module-ol_style_RegularShape-RegularShape.html + /// + public class RegularShapeStyleOptions : ImageStyleOptions + { + public int Points { get; set; } = 3; // Default to a triangle + public double? Radius { get; set; } + public double? Radius1 { get; set; } + public double? Radius2 { get; set; } + public double? Angle { get; set; } + public double[] Displacement { get; set; } + public StrokeOptions? Stroke { get; set; } + public double? Rotation { get; set; } = 0; + public bool? RotateWithView { get; set; } = false; + public double? Scale { get; set; } = 1; + public DeclutterMode? DeclutterMode { get; set; } + } + + /// + /// https://openlayers.org/en/latest/apidoc/module-ol_style_Circle-CircleStyle.html + /// + public class CircleStyleOptions : RegularShapeStyleOptions + { + public FillOptions? Fill { get; set; } + public double Radius { get; set; } + public StrokeOptions? Stroke { get; set; } + public double[]? Displacement { get; set; } + public double? Scale { get; set; } = 1; + public double? Rotation { get; set; } = 0; + public bool? RotateWithView { get; set; } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public DeclutterMode? DeclutterMode { get; set; } + } + } +} \ No newline at end of file diff --git a/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js b/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js index 302074b..4e43ba8 100644 --- a/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js +++ b/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js @@ -20,8 +20,8 @@ export function MapOLSetDefaults(mapId, defaults) { _MapOL[mapId].setDefaults(defaults); } -export function MapOLLoadGeoJson(mapId, json, dataProjection) { - _MapOL[mapId].loadGeoJson(json, dataProjection); +export function MapOLLoadGeoJson(mapId, json, dataProjection, raiseEvents) { + _MapOL[mapId].loadGeoJson(json, dataProjection, raiseEvents); } export function MapOLZoomToExtent(mapId, extent) { @@ -213,25 +213,7 @@ MapOL.prepareLayers = function (layers) { layers.forEach((l, i, arr) => { let source; - if (l.extent == null) l.extent = undefined; - if (l.className == null) l.className = undefined; - if (l.minResolution == null) l.minResolution = undefined; - if (l.maxResolution == null) l.maxResolution = undefined; - if (l.maxZoom == null) l.maxZoom = undefined; - if (l.minZoom == null) l.minZoom = undefined; - if (l.zIndex == null) l.zIndex = undefined; - if (l.source.url == null) l.source.url = undefined; - if (l.source.urls == null) l.source.urls = undefined; - if (l.source.cacheSize == null) l.source.cacheSize = undefined; - if (l.source.crossOrigin == null) l.source.crossOrigin = undefined; - if (l.source.transition == null) l.source.transition = undefined; - if (l.source.layer == null) l.source.layer = undefined; - if (l.source.key == null) l.source.key = undefined; - if (l.source.serverType == null) l.source.serverType = undefined; - if (l.source.matrixSet == null) l.source.matrixSet = undefined; - if (l.source.format == null) l.source.format = undefined; - if (l.source.projection == null) l.source.projection = undefined; - if (l.source.reprojectionErrorThreshold == null) l.source.reprojectionErrorThreshold = undefined; + l = MapOL.transformNullToUndefined(l); switch (l.source.sourceType) { case 'TileImage': @@ -353,17 +335,21 @@ MapOL.prototype.setShapes = function (shapes) { }); } -MapOL.prototype.loadGeoJson = function (json, dataProjection) { +MapOL.prototype.loadGeoJson = function (json, dataProjection, raiseEvents) { + var that = this; + if (this.GeoLayer) { var source = this.GeoLayer.getSource(); - source.clear(); } if (!json) return; + var features = (new ol.format.GeoJSON()).readFeatures(json, + { featureProjection: this.Defaults.coordinatesProjection, dataProjection: dataProjection }); + var geoSource = new ol.source.Vector({ - features: (new ol.format.GeoJSON()).readFeatures(json, { featureProjection: this.Defaults.coordinatesProjection, dataProjection: dataProjection }) + features: features }); if (this.GeoLayer) { @@ -377,6 +363,8 @@ MapOL.prototype.loadGeoJson = function (json, dataProjection) { this.Map.addLayer(this.GeoLayer); } + + if (raiseEvents) features.forEach((f, i, arr) => { that.onFeatureAdded(f) }); } MapOL.prototype.setZoom = function (zoom) { @@ -613,17 +601,14 @@ MapOL.prototype.mapFeatureToShape = function (feature) { if (geometry != null && !Array.isArray(geometry)) { switch (geometry.getType()) { - case 'Point': - coordinates = ol.proj.transform(geometry.getCoordinates(), viewProjection, this.Defaults.coordinatesProjection); - break; case 'Circle': coordinates = ol.proj.transform(geometry.getCenter(), viewProjection, this.Defaults.coordinatesProjection); break; - case 'Polygon': - coordinates = ol.proj.transform(geometry.getCoordinates(), viewProjection, this.Defaults.coordinatesProjection); - break; default: - coordinates = ol.proj.transform(geometry.getCoordinates(), viewProjection, this.Defaults.coordinatesProjection); + var g = geometry.getCoordinates(); + var l = g.length; + if (Array.isArray(g[0])) g.forEach((g2) => l = l + g2.length); + if (l < 200) coordinates = ol.proj.transform(geometry.getCoordinates(), viewProjection, this.Defaults.coordinatesProjection); break; } } @@ -754,7 +739,7 @@ MapOL.prototype.getDefaultStyle = function (shape) { var coordinates = ol.proj.transform(shape.coordinates ?? this.Map.getView().getCenter(), this.Defaults.coordinatesProjection, viewProjection); var radius = 5; if (shape.radius != null) { - radius = shape.radius + radius = shape.radius; } if (coordinates.length > 0) { radius = radius / ol.proj.getPointResolution(viewProjection, 1, coordinates); @@ -767,10 +752,10 @@ MapOL.prototype.getDefaultStyle = function (shape) { }), stroke: new ol.style.Stroke({ color: shape.borderColor, - width: shape.borderSize, - }), + width: shape.borderSize + }) }), - zIndex: Infinity, + zIndex: Infinity }); } else { @@ -968,67 +953,30 @@ MapOL.prototype.customImageStyle = function (marker) { MapOL.prototype.getGeoStyle = function (feature) { var that = this; - var geoStyles = { - 'Point': that.awesomeStyle(feature), - 'LineString': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'green', - width: 1 - }) - }), - 'MultiLineString': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'green', - width: 1 - }) - }), - 'MultiPolygon': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'yellow', - width: 1 - }), - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 0, 0.3)' - }) - }), - 'Polygon': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'blue', - lineDash: [4], - width: 3 - }), - fill: new ol.style.Fill({ - color: 'rgba(0, 0, 255, 0.3)' - }) - }), - 'GeometryCollection': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'magenta', - width: 2 - }), - fill: new ol.style.Fill({ - color: 'magenta' - }), - image: new ol.style.Circle({ - radius: 10, - fill: null, - stroke: new ol.style.Stroke({ - color: 'magenta' - }) - }) - }), - 'Circle': new ol.style.Style({ - stroke: new ol.style.Stroke({ - color: 'red', - width: 2 - }), - fill: new ol.style.Fill({ - color: 'rgba(255,0,0,0.3)' - }) - }) - }; + var shape = this.mapFeatureToShape(feature); + var style = this.Instance.invokeMethod('OnGetShapeStyle', shape); + + var styleObject = new ol.style.Style({ + stroke: style.stroke != null ? new ol.style.Stroke(MapOL.transformNullToUndefined(style.stroke)) : undefined, + fill: style.fill != null ? new ol.style.Fill(MapOL.transformNullToUndefined(style.fill)): undefined, + text: style.text != null ? new ol.style.Text(MapOL.transformNullToUndefined(style.text)): undefined, + image: style.circle != null ? new ol.style.Circle(MapOL.transformNullToUndefined(style.circle)) : + style.icon != null ? new ol.style.Icon(MapOL.transformNullToUndefined(style.icon)) : undefined + }); - return geoStyles[feature.getGeometry().getType()]; + return styleObject; +} + + +MapOL.transformNullToUndefined = function transformNullToUndefined(obj) { + for (const key in obj) { + if (obj.hasOwnProperty(key) && obj[key] === null) { + obj[key] = undefined; + } else if (typeof obj[key] === 'object') { + transformNullToUndefined(obj[key]); + } + } + return obj; } /* From 2fea37d2d556c3d277cae525b4834f91e6a38ee9 Mon Sep 17 00:00:00 2001 From: lolochristen Date: Mon, 23 Oct 2023 19:05:37 +0200 Subject: [PATCH 2/9] Replace template with new shape callback --- .../Pages/DrawDemo.razor | 30 ++++++---- src/OpenLayers.Blazor/Map.razor.cs | 28 ++++----- src/OpenLayers.Blazor/Shape.cs | 30 ---------- src/OpenLayers.Blazor/ShapeType.cs | 12 ++++ .../wwwroot/openlayers_interop.js | 57 +++++++++++++------ 5 files changed, 84 insertions(+), 73 deletions(-) create mode 100644 src/OpenLayers.Blazor/ShapeType.cs diff --git a/src/OpenLayers.Blazor.Demo.Components/Pages/DrawDemo.razor b/src/OpenLayers.Blazor.Demo.Components/Pages/DrawDemo.razor index 47d162c..2418ff7 100644 --- a/src/OpenLayers.Blazor.Demo.Components/Pages/DrawDemo.razor +++ b/src/OpenLayers.Blazor.Demo.Components/Pages/DrawDemo.razor @@ -23,9 +23,9 @@ - - - + + + @@ -34,7 +34,7 @@ - + [Parameter] - public Shape NewShapeTemplate { get; set; } + public ShapeType NewShapeType { get; set; } /// /// Get or set if new shapes shall be drawn @@ -257,17 +256,15 @@ public override Task SetParametersAsync(ParameterView parameters) else shapeSnap = EnableShapeSnap; - if (parameters.TryGetValue(nameof(NewShapeTemplate), out Shape shapeTemplate) && shapeTemplate != null && - !shapeTemplate.InternalFeature.Equals(NewShapeTemplate?.InternalFeature)) + if (parameters.TryGetValue(nameof(NewShapeType), out ShapeType shapeType) && shapeType != NewShapeType) { drawingChanges++; - shapeTemplate.ParentMap = this; // to link the template with parent } else - shapeTemplate = NewShapeTemplate; + shapeType = NewShapeType; if (drawingChanges > 0) - _ = SetDrawingSettings(newShapes, editShapes, shapeSnap, shapeTemplate); + _ = SetDrawingSettings(newShapes, editShapes, shapeSnap, shapeType); return base.SetParametersAsync(parameters); } @@ -540,17 +537,20 @@ public StyleOptions OnGetShapeStyle(Internal.Shape shape) [Parameter] public Func ShapeStyleCallback { get; set; } = DefaultShapeStyleCallback; - public Task SetDrawingSettings() - { - return SetDrawingSettings(EnableNewShapes, EnableEditShapes, EnableShapeSnap, NewShapeTemplate); - } - - public async Task SetDrawingSettings(bool newShapes, bool editShapes, bool shapeSnap, Shape shapeTemplate) + /// + /// Sets explicitly drawing settings + /// + /// + /// + /// + /// + /// + public async Task SetDrawingSettings(bool newShapes, bool editShapes, bool shapeSnap, ShapeType shapeType) { try { if (_module != null) - await _module.InvokeVoidAsync("MapOLSetDrawingSettings", _mapId, newShapes, editShapes, shapeSnap, shapeTemplate?.InternalFeature); + await _module.InvokeVoidAsync("MapOLSetDrawingSettings", _mapId, newShapes, editShapes, shapeSnap, shapeType); } catch (Exception exp) { diff --git a/src/OpenLayers.Blazor/Shape.cs b/src/OpenLayers.Blazor/Shape.cs index 278363f..3117378 100644 --- a/src/OpenLayers.Blazor/Shape.cs +++ b/src/OpenLayers.Blazor/Shape.cs @@ -3,14 +3,6 @@ namespace OpenLayers.Blazor; -public enum ShapeType -{ - Point, - LineString, - Polygon, - Circle -} - public abstract class Shape : Shape where T : Internal.Shape, new() { internal Shape(T shape) : base(shape) @@ -180,28 +172,6 @@ protected override void OnInitialized() ParentMap?.ShapesList.Add(this); } - private bool _drawSettingsChanged; - - public override Task SetParametersAsync(ParameterView parameters) - { - _drawSettingsChanged = false; - if (parameters.TryGetValue(nameof(BackgroundColor), out string? bgColor) && bgColor != BackgroundColor) _drawSettingsChanged = true; - if (parameters.TryGetValue(nameof(Color), out string? color) && color != Color) _drawSettingsChanged = true; - if (parameters.TryGetValue(nameof(BorderColor), out string? bcolor) && bcolor != BorderColor) _drawSettingsChanged = true; - if (parameters.TryGetValue(nameof(BorderSize), out int? size) && size != BorderSize) _drawSettingsChanged = true; - if (parameters.TryGetValue(nameof(ShapeType), out ShapeType shapeType) && shapeType != ShapeType) _drawSettingsChanged = true; - - return base.SetParametersAsync(parameters); - } - - protected override async Task OnParametersSetAsync() - { - if (ParentMap != null && ReferenceEquals(ParentMap.NewShapeTemplate, this) && _drawSettingsChanged) - await ParentMap.SetDrawingSettings(); - - await base.OnParametersSetAsync(); - } - public async Task UpdateShape() { if (ParentMap != null) diff --git a/src/OpenLayers.Blazor/ShapeType.cs b/src/OpenLayers.Blazor/ShapeType.cs new file mode 100644 index 0000000..134f683 --- /dev/null +++ b/src/OpenLayers.Blazor/ShapeType.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace OpenLayers.Blazor; + +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum ShapeType +{ + Point, + LineString, + Polygon, + Circle +} \ No newline at end of file diff --git a/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js b/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js index 4e43ba8..6367219 100644 --- a/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js +++ b/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js @@ -64,8 +64,8 @@ export function MapOLSetVisibleExtent(mapId, extent) { _MapOL[mapId].setVisibleExtent(extent); } -export function MapOLSetDrawingSettings(mapId, enableNewShapes, enableEditShapes, enableShapeSnap, newShapeTemplate) { - _MapOL[mapId].setDrawingSettings(enableNewShapes, enableEditShapes, enableShapeSnap, newShapeTemplate); +export function MapOLSetDrawingSettings(mapId, enableNewShapes, enableEditShapes, enableShapeSnap, geometryType) { + _MapOL[mapId].setDrawingSettings(enableNewShapes, enableEditShapes, enableShapeSnap, geometryType); } export function MapOLUndoDrawing(mapId) { @@ -358,7 +358,7 @@ MapOL.prototype.loadGeoJson = function (json, dataProjection, raiseEvents) { else { this.GeoLayer = new ol.layer.Vector({ source: geoSource, - style: (feature) => this.getGeoStyle(feature) + style: (feature) => this.getShapeStyle(feature) }); this.Map.addLayer(this.GeoLayer); @@ -533,8 +533,8 @@ MapOL.prototype.setVisibleExtent = function (extent) { MapOL.prototype.currentDraw = null; MapOL.prototype.currentSnap = null; MapOL.prototype.currentModify = null; -MapOL.prototype.setDrawingSettings = function (enableNewShapes, enableEditShapes, enableShapeSnap, newShapeTemplate) { - +MapOL.prototype.setDrawingSettings = function (enableNewShapes, enableEditShapes, enableShapeSnap, geometryType) { + var that = this; this.removeDrawingInteractions(); var source = this.Geometries.getSource(); @@ -547,14 +547,14 @@ MapOL.prototype.setDrawingSettings = function (enableNewShapes, enableEditShapes } if (enableNewShapes) { - var style = this.getDefaultStyle(newShapeTemplate); - this.currentDraw = new ol.interaction.Draw({ source: source, - type: newShapeTemplate.geometryType, - //style: style + type: geometryType + }); + this.currentDraw.on("drawend", function(evt) { + var style = that.getShapeStyle(evt.feature); + evt.feature.setStyle(style); }); - this.currentDraw.on("drawend", function (evt) { evt.feature.setStyle(style); }); this.Map.addInteraction(this.currentDraw); } @@ -949,19 +949,42 @@ MapOL.prototype.customImageStyle = function (marker) { ]; } -// --- GeoStyles ------------------------------------------------------------------------// -MapOL.prototype.getGeoStyle = function (feature) { +// Shape Style +MapOL.prototype.getShapeStyle = function (feature) { var that = this; var shape = this.mapFeatureToShape(feature); var style = this.Instance.invokeMethod('OnGetShapeStyle', shape); + style = MapOL.transformNullToUndefined(style); + + if (feature.getGeometry().getType() == 'Point') { + if (style.circle == undefined) { + style.circle = { + radius: 5, + fill: style.fill, + stroke: style.stroke + } + } + } + + if (style.circle) { + if (style.circle.fill) style.circle.fill = new ol.style.Fill(style.circle.fill); + if (style.circle.stroke) style.circle.stroke = new ol.style.Stroke(style.circle.stroke); + } + + if (style.text) { + if (style.text.fill) style.text.fill = new ol.style.Fill(style.text.fill); + if (style.text.stroke) style.text.stroke = new ol.style.Stroke(style.text.stroke); + if (style.text.backgroundFill) style.text.backgroundFill = new ol.style.Fill(style.text.backgroundFill); + if (style.text.backgroundStroke) style.text.backgroundStroke = new ol.style.Stroke(style.text.backgroundStroke); + } var styleObject = new ol.style.Style({ - stroke: style.stroke != null ? new ol.style.Stroke(MapOL.transformNullToUndefined(style.stroke)) : undefined, - fill: style.fill != null ? new ol.style.Fill(MapOL.transformNullToUndefined(style.fill)): undefined, - text: style.text != null ? new ol.style.Text(MapOL.transformNullToUndefined(style.text)): undefined, - image: style.circle != null ? new ol.style.Circle(MapOL.transformNullToUndefined(style.circle)) : - style.icon != null ? new ol.style.Icon(MapOL.transformNullToUndefined(style.icon)) : undefined + stroke: style.stroke ? new ol.style.Stroke(style.stroke) : undefined, + fill: style.fill ? new ol.style.Fill(style.fill): undefined, + text: style.text ? new ol.style.Text(style.text): undefined, + image: style.circle ? new ol.style.Circle(style.circle) : + style.icon ? new ol.style.Icon(style.icon) : undefined }); return styleObject; From 29f9b1b6354fed21ccc55442f1b27ab15283c31e Mon Sep 17 00:00:00 2001 From: lolochristen Date: Mon, 23 Oct 2023 21:03:03 +0200 Subject: [PATCH 3/9] Serialization Limit added --- src/OpenLayers.Blazor/Defaults.cs | 2 ++ src/OpenLayers.Blazor/wwwroot/openlayers_interop.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/OpenLayers.Blazor/Defaults.cs b/src/OpenLayers.Blazor/Defaults.cs index 9082421..8198595 100644 --- a/src/OpenLayers.Blazor/Defaults.cs +++ b/src/OpenLayers.Blazor/Defaults.cs @@ -18,4 +18,6 @@ public class Defaults [JsonConverter(typeof(JsonStringEnumConverter))] public ScaleLineUnit ScaleLineUnit { get; set; } = ScaleLineUnit.Metric; + + public int SerializationCoordinatesLimit { get; set; } = 255; } \ No newline at end of file diff --git a/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js b/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js index 6367219..67f4d1d 100644 --- a/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js +++ b/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js @@ -608,7 +608,7 @@ MapOL.prototype.mapFeatureToShape = function (feature) { var g = geometry.getCoordinates(); var l = g.length; if (Array.isArray(g[0])) g.forEach((g2) => l = l + g2.length); - if (l < 200) coordinates = ol.proj.transform(geometry.getCoordinates(), viewProjection, this.Defaults.coordinatesProjection); + if (l < this.Defaults.serializationCoordinatesLimit) coordinates = ol.proj.transform(geometry.getCoordinates(), viewProjection, this.Defaults.coordinatesProjection); break; } } From 4cb93dcf8bcabd9b6a0d2e6fec803ed2147cdc8d Mon Sep 17 00:00:00 2001 From: lolochristen Date: Mon, 23 Oct 2023 21:18:05 +0200 Subject: [PATCH 4/9] some clean up --- .../Pages/CustomWMTSMap.razor | 1 - .../Pages/DrawDemo.razor | 5 ----- .../Pages/GeoJsonDemo.razor | 17 +++++++++++++---- .../Pages/LayersDemo.razor | 6 +----- .../Pages/MarkersDemo.razor | 6 +----- .../Pages/OpenStreetMapDemo.razor | 2 -- .../Pages/ShapesDemo.razor | 6 ++---- .../Pages/SwissMapLayersDemo.razor | 4 ---- 8 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/OpenLayers.Blazor.Demo.Components/Pages/CustomWMTSMap.razor b/src/OpenLayers.Blazor.Demo.Components/Pages/CustomWMTSMap.razor index 27c6080..ddc6ec8 100644 --- a/src/OpenLayers.Blazor.Demo.Components/Pages/CustomWMTSMap.razor +++ b/src/OpenLayers.Blazor.Demo.Components/Pages/CustomWMTSMap.razor @@ -1,7 +1,6 @@ @page "/customdemo"
-

Custom WMTS Map

diff --git a/src/OpenLayers.Blazor.Demo.Components/Pages/DrawDemo.razor b/src/OpenLayers.Blazor.Demo.Components/Pages/DrawDemo.razor index 2418ff7..450e2bb 100644 --- a/src/OpenLayers.Blazor.Demo.Components/Pages/DrawDemo.razor +++ b/src/OpenLayers.Blazor.Demo.Components/Pages/DrawDemo.razor @@ -1,13 +1,10 @@ @page "/drawdemo"
-

Drawing Demo

-
-
/// GeoJson Data /// Data projection of GeoJson - /// Raise events for new created features + /// Raise events for new created features and add it to list of shapes public ValueTask LoadGeoJson(JsonElement json, string? dataProjection = null, bool? raiseEvents = true) { return _module?.InvokeVoidAsync("MapOLLoadGeoJson", _mapId, json, dataProjection, raiseEvents) ?? ValueTask.CompletedTask; diff --git a/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js b/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js index 6c4b19e..c36f034 100644 --- a/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js +++ b/src/OpenLayers.Blazor/wwwroot/openlayers_interop.js @@ -677,35 +677,34 @@ MapOL.prototype.mapShapeToFeature = function(shape) { var geometry; const viewProjection = this.Map.getView().getProjection().getCode(); - var coordinates; - if (shape.coordinates) - coordinates = ol.proj.transform(shape.coordinates, this.Defaults.coordinatesProjection, viewProjection); + if (shape.coordinates) { + var coordinates = ol.proj.transform(shape.coordinates, this.Defaults.coordinatesProjection, viewProjection); - switch (shape.geometryType) { - case "Point": - geometry = new ol.geom.Point(coordinates); - break; - case "LineString": - geometry = new ol.geom.LineString(coordinates); - break; - case "Polygon": - geometry = new ol.geom.Polygon(coordinates); - break; - case "Circle": - geometry = new ol.geom.Circle(coordinates, - shape.radius / ol.proj.getPointResolution(viewProjection, 1, coordinates)); - break; - case "MultiPoint": - geometry = new ol.geom.MultiPoint(coordinates); - break; - case "MultiLineString": - geometry = new ol.geom.MultiLineString(coordinates); - break; - case "MultiPolygon": - geometry = new ol.geom.MultiPolygon(coordinates); - break; + switch (shape.geometryType) { + case "Point": + geometry = new ol.geom.Point(coordinates); + break; + case "LineString": + geometry = new ol.geom.LineString(coordinates); + break; + case "Polygon": + geometry = new ol.geom.Polygon(coordinates); + break; + case "Circle": + geometry = new ol.geom.Circle(coordinates, + shape.radius / ol.proj.getPointResolution(viewProjection, 1, coordinates)); + break; + case "MultiPoint": + geometry = new ol.geom.MultiPoint(coordinates); + break; + case "MultiLineString": + geometry = new ol.geom.MultiLineString(coordinates); + break; + case "MultiPolygon": + geometry = new ol.geom.MultiPolygon(coordinates); + break; + } } - const feature = new ol.Feature({ type: shape.properties.type, popup: shape.properties.popup, @@ -809,12 +808,15 @@ MapOL.prototype.onFeatureChanged = function(feature) { }; MapOL.prototype.updateShape = function(shape) { - const source = this.Geometries.getSource(); - const feature = source.getFeatureById(shape.id); + + var feature = this.Geometries.getSource().getFeatureById(shape.id); + if (!feature && this.GeoLayer) feature = this.GeoLayer.getSource().getFeatureById(shape.id); if (feature) { const newFeature = this.mapShapeToFeature(shape); - feature.setGeometry(newFeature.getGeometry()); + const geometry = newFeature.getGeometry(); + if (geometry) + feature.setGeometry(geometry); feature.setStyle(newFeature.getStyle()); } }; From 465253b628a60431f7066865198aab3a4dfef71e Mon Sep 17 00:00:00 2001 From: lolochristen Date: Tue, 24 Oct 2023 21:35:13 +0200 Subject: [PATCH 8/9] Fixed WMS param hanlding Added German GDZ Demo --- OpenLayers.Blazor.sln | 2 +- .../OpenLayers.Blazor.Demo.Components.csproj | 1 + .../Pages/GermanGdzDemo.razor | 17 +++++++++++++++ .../Pages/OpenStreetMapDemo.razor | 2 +- .../Shared/NavMenu.razor | 6 ++++++ src/OpenLayers.Blazor/Layer.cs | 21 +++++++++++-------- 6 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor diff --git a/OpenLayers.Blazor.sln b/OpenLayers.Blazor.sln index 5b6d6d2..e42060e 100644 --- a/OpenLayers.Blazor.sln +++ b/OpenLayers.Blazor.sln @@ -13,7 +13,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenLayers.Blazor.Demo.Maui EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenLayers.Blazor.Tests", "test\OpenLayers.Blazor.Tests\OpenLayers.Blazor.Tests.csproj", "{D235BF12-E194-49CA-AB16-27E23D87B9C5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenLayers.Blazor.Demo.Components", "src\OpenLayers.Blazor.Demo.Components\OpenLayers.Blazor.Demo.Components.csproj", "{9BEEE062-7A06-4391-9934-B3963D62B50D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenLayers.Blazor.Demo.Components", "src\OpenLayers.Blazor.Demo.Components\OpenLayers.Blazor.Demo.Components.csproj", "{9BEEE062-7A06-4391-9934-B3963D62B50D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/OpenLayers.Blazor.Demo.Components/OpenLayers.Blazor.Demo.Components.csproj b/src/OpenLayers.Blazor.Demo.Components/OpenLayers.Blazor.Demo.Components.csproj index 740300e..2563e0c 100644 --- a/src/OpenLayers.Blazor.Demo.Components/OpenLayers.Blazor.Demo.Components.csproj +++ b/src/OpenLayers.Blazor.Demo.Components/OpenLayers.Blazor.Demo.Components.csproj @@ -20,6 +20,7 @@ + diff --git a/src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor b/src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor new file mode 100644 index 0000000..4361cd2 --- /dev/null +++ b/src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor @@ -0,0 +1,17 @@ +@page "/gdzdemo" + +
+
+

German GDZ Demo

+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/src/OpenLayers.Blazor.Demo.Components/Pages/OpenStreetMapDemo.razor b/src/OpenLayers.Blazor.Demo.Components/Pages/OpenStreetMapDemo.razor index e26bb41..b41158c 100644 --- a/src/OpenLayers.Blazor.Demo.Components/Pages/OpenStreetMapDemo.razor +++ b/src/OpenLayers.Blazor.Demo.Components/Pages/OpenStreetMapDemo.razor @@ -15,7 +15,7 @@ Zoom: @_map?.Zoom - + + + diff --git a/src/OpenLayers.Blazor/Layer.cs b/src/OpenLayers.Blazor/Layer.cs index 15da511..527ddca 100644 --- a/src/OpenLayers.Blazor/Layer.cs +++ b/src/OpenLayers.Blazor/Layer.cs @@ -175,11 +175,7 @@ public string? MatrixSet public string? Format { get => _internalLayer.Source.Format; - set - { - _internalLayer.Source.Format = value; - _internalLayer.Source.Params["format"] = value; - } + set => _internalLayer.Source.Format = value; } [Parameter] @@ -199,15 +195,22 @@ public string? ServerType [Parameter] public string? Layers { - get => _internalLayer.Source.Params.ContainsKey("layers") ? _internalLayer.Source.Params["layers"].ToString() : null; - set => _internalLayer.Source.Params["layers"] = value; + get => _internalLayer.Source.Params.ContainsKey("LAYERS") ? _internalLayer.Source.Params["LAYERS"].ToString() : null; + set => _internalLayer.Source.Params["LAYERS"] = value; + } + + [Parameter] + public string? Styles + { + get => _internalLayer.Source.Params.ContainsKey("STYLES") ? _internalLayer.Source.Params["STYLES"].ToString() : null; + set => _internalLayer.Source.Params["STYLES"] = value; } [Parameter] public string? Title { - get => _internalLayer.Properties.ContainsKey("title") ? _internalLayer.Properties["title"].ToString() : null; - set => _internalLayer.Properties["title"] = value; + get => _internalLayer.Properties.ContainsKey("TITLE") ? _internalLayer.Properties["TITLE"].ToString() : null; + set => _internalLayer.Properties["TITLE"] = value; } protected override void OnInitialized() From e6eeae43182b212d8c257887a615fdbb0d1b6dce Mon Sep 17 00:00:00 2001 From: lolochristen Date: Tue, 24 Oct 2023 21:35:55 +0200 Subject: [PATCH 9/9] simplified --- src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor b/src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor index 4361cd2..089e750 100644 --- a/src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor +++ b/src/OpenLayers.Blazor.Demo.Components/Pages/GermanGdzDemo.razor @@ -10,7 +10,7 @@ - +