From 17bbd8946c93b636c37f9ca6539eef1c895f4b56 Mon Sep 17 00:00:00 2001
From: Tim Purdum
Date: Thu, 11 Dec 2025 22:01:10 -0600
Subject: [PATCH 1/7] updates
---
.../Scripts/geoblazorProto.ts | 431 +++
.../Serialization/JsSyncManager.cs | 519 ++-
.../ProtobufSerializationRecords.cs | 2846 +++++++++++++++++
src/dymaptic.GeoBlazor.Core/copyProtobuf.ps1 | 14 +
4 files changed, 3756 insertions(+), 54 deletions(-)
create mode 100644 src/dymaptic.GeoBlazor.Core/Scripts/geoblazorProto.ts
create mode 100644 src/dymaptic.GeoBlazor.Core/Serialization/ProtobufSerializationRecords.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/copyProtobuf.ps1
diff --git a/src/dymaptic.GeoBlazor.Core/Scripts/geoblazorProto.ts b/src/dymaptic.GeoBlazor.Core/Scripts/geoblazorProto.ts
new file mode 100644
index 000000000..c708ff541
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Scripts/geoblazorProto.ts
@@ -0,0 +1,431 @@
+export let protoTypeDefinitions: string = `
+syntax = "proto3";
+package dymaptic.GeoBlazor.Core.Serialization;
+import "google/protobuf/empty.proto";
+
+message ActionBase {
+ string type = 1;
+ string title = 2;
+ string className = 3;
+ bool active = 4;
+ bool disabled = 5;
+ bool visible = 6;
+ string id = 7;
+ string image = 8;
+ bool value = 9;
+ string actionId = 10;
+ string test = 11;
+ bool isNull = 1000;
+}
+message ActionBaseCollection {
+ repeated ActionBase items = 1;
+ bool isNull = 1000;
+}
+message Attribute {
+ string key = 1;
+ string value = 2;
+ string valueType = 3;
+ bool isNull = 1000;
+}
+message AttributeCollection {
+ repeated Attribute items = 1;
+ bool isNull = 1000;
+}
+message ChartMediaInfoValueSeries {
+ string fieldName = 1;
+ string tooltip = 2;
+ double value = 3;
+ string id = 4;
+ bool isNull = 1000;
+}
+message ChartMediaInfoValueSeriesCollection {
+ repeated ChartMediaInfoValueSeries items = 1;
+ bool isNull = 1000;
+}
+message ElementExpressionInfo {
+ string expression = 1;
+ string title = 2;
+ bool isNull = 1000;
+}
+message ElementExpressionInfoCollection {
+ repeated ElementExpressionInfo items = 1;
+ bool isNull = 1000;
+}
+message FieldInfo {
+ string fieldName = 1;
+ string label = 2;
+ string tooltip = 3;
+ string stringFieldOption = 4;
+ FieldInfoFormat format = 5;
+ bool isEditable = 6;
+ bool visible = 7;
+ string id = 8;
+ bool isNull = 1000;
+}
+message FieldInfoCollection {
+ repeated FieldInfo items = 1;
+ bool isNull = 1000;
+}
+message FieldInfoFormat {
+ int32 places = 1;
+ bool digitSeparator = 2;
+ string dateFormat = 3;
+ string id = 4;
+ bool isNull = 1000;
+}
+message FieldInfoFormatCollection {
+ repeated FieldInfoFormat items = 1;
+ bool isNull = 1000;
+}
+message Geometry {
+ string type = 1;
+ Geometry extent = 2;
+ SpatialReference spatialReference = 3;
+ double longitude = 4;
+ double latitude = 5;
+ double x = 6;
+ double y = 7;
+ double z = 8;
+ repeated MapPath paths = 9;
+ repeated MapPath rings = 10;
+ double xmax = 11;
+ double xmin = 12;
+ double ymax = 13;
+ double ymin = 14;
+ double zmax = 15;
+ double zmin = 16;
+ double mmax = 17;
+ double mmin = 18;
+ bool hasM = 19;
+ bool hasZ = 20;
+ double m = 21;
+ Geometry centroid = 22;
+ bool isSelfIntersecting = 23;
+ Geometry center = 24;
+ bool geodesic = 25;
+ int32 numberOfPoints = 26;
+ double radius = 27;
+ string radiusUnit = 28;
+ string id = 29;
+ repeated MapPoint points = 30;
+ bool isSimple = 31;
+ repeated MeshComponent components = 32;
+ MeshTransform transform = 33;
+ MeshVertexAttributes vertexAttributes = 34;
+ MeshVertexSpace vertexSpace = 35;
+ bool isNull = 1000;
+}
+message GeometryCollection {
+ repeated Geometry items = 1;
+ bool isNull = 1000;
+}
+message Graphic {
+ string id = 1;
+ Geometry geometry = 2;
+ Symbol symbol = 3;
+ PopupTemplate popupTemplate = 4;
+ repeated Attribute attributes = 5;
+ bool visible = 6;
+ string aggregateGeometries = 7;
+ GraphicOrigin origin = 8;
+ string layerId = 9;
+ string viewId = 10;
+ repeated Attribute stackedAttributes = 11;
+ bool isNull = 1000;
+}
+message GraphicCollection {
+ repeated Graphic items = 1;
+ bool isNull = 1000;
+}
+message GraphicOrigin {
+ string layerId = 1;
+ string arcGISLayerId = 2;
+ int32 layerIndex = 3;
+ bool isNull = 1000;
+}
+message GraphicOriginCollection {
+ repeated GraphicOrigin items = 1;
+ bool isNull = 1000;
+}
+message ImageData {
+ bytes data = 1;
+ string colorSpace = 2;
+ int64 height = 3;
+ int64 width = 4;
+ bool isNull = 1000;
+}
+message ImageDataCollection {
+ bool isNull = 1000;
+}
+message MapColor {
+ repeated double rgbaValues = 1;
+ string hexOrNameValue = 2;
+ bool isNull = 1000;
+}
+message MapColorCollection {
+ bool isNull = 1000;
+}
+message MapFont {
+ double size = 1;
+ string family = 2;
+ string fontStyle = 3;
+ string weight = 4;
+ string decoration = 5;
+ string id = 6;
+ bool isNull = 1000;
+}
+message MapFontCollection {
+ repeated MapFont items = 1;
+ bool isNull = 1000;
+}
+message MapPath {
+ repeated MapPoint points = 1;
+ bool isNull = 1000;
+}
+message MapPathCollection {
+ repeated MapPath items = 1;
+ bool isNull = 1000;
+}
+message MapPoint {
+ repeated double coordinates = 1;
+ bool isNull = 1000;
+}
+message MapPointCollection {
+ repeated MapPoint items = 1;
+ bool isNull = 1000;
+}
+message MediaInfo {
+ string type = 1;
+ string altText = 2;
+ string caption = 3;
+ string title = 4;
+ MediaInfoValue value = 5;
+ double refreshInterval = 6;
+ string id = 7;
+ bool isNull = 1000;
+}
+message MediaInfoCollection {
+ repeated MediaInfo items = 1;
+ bool isNull = 1000;
+}
+message MediaInfoValue {
+ repeated string fields = 1;
+ string normalizeField = 2;
+ string tooltipField = 3;
+ repeated ChartMediaInfoValueSeries series = 4;
+ string linkURL = 5;
+ string sourceURL = 6;
+ string id = 7;
+ bool isNull = 1000;
+}
+message MediaInfoValueCollection {
+ repeated MediaInfoValue items = 1;
+ bool isNull = 1000;
+}
+message MeshComponent {
+ bytes faces = 1;
+ MeshComponentMaterial material = 2;
+ string name = 3;
+ string shading = 4;
+ bool isNull = 1000;
+}
+message MeshComponentCollection {
+ repeated MeshComponent items = 1;
+ bool isNull = 1000;
+}
+message MeshComponentMaterial {
+ double alphaCutoff = 1;
+ string alphaMode = 2;
+ MapColor color = 3;
+ MeshTexture colorTexture = 4;
+ MeshTextureTransform colorTextureTransform = 5;
+ bool doubleSided = 6;
+ MeshTexture normalTexture = 7;
+ MeshTextureTransform normalTextureTransform = 8;
+ MapColor emissiveColor = 9;
+ MeshTexture emissiveTexture = 10;
+ MeshTextureTransform emissiveTextureTransform = 11;
+ double metallic = 12;
+ MeshTexture metallicRoughnessTexture = 13;
+ MeshTexture occlusionTexture = 14;
+ MeshTextureTransform occlusionTextureTransform = 15;
+ double roughness = 16;
+ bool isNull = 1000;
+}
+message MeshComponentMaterialCollection {
+ repeated MeshComponentMaterial items = 1;
+ bool isNull = 1000;
+}
+message MeshTexture {
+ ImageData imageData = 1;
+ repeated string wrap = 2;
+ bool transparent = 3;
+ string url = 4;
+ bool isNull = 1000;
+}
+message MeshTextureCollection {
+ repeated MeshTexture items = 1;
+ bool isNull = 1000;
+}
+message MeshTextureTransform {
+ repeated double offset = 1;
+ double rotation = 2;
+ repeated double scale = 3;
+ bool isNull = 1000;
+}
+message MeshTextureTransformCollection {
+ repeated MeshTextureTransform items = 1;
+ bool isNull = 1000;
+}
+message MeshTransform {
+ double rotationAngle = 1;
+ repeated double rotationAxis = 2;
+ repeated double scale = 3;
+ repeated double translation = 4;
+ bool isNull = 1000;
+}
+message MeshTransformCollection {
+ repeated MeshTransform items = 1;
+ bool isNull = 1000;
+}
+message MeshVertexAttributes {
+ bytes color = 1;
+ repeated double normal = 2;
+ repeated double position = 3;
+ repeated double tangent = 4;
+ repeated double uv = 5;
+ bool isNull = 1000;
+}
+message MeshVertexAttributesCollection {
+ repeated MeshVertexAttributes items = 1;
+ bool isNull = 1000;
+}
+message MeshVertexSpace {
+ string type = 1;
+ repeated double origin = 2;
+ bool isNull = 1000;
+}
+message MeshVertexSpaceCollection {
+ repeated MeshVertexSpace items = 1;
+ bool isNull = 1000;
+}
+message PopupContent {
+ string type = 1;
+ string description = 2;
+ string displayType = 3;
+ string title = 4;
+ ElementExpressionInfo expressionInfo = 5;
+ repeated FieldInfo fieldInfos = 6;
+ int32 activeMediaInfoIndex = 7;
+ repeated MediaInfo mediaInfos = 8;
+ int32 displayCount = 9;
+ repeated RelatedRecordsInfoFieldOrder orderByFields = 10;
+ int64 relationshipId = 11;
+ string text = 12;
+ string id = 13;
+ repeated string outFields = 14;
+ bool isNull = 1000;
+}
+message PopupContentCollection {
+ repeated PopupContent items = 1;
+ bool isNull = 1000;
+}
+message PopupExpressionInfo {
+ string expression = 1;
+ string name = 2;
+ string title = 3;
+ string returnType = 4;
+ string id = 5;
+ bool isNull = 1000;
+}
+message PopupExpressionInfoCollection {
+ repeated PopupExpressionInfo items = 1;
+ bool isNull = 1000;
+}
+message PopupTemplate {
+ string title = 1;
+ string stringContent = 2;
+ repeated string outFields = 3;
+ repeated FieldInfo fieldInfos = 4;
+ repeated PopupContent content = 5;
+ repeated PopupExpressionInfo expressionInfos = 6;
+ bool overwriteActions = 7;
+ bool returnGeometry = 8;
+ repeated ActionBase actions = 9;
+ string id = 10;
+ bool isNull = 1000;
+}
+message PopupTemplateCollection {
+ repeated PopupTemplate items = 1;
+ bool isNull = 1000;
+}
+message RelatedRecordsInfoFieldOrder {
+ bool isNull = 1000;
+}
+message RelatedRecordsInfoFieldOrderCollection {
+ repeated RelatedRecordsInfoFieldOrder items = 1;
+ bool isNull = 1000;
+}
+message SpatialReference {
+ int32 wkid = 1;
+ string wkt = 2;
+ string wkt2 = 3;
+ bool isNull = 1000;
+}
+message SpatialReferenceCollection {
+ repeated SpatialReference items = 1;
+ bool isNull = 1000;
+}
+message Symbol {
+ string type = 1;
+ MapColor color = 2;
+ Symbol outline = 3;
+ double size = 4;
+ string style = 5;
+ double angle = 6;
+ double xoffset = 7;
+ double yoffset = 8;
+ double width = 9;
+ string lineStyle = 10;
+ string text = 11;
+ MapColor haloColor = 12;
+ double haloSize = 13;
+ MapFont font = 14;
+ double height = 15;
+ string url = 16;
+ MapColor backgroundColor = 17;
+ double borderLineSize = 18;
+ MapColor borderLineColor = 19;
+ string horizontalAlignment = 20;
+ bool kerning = 21;
+ double lineHeight = 22;
+ double lineWidth = 23;
+ bool rotated = 24;
+ string verticalAlignment = 25;
+ double xScale = 26;
+ double yScale = 27;
+ string id = 28;
+ string name = 29;
+ string portalUrl = 30;
+ string styleName = 31;
+ string styleUrl = 32;
+ bool isNull = 1000;
+}
+message SymbolCollection {
+ repeated Symbol items = 1;
+ bool isNull = 1000;
+}
+message ViewHit {
+ string type = 1;
+ Geometry mapPoint = 2;
+ Graphic graphic = 3;
+ string layerId = 4;
+ double distance = 5;
+ bool isNull = 1000;
+}
+message ViewHitCollection {
+ repeated ViewHit items = 1;
+ bool isNull = 1000;
+}
+
+`;
diff --git a/src/dymaptic.GeoBlazor.Core/Serialization/JsSyncManager.cs b/src/dymaptic.GeoBlazor.Core/Serialization/JsSyncManager.cs
index b7856f288..27ca00d0e 100644
--- a/src/dymaptic.GeoBlazor.Core/Serialization/JsSyncManager.cs
+++ b/src/dymaptic.GeoBlazor.Core/Serialization/JsSyncManager.cs
@@ -1,46 +1,19 @@
-using Microsoft.JSInterop;
using ProtoBuf.Meta;
using System.Runtime.CompilerServices;
+
namespace dymaptic.GeoBlazor.Core.Serialization;
-///
-/// Manages JavaScript interop with support for Protobuf serialization and streaming.
-///
-///
-/// This is the infrastructure class for the Protobuf serialization system.
-/// The full implementation with serialization records will be added in a subsequent PR.
-///
public static class JsSyncManager
{
- ///
- /// Dictionary of serializable methods keyed by class name.
- ///
public static Dictionary SerializableMethods { get; set; } = [];
- ///
- /// Dictionary mapping source types to their Protobuf contract types.
- ///
public static Dictionary ProtoContractTypes { get; set; } = [];
- ///
- /// Dictionary mapping collection item types to their Protobuf collection types.
- ///
public static Dictionary ProtoCollectionTypes { get; set; } = [];
- private static Dictionary>? _serializableMethods;
-
- ///
- /// Initializes the JsSyncManager with Protobuf type registrations.
- ///
- ///
- /// This method should be called once at application startup to register all
- /// protobuf types with the RuntimeTypeModel and compile the serialization model.
- ///
public static void Initialize()
{
- // TODO: ProtoContractTypes and SerializableMethods dictionaries will be populated
- // by generated code from ProtobufSourceGenerator in a subsequent PR.
foreach (Type protoType in ProtoContractTypes.Values)
{
RuntimeTypeModel.Default.Add(protoType, true);
@@ -53,43 +26,481 @@ public static void Initialize()
}
///
- /// Wrapper method to invoke a void JS function with serialization support.
+ /// Wrapper method to invoke a void JS function.
///
- /// The IJSObjectReference to invoke the method on.
- /// Boolean flag to identify if GeoBlazor is running in Blazor Server mode.
- /// The name of the JS function to call.
- /// The name of the calling class.
- /// A CancellationToken to cancel an asynchronous operation.
- /// The collection of parameters to pass to the JS call.
+ ///
+ /// The to invoke the method on.
+ ///
+ ///
+ /// Boolean flag to identify if GeoBlazor is running in Blazor Server mode
+ ///
+ ///
+ /// The name of the JS function to call.
+ ///
+ ///
+ /// The name of the calling class.
+ ///
+ ///
+ /// A CancellationToken to cancel an asynchronous operation.
+ ///
+ ///
+ /// The collection of parameters to pass to the JS call.
+ ///
public static async Task InvokeVoidJsMethod(this IJSObjectReference js, bool isServer,
- [CallerMemberName] string method = "", string className = "",
+ [CallerMemberName]string method = "", string className = "",
CancellationToken cancellationToken = default, params object?[] parameters)
{
- // TODO: Implement protobuf serialization for Blazor Server mode.
- // When isServer is true and the method/parameters support protobuf serialization,
- // this should serialize parameters to binary format for more efficient transfer.
- await js.InvokeVoidAsync(method, cancellationToken, parameters);
+ SerializableMethodRecord methodRecord = GetMethodRecord(method, className, true, parameters);
+ List parameterList = GenerateSerializedParameters(methodRecord, parameters, isServer);
+
+ await js.InvokeVoidAsync("invokeVoidSerializedMethod", cancellationToken,
+ [methodRecord.MethodName, isServer, ..parameterList]);
}
///
- /// Wrapper method to invoke a JS function that returns a value with serialization support.
+ /// Wrapper method to invoke a JS function that returns a value.
///
- /// The expected return type.
- /// The IJSObjectReference to invoke the method on.
- /// Boolean flag to identify if GeoBlazor is running in Blazor Server mode.
- /// The name of the JS function to call.
- /// The name of the calling class.
- /// A CancellationToken to cancel an asynchronous operation.
- /// The collection of parameters to pass to the JS call.
- /// The result of the JS call.
+ ///
+ /// The to invoke the method on.
+ ///
+ ///
+ /// Boolean flag to identify if GeoBlazor is running in Blazor Server mode
+ ///
+ ///
+ /// The name of the JS function to call.
+ ///
+ ///
+ /// The name of the calling class.
+ ///
+ ///
+ /// A CancellationToken to cancel an asynchronous operation.
+ ///
+ ///
+ /// The collection of parameters to pass to the JS call.
+ ///
public static async Task InvokeJsMethod(this IJSObjectReference js, bool isServer,
- [CallerMemberName] string method = "", string className = "",
+ [CallerMemberName]string method = "", string className = "",
CancellationToken cancellationToken = default,
params object?[] parameters)
{
- // TODO: Implement protobuf deserialization for Blazor Server mode.
- // When isServer is true and the return type supports protobuf serialization,
- // this should deserialize the binary response for more efficient transfer.
- return await js.InvokeAsync(method, cancellationToken, parameters);
+ SerializableMethodRecord methodRecord = GetMethodRecord(method, className, false, parameters);
+
+ List parameterList = GenerateSerializedParameters(methodRecord, parameters, isServer);
+
+ Type? returnType = methodRecord.ReturnValue?.Type;
+ bool returnTypeIsProtobuf = returnType is not null && ProtoContractTypes.ContainsKey(returnType);
+
+ if (isServer || returnTypeIsProtobuf || returnType?.IsAssignableTo(typeof(Stream)) == true)
+ {
+ string? protoReturnTypeName = null;
+ if (returnTypeIsProtobuf)
+ {
+ Type? protoReturnType;
+ if (methodRecord.ReturnValue!.SingleType is not null)
+ {
+ ProtoCollectionTypes.TryGetValue(methodRecord.ReturnValue.SingleType,
+ out protoReturnType);
+ }
+ else
+ {
+ ProtoContractTypes.TryGetValue(returnType!, out protoReturnType);
+ }
+
+ protoReturnTypeName = protoReturnType?.Name.Replace("SerializationRecord", "");
+ }
+
+ IJSStreamReference? streamRef = await js.InvokeAsync(
+ "invokeSerializedMethod", cancellationToken,
+ [methodRecord.MethodName, true, returnTypeIsProtobuf, protoReturnTypeName, ..parameterList]);
+
+ if (streamRef is null)
+ {
+ return default!;
+ }
+
+ if (returnTypeIsProtobuf)
+ {
+ if (methodRecord.ReturnValue?.SingleType is not null)
+ {
+ return await streamRef.ReadJsStreamReferenceAsProtobufCollection(methodRecord.ReturnValue.SingleType) ?? default!;
+ }
+ return await streamRef.ReadJsStreamReferenceAsProtobuf(returnType!) ?? default!;
+ }
+
+ if (returnType?.IsAssignableTo(typeof(Stream)) == true)
+ {
+ Stream? result = await streamRef.ReadJsStreamReferenceAsStream();
+
+ if (result is null)
+ {
+ return default!;
+ }
+
+ // double-cast to force to generic
+ return (T)(object)result;
+ }
+
+ return (await streamRef.ReadJsStreamReferenceAsJSON())!;
+ }
+
+ return await js.InvokeAsync(
+ "invokeSerializedMethod", cancellationToken, [methodRecord.MethodName, false, false, null, ..parameterList]);
}
+
+ private static SerializableMethodRecord GetMethodRecord(string method, string className, bool returnsVoid,
+ object?[] providedParameters)
+ {
+ if (!_serializableMethods.TryGetValue(className, out List? classMethods))
+ {
+ classMethods = new List();
+ _serializableMethods[className] = classMethods;
+ }
+
+ if (classMethods.Where(m =>
+ // same method name
+ string.Equals(m.MethodName, method, StringComparison.OrdinalIgnoreCase)
+ // same number of parameters
+ && m.Parameters.Length == providedParameters.Length
+ // either both void or both non-void
+ && ((m.ReturnValue is null && returnsVoid)
+ || (m.ReturnValue is not null && !returnsVoid))).ToList()
+ is not { } matchedMethods)
+ {
+ // use reflection since we don't have a stored method record
+ var classType = GeoBlazorMetaData.GeoblazorTypes.First(t => t.Name == className);
+ var methodInfos = classType.GetMethods(BindingFlags.Instance | BindingFlags.Public)
+ .Where(m => string.Equals(m.Name, method, StringComparison.OrdinalIgnoreCase)
+ && m.GetParameters().Length == providedParameters.Length)
+ .ToArray();
+
+ matchedMethods = [];
+
+ foreach (MethodInfo methodInfo in methodInfos)
+ {
+ List methodParams = [];
+ var paramInfos = methodInfo.GetParameters();
+
+ foreach (ParameterInfo paramInfo in paramInfos)
+ {
+ NullabilityInfo nullabilityInfo = nullabilityContext.Create(paramInfo);
+ bool isNullable = nullabilityInfo.ReadState == NullabilityState.Nullable;
+ Type paramType = paramInfo.ParameterType.IsGenericType &&
+ paramInfo.ParameterType.GetGenericTypeDefinition() == typeof(Nullable<>)
+ ? Nullable.GetUnderlyingType(paramInfo.ParameterType)!
+ : paramInfo.ParameterType;
+ Type? collectionType = paramType.IsArray
+ ? paramType.GetElementType()
+ : paramType is { IsGenericType: true, GenericTypeArguments.Length: 1 }
+ ? paramType.GenericTypeArguments[0]
+ : null;
+ methodParams.Add(new SerializableParameterRecord(paramType, isNullable, collectionType));
+ }
+
+ SerializableParameterRecord? returnRecord = null;
+
+ if (!returnsVoid && methodInfo.ReturnType != typeof(void))
+ {
+ ParameterInfo returnParamInfo = methodInfo.ReturnParameter;
+ Type returnType = returnParamInfo.ParameterType;
+
+ if (returnType.Name.StartsWith("Task") || returnType.Name.StartsWith("ValueTask"))
+ {
+ returnType = returnType.IsGenericType
+ ? returnType.GenericTypeArguments[0]
+ : typeof(void);
+ }
+
+ bool isNullable = false;
+
+ if (returnType.IsGenericType &&
+ methodInfo.ReturnType.GetGenericTypeDefinition() == typeof(Nullable<>))
+ {
+ isNullable = true;
+ returnType = Nullable.GetUnderlyingType(returnType)!;
+ }
+
+ bool returnIsCollection = returnType.IsArray ||
+ returnType is { IsGenericType: true, GenericTypeArguments.Length: 1 };
+
+ Type? singleType = null;
+
+ if (returnIsCollection)
+ {
+ singleType = returnType.IsArray
+ ? returnType.GetElementType()
+ : returnType.GenericTypeArguments[0];
+ }
+
+ bool isGenericParameter = returnType.IsGenericParameter;
+
+ if (isGenericParameter)
+ {
+ returnType = returnType.GenericTypeArguments[0];
+ }
+
+ returnRecord = new SerializableParameterRecord(returnType, isNullable, singleType);
+ }
+
+ SerializableMethodRecord methodRecord = new(method.ToLowerFirstChar(), methodParams.ToArray(), returnRecord);
+ matchedMethods.Add(methodRecord);
+
+ if (methodRecord.ReturnValue?.Type.IsGenericType != true)
+ {
+ // only add non-generic return typed methods to the dictionary
+ classMethods.Add(methodRecord);
+ }
+ }
+ }
+
+ if (matchedMethods.Count == 0)
+ {
+ // no matching methods, build the record manually
+ return new SerializableMethodRecord(method.ToLowerFirstChar(),
+ providedParameters.Select(GetSerializableParameterRecord).ToArray(),
+ GetSerializableReturnRecord(returnsVoid));
+ }
+
+ if (matchedMethods.Count == 1)
+ {
+ return matchedMethods[0];
+ }
+
+ Type requestedReturnType = typeof(T);
+
+ // find record with potentially matching parameter types including nulls
+ return matchedMethods.First(m =>
+ {
+ for (int i = 0; i < m.Parameters.Length; i++)
+ {
+ Type? providedParameterType = providedParameters[i]?.GetType();
+ if (providedParameterType is not null &&
+ providedParameterType.IsGenericType &&
+ providedParameterType.GetGenericTypeDefinition() == typeof(Nullable<>))
+ {
+ providedParameterType = Nullable.GetUnderlyingType(providedParameterType)!;
+ }
+
+ SerializableParameterRecord methodParam = m.Parameters[i];
+
+ if (providedParameterType is null)
+ {
+ if (!methodParam.IsNullable)
+ {
+ return false;
+ }
+ }
+ else if (!providedParameterType.IsAssignableTo(methodParam.Type))
+ {
+ return false;
+ }
+ }
+
+ if (!returnsVoid && requestedReturnType != m.ReturnValue?.Type)
+ {
+ return false;
+ }
+
+ return true;
+ });
+ }
+
+ private static List GenerateSerializedParameters(SerializableMethodRecord methodRecord,
+ object?[] parameters, bool isServer)
+ {
+ List serializedParameters = [];
+ for (int i = 0; i < parameters.Length; i++)
+ {
+ object? parameterValue = parameters[i];
+ SerializableParameterRecord parameterRecord = methodRecord.Parameters[i];
+ serializedParameters.AddRange(ProcessParameter(parameterValue, parameterRecord, isServer));
+ }
+ return serializedParameters;
+ }
+
+ ///
+ /// Returns the processed parameter Type and a Serialized or DotNetStreamReference of the serialized parameter value.
+ ///
+ ///
+ /// The original parameter to process.
+ ///
+ ///
+ /// The SerializableParameterRecord for the parameter.
+ ///
+ ///
+ /// Boolean flag to identify if GeoBlazor is running in Blazor Server mode
+ ///
+ private static object?[] ProcessParameter(object? parameterValue, SerializableParameterRecord parameterRecord,
+ bool isServer)
+ {
+ if (parameterValue is null)
+ {
+ return ["null", null];
+ }
+
+ Type paramType = parameterRecord.Type;
+
+ if (simpleTypes.Contains(paramType) || paramType.IsPrimitive)
+ {
+ return [GetKey(paramType), parameterValue];
+ }
+
+ if (paramType.IsAssignableTo(typeof(IJSObjectReference)))
+ {
+ return ["JsObject", parameterValue];
+ }
+
+ if (paramType.IsEnum)
+ {
+ // use the JsonConverter defined EnumToKebabCaseConverters to serialize enums as strings
+ string stringValue = JsonSerializer.Serialize(parameterValue, GeoBlazorSerialization.JsonSerializerOptions);
+ // pass as type string so JS can parse correctly
+ return [nameof(String), stringValue];
+ }
+
+ if (paramType.IsGenericType && paramType.GetGenericTypeDefinition() == typeof(Nullable<>))
+ {
+ Type underlyingType = Nullable.GetUnderlyingType(paramType)!;
+ object underlyingValue = Convert.ChangeType(parameterValue, underlyingType);
+ return ProcessParameter(underlyingValue, parameterRecord with { Type = underlyingType, IsNullable = true }, isServer);
+ }
+
+ if (parameterValue is IList list && paramType != typeof(MapPath) && paramType != typeof(MapPoint))
+ {
+ Type genericType = parameterRecord.SingleType ?? (paramType.IsArray
+ ? paramType.GetElementType()!
+ : paramType.GenericTypeArguments[0]);
+ string key = $"{GetKey(genericType)}Collection";
+
+ if (ProtoContractTypes.ContainsKey(genericType))
+ {
+ object protobufParameter = list.ToProtobufCollectionParameter(genericType, isServer);
+ return [key, protobufParameter];
+ }
+
+ return [key, parameterValue.ToJsonParameter(isServer)];
+ }
+
+ if (ProtoContractTypes.ContainsKey(paramType))
+ {
+ object protobufParameter = parameterValue.ToProtobufParameter(paramType, isServer);
+ return [GetKey(paramType), protobufParameter];
+ }
+
+ if (parameterValue is AttributesDictionary attributesDictionary)
+ {
+ AttributeSerializationRecord[] serializedItems = attributesDictionary.ToProtobufArray();
+ AttributeCollectionSerializationRecord collection = new(serializedItems);
+ MemoryStream memoryStream = new();
+ Serializer.Serialize(memoryStream, collection);
+ memoryStream.Seek(0, SeekOrigin.Begin);
+
+ if (isServer)
+ {
+ return [nameof(AttributesDictionary), new DotNetStreamReference(memoryStream)];
+ }
+
+ byte[] data = memoryStream.ToArray();
+ memoryStream.Dispose();
+ return [nameof(AttributesDictionary), data];
+ }
+
+ return [GetKey(paramType), parameterValue.ToJsonParameter(isServer)];
+ }
+
+ private static object ToJsonParameter(this T obj, bool isServer)
+ {
+ if (isServer)
+ {
+ MemoryStream memoryStream = new();
+ JsonSerializer.Serialize(memoryStream, obj, GeoBlazorSerialization.JsonSerializerOptions);
+ memoryStream.Seek(0, SeekOrigin.Begin);
+ return new DotNetStreamReference(memoryStream);
+ }
+
+ return JsonSerializer.Serialize(obj, GeoBlazorSerialization.JsonSerializerOptions);
+ }
+
+ private static string GetKey(Type type)
+ {
+ Type? matchedType = ProtoContractTypes.Keys.FirstOrDefault(t => t == type);
+
+ if (matchedType is not null)
+ {
+ return ProtoContractTypes[type].GetCustomAttribute()!.Name;
+ }
+
+ return type.Name;
+ }
+
+ private static SerializableParameterRecord GetSerializableParameterRecord(object? parameter)
+ {
+ if (parameter is null)
+ {
+ return new SerializableParameterRecord(typeof(object), true, null);
+ }
+
+ Type paramType = parameter.GetType();
+
+ if (simpleTypes.Contains(paramType))
+ {
+ return new SerializableParameterRecord(paramType, true, null);
+ }
+
+ if (paramType.Name.Contains("AnonymousType"))
+ {
+ // anonymous object
+ return new SerializableParameterRecord(typeof(object), true, null);
+ }
+
+ bool isCollection = paramType.IsAssignableTo(typeof(IEnumerable));
+ Type? collectionType = isCollection
+ ? paramType.IsArray
+ ? paramType.GetElementType()
+ : paramType.GetGenericArguments()[0]
+ : null;
+ return new SerializableParameterRecord(paramType, true, collectionType);
+ }
+
+ private static SerializableParameterRecord GetSerializableReturnRecord(bool returnsVoid)
+ {
+ if (returnsVoid)
+ {
+ return new SerializableParameterRecord(typeof(void), false, null);
+ }
+ Type returnType = typeof(T);
+
+ if (simpleTypes.Contains(returnType))
+ {
+ return new SerializableParameterRecord(returnType, true, null);
+ }
+
+ if (returnType == typeof(AttributesDictionary))
+ {
+ return new SerializableParameterRecord(typeof(AttributesDictionary), true,
+ typeof(AttributeSerializationRecord));
+ }
+ bool isCollection = returnType.IsAssignableTo(typeof(IEnumerable))
+ && !returnType.IsAssignableTo(typeof(IDictionary));
+ Type? collectionType = isCollection
+ ? returnType.IsArray
+ ? returnType.GetElementType()
+ : returnType.GetGenericArguments()[0]
+ : null;
+ return new SerializableParameterRecord(returnType, true, collectionType);
+ }
+
+ private static Dictionary> _serializableMethods = [];
+ private static readonly NullabilityInfoContext nullabilityContext = new();
+
+ private static readonly Type[] simpleTypes =
+ [
+ typeof(string), typeof(char), typeof(bool), typeof(byte), typeof(sbyte), typeof(short),
+ typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float),
+ typeof(double), typeof(decimal), typeof(DateTime), typeof(DateTimeOffset), typeof(TimeSpan),
+ typeof(Guid), typeof(DateOnly), typeof(TimeOnly)
+ ];
}
+
+public record SerializableMethodRecord(string MethodName, SerializableParameterRecord[] Parameters,
+ SerializableParameterRecord? ReturnValue);
+public record SerializableParameterRecord(Type Type, bool IsNullable, Type? SingleType);
diff --git a/src/dymaptic.GeoBlazor.Core/Serialization/ProtobufSerializationRecords.cs b/src/dymaptic.GeoBlazor.Core/Serialization/ProtobufSerializationRecords.cs
new file mode 100644
index 000000000..aa1c502ae
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Serialization/ProtobufSerializationRecords.cs
@@ -0,0 +1,2846 @@
+using FieldInfo = dymaptic.GeoBlazor.Core.Components.FieldInfo;
+
+
+namespace dymaptic.GeoBlazor.Core.Serialization;
+
+///
+/// Base class for all Protobuf serialization records for MapComponents.
+///
+[ProtoContract(Name = "MapComponent")]
+public abstract record MapComponentSerializationRecord
+{
+ [ProtoMember(1000)]
+ public abstract bool IsNull { get; init; }
+}
+
+public abstract record MapComponentSerializationRecord : MapComponentSerializationRecord
+{
+ public abstract T? FromSerializationRecord();
+}
+
+[ProtoContract(Name = "MapComponentCollection")]
+public abstract record MapComponentBaseCollectionSerializationRecord
+{
+ [ProtoMember(1000)]
+ public abstract bool IsNull { get; init; }
+}
+
+public abstract record MapComponentCollectionSerializationRecord : MapComponentBaseCollectionSerializationRecord
+ where TItem : MapComponentSerializationRecord
+{
+ public abstract TItem[]? Items { get; set; }
+}
+
+[ProtoContract(Name = "Geometry")]
+public record GeometrySerializationRecord : MapComponentSerializationRecord
+{
+ public GeometrySerializationRecord()
+ {
+ }
+
+ public GeometrySerializationRecord(string Id, string Type, GeometrySerializationRecord? Extent,
+ SpatialReferenceSerializationRecord? SpatialReference)
+ {
+ this.Id = Id;
+ this.Type = Type;
+ this.Extent = Extent;
+ this.SpatialReference = SpatialReference;
+ }
+
+ [ProtoMember(1)]
+ public string Type { get; set; } = string.Empty;
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public GeometrySerializationRecord? Extent { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public SpatialReferenceSerializationRecord? SpatialReference { get; set; }
+
+ [ProtoMember(4)]
+ public double? Longitude { get; set; }
+
+ [ProtoMember(5)]
+ public double? Latitude { get; set; }
+
+ [ProtoMember(6)]
+ public double? X { get; set; }
+
+ [ProtoMember(7)]
+ public double? Y { get; set; }
+
+ [ProtoMember(8)]
+ public double? Z { get; set; }
+
+ [ProtoMember(9)]
+ public MapPathSerializationRecord[]? Paths { get; set; }
+
+ [ProtoMember(10)]
+ public MapPathSerializationRecord[]? Rings { get; set; }
+
+ [ProtoMember(11)]
+ public double? Xmax { get; set; }
+
+ [ProtoMember(12)]
+ public double? Xmin { get; set; }
+
+ [ProtoMember(13)]
+ public double? Ymax { get; set; }
+
+ [ProtoMember(14)]
+ public double? Ymin { get; set; }
+
+ [ProtoMember(15)]
+ public double? Zmax { get; set; }
+
+ [ProtoMember(16)]
+ public double? Zmin { get; set; }
+
+ [ProtoMember(17)]
+ public double? Mmax { get; set; }
+
+ [ProtoMember(18)]
+ public double? Mmin { get; set; }
+
+ [ProtoMember(19)]
+ public bool? HasM { get; set; }
+
+ [ProtoMember(20)]
+ public bool? HasZ { get; set; }
+
+ [ProtoMember(21)]
+ public double? M { get; set; }
+
+ [ProtoMember(22)]
+ public GeometrySerializationRecord? Centroid { get; set; }
+
+ [ProtoMember(23)]
+ public bool? IsSelfIntersecting { get; set; }
+
+ [ProtoMember(24)]
+ public GeometrySerializationRecord? Center { get; set; }
+
+ [ProtoMember(25)]
+ public bool? Geodesic { get; set; }
+
+ [ProtoMember(26)]
+ public int? NumberOfPoints { get; set; }
+
+ [ProtoMember(27)]
+ public double? Radius { get; set; }
+
+ [ProtoMember(28)]
+ public string? RadiusUnit { get; set; }
+
+ [ProtoMember(29)]
+ public string? Id { get; set; }
+
+ ///
+ /// Multipoint geometry points.
+ ///
+ [ProtoMember(30)]
+ public MapPointSerializationRecord[]? Points { get; set; }
+
+ [ProtoMember(31)]
+ public bool? IsSimple { get; set; }
+
+ [ProtoMember(32)]
+ public MeshComponentSerializationRecord[]? Components { get; set; }
+
+ [ProtoMember(33)]
+ public MeshTransformSerializationRecord? Transform { get; set; }
+
+ [ProtoMember(34)]
+ public MeshVertexAttributesSerializationRecord? VertexAttributes { get; set; }
+
+ [ProtoMember(35)]
+ public MeshVertexSpaceSerializationRecord? VertexSpace { get; set; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override Geometry? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var extent = Extent?.FromSerializationRecord() as Extent;
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guidId))
+ {
+ id = guidId;
+ }
+
+ switch (Type)
+ {
+ case "point":
+ return new Point(Longitude, Latitude, X, Y, Z, SpatialReference?.FromSerializationRecord(), HasM, HasZ,
+ M) { Extent = extent, Id = id };
+ case "polyline":
+ var paths = Paths?.Any(p => !p.IsNull) == true
+ ? Paths.Select(x => x.FromSerializationRecord()!).ToArray()
+ : null;
+
+ if (paths is null)
+ {
+ return null;
+ }
+
+ return new Polyline(paths,
+ SpatialReference?.FromSerializationRecord(), HasM, HasZ)
+ {
+ Extent = extent, Id = id, IsSimple = IsSimple
+ };
+ case "polygon":
+ var rings = Rings?.Any(p => !p.IsNull) == true
+ ? Rings.Select(x => x.FromSerializationRecord()!).ToArray()
+ : null;
+
+ if (rings is null)
+ {
+ return null;
+ }
+
+ return Center is not null && Radius is not null && !Center.IsNull
+ ? new Circle((Point)Center.FromSerializationRecord()!, Radius.Value,
+ Centroid?.FromSerializationRecord() as Point, Geodesic, HasM, HasZ, NumberOfPoints,
+ RadiusUnit is null ? null : Enum.Parse(RadiusUnit), rings,
+ SpatialReference?.FromSerializationRecord()) { Extent = extent, Id = id, IsSimple = IsSimple }
+ : new Polygon(rings,
+ SpatialReference?.FromSerializationRecord(), Centroid?.FromSerializationRecord() as Point, HasM,
+ HasZ) { Extent = extent, Id = id, IsSimple = IsSimple };
+ case "extent":
+ return new Extent(Xmax!.Value, Xmin!.Value, Ymax!.Value, Ymin!.Value, Zmax, Zmin, Mmax, Mmin,
+ SpatialReference?.FromSerializationRecord(), HasM, HasZ) { Id = id, IsSimple = IsSimple };
+ case "multipoint":
+ // Multipoint is in GeoBlazor Pro assembly, so we need to use reflection to get the type
+ var multipointType = System.Type.GetType("dymaptic.GeoBlazor.Pro.Components.Geometries.Multipoint, " +
+ "dymaptic.GeoBlazor.Pro");
+
+ if (multipointType is not null && multipointType.IsSubclassOf(typeof(Geometry)))
+ {
+ var points = Points?.Any(p => !p.IsNull) == true
+ ? Points?.Select(p =>
+ {
+ var mp = p.FromSerializationRecord()!;
+
+ return new Point(x: mp[0], y: mp[1]);
+ })
+ .ToArray()
+ : null;
+
+ if (Activator.CreateInstance(multipointType, HasM, HasZ, points,
+ SpatialReference?.FromSerializationRecord())
+ is Geometry multipoint)
+ {
+ multipoint.Extent = extent;
+ multipoint.Id = id;
+ multipoint.IsSimple = IsSimple;
+
+ return multipoint;
+ }
+ }
+
+ throw new InvalidOperationException(
+ "Multipoint could not be created. Ensure the type is correct and the assembly is loaded.");
+ case "mesh":
+ // Mesh is in GeoBlazor Pro assembly, so we need to use reflection to get the type
+ var meshType = System.Type.GetType("dymaptic.GeoBlazor.Pro.Components.Geometries.Mesh, " +
+ "dymaptic.GeoBlazor.Pro");
+
+ if (meshType is not null
+ && meshType.IsSubclassOf(typeof(Geometry))
+ && Activator.CreateInstance(meshType,
+ Components?.Select(c => c.FromSerializationRecord()).ToArray(),
+ HasM, HasZ,
+ SpatialReference?.FromSerializationRecord(),
+ Transform?.FromSerializationRecord(),
+ VertexAttributes?.FromSerializationRecord(),
+ VertexSpace?.FromSerializationRecord())
+ is Geometry mesh)
+ {
+ mesh.Extent = extent;
+ mesh.Id = id;
+ mesh.IsSimple = IsSimple;
+
+ return mesh;
+ }
+
+ throw new InvalidOperationException(
+ "Mesh could not be created. Ensure the type is correct and the assembly is loaded.");
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+}
+
+[ProtoContract(Name = "GeometryCollection")]
+internal record
+ GeometryCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public GeometryCollectionSerializationRecord()
+ {
+ }
+
+ public GeometryCollectionSerializationRecord(GeometrySerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override GeometrySerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "PopupContent")]
+public record PopupContentSerializationRecord : MapComponentSerializationRecord
+{
+ public PopupContentSerializationRecord()
+ {
+ }
+
+ public PopupContentSerializationRecord(string Id, string Type)
+ {
+ this.Type = Type;
+ this.Id = Id;
+ }
+
+ [ProtoMember(1)]
+ public string Type { get; init; } = string.Empty;
+
+ [ProtoMember(2)]
+ public string? Description { get; init; }
+
+ [ProtoMember(3)]
+ public string? DisplayType { get; init; }
+
+ [ProtoMember(4)]
+ public string? Title { get; init; }
+
+ [ProtoMember(5)]
+ public ElementExpressionInfoSerializationRecord? ExpressionInfo { get; init; }
+
+ [ProtoMember(6)]
+ public FieldInfoSerializationRecord[]? FieldInfos { get; init; }
+
+ [ProtoMember(7)]
+ public int? ActiveMediaInfoIndex { get; init; }
+
+ [ProtoMember(8)]
+ public MediaInfoSerializationRecord[]? MediaInfos { get; init; }
+
+ [ProtoMember(9)]
+ public int? DisplayCount { get; init; }
+
+ [ProtoMember(10)]
+ public RelatedRecordsInfoFieldOrderSerializationRecord[]? OrderByFields { get; init; }
+
+ [ProtoMember(11)]
+ public long? RelationshipId { get; init; }
+
+ [ProtoMember(12)]
+ public string? Text { get; init; }
+
+ [ProtoMember(13)]
+ public string? Id { get; set; }
+
+ [ProtoMember(14)]
+ public string[]? OutFields { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override PopupContent? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guidId))
+ {
+ id = guidId;
+ }
+
+ if (Type == "custom")
+ {
+ // CustomPopupContent is in GeoBlazor Pro assembly, so we need to use reflection to get the type
+ var customType =
+ System.Type.GetType(
+ "dymaptic.GeoBlazor.Pro.Components.Popups.CustomPopupContent, dymaptic.GeoBlazor.Pro");
+
+ if (customType is not null && customType.IsSubclassOf(typeof(PopupContent)))
+ {
+ var customContent = Activator.CreateInstance(customType, [null, OutFields]) as PopupContent;
+
+ if (customContent is null)
+ {
+ throw new InvalidOperationException(
+ "CustomPopupContent could not be created. Ensure the type is correct and the assembly is loaded.");
+ }
+
+ customContent.Id = id;
+
+ return customContent;
+ }
+ }
+
+ return Type switch
+ {
+ "fields" => new FieldsPopupContent(FieldInfos?.Any(i => !i.IsNull) == true
+ ? FieldInfos.Select(i => i.FromSerializationRecord()!).ToArray()
+ : [],
+ Description, Title) { Id = id },
+ "text" => new TextPopupContent(Text) { Id = id },
+ "attachments" => new AttachmentsPopupContent(Title, Description,
+ DisplayType is null ? null : Enum.Parse(DisplayType)) { Id = id },
+ "expression" => new ExpressionPopupContent(ExpressionInfo?.FromSerializationRecord()) { Id = id },
+ "media" => new MediaPopupContent(Title, Description, MediaInfos?.Any(i => !i.IsNull) == true
+ ? MediaInfos.Select(i => i.FromSerializationRecord()!).ToArray()
+ : null,
+ ActiveMediaInfoIndex) { Id = id },
+ "relationship" => new RelationshipPopupContent(Title, Description, DisplayCount,
+ DisplayType, OrderByFields?.Any(f => !f.IsNull) == true
+ ? OrderByFields.Select(x => x.FromSerializationRecord()!).ToList()
+ : null,
+ RelationshipId) { Id = id },
+ _ => throw new NotSupportedException($"PopupContent type {Type} is not supported")
+ };
+ }
+}
+
+[ProtoContract(Name = "PopupContentCollection")]
+internal record
+ PopupContentCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ PopupContentSerializationRecord>
+{
+ public PopupContentCollectionSerializationRecord()
+ {
+ }
+
+ public PopupContentCollectionSerializationRecord(PopupContentSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override PopupContentSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "PopupExpressionInfo")]
+public record PopupExpressionInfoSerializationRecord : MapComponentSerializationRecord
+{
+ public PopupExpressionInfoSerializationRecord()
+ {
+ }
+
+ public PopupExpressionInfoSerializationRecord(string Id, string? Expression, string? Name, string? Title,
+ PopupExpressionInfoReturnType? ReturnType)
+ {
+ this.Id = Id;
+ this.Expression = Expression;
+ this.Name = Name;
+ this.Title = Title;
+ this.ReturnType = ReturnType.ToString();
+ }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(1)]
+ public string? Expression { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public string? Name { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public string? Title { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(4)]
+ public string? ReturnType { get; init; }
+
+ [ProtoMember(5)]
+ public string? Id { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override PopupExpressionInfo? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guid))
+ {
+ id = guid;
+ }
+
+ return new PopupExpressionInfo(Expression, Name,
+ ReturnType is null ? null : Enum.Parse(ReturnType),
+ Title) { Id = id };
+ }
+}
+
+[ProtoContract(Name = "PopupExpressionInfoCollection")]
+internal record
+ PopupExpressionInfoCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ PopupExpressionInfoSerializationRecord>
+{
+ public PopupExpressionInfoCollectionSerializationRecord()
+ {
+ }
+
+ public PopupExpressionInfoCollectionSerializationRecord(PopupExpressionInfoSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override PopupExpressionInfoSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "PopupTemplate")]
+public record PopupTemplateSerializationRecord : MapComponentSerializationRecord
+{
+ public PopupTemplateSerializationRecord()
+ {
+ }
+
+ public PopupTemplateSerializationRecord(string? Title,
+ string? StringContent = null,
+ IEnumerable? OutFields = null,
+ IEnumerable? FieldInfos = null,
+ IEnumerable? Content = null,
+ IEnumerable? ExpressionInfos = null,
+ bool? OverwriteActions = null,
+ bool? ReturnGeometry = null,
+ IEnumerable? Actions = null,
+ string? Id = null)
+ {
+ this.Title = Title;
+ this.StringContent = StringContent;
+ this.OutFields = OutFields;
+ this.FieldInfos = FieldInfos;
+ this.Content = Content;
+ this.ExpressionInfos = ExpressionInfos;
+ this.OverwriteActions = OverwriteActions;
+ this.ReturnGeometry = ReturnGeometry;
+ this.Actions = Actions;
+ this.Id = Id;
+ }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(1)]
+ public string? Title { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public string? StringContent { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public IEnumerable? OutFields { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(4)]
+ public IEnumerable? FieldInfos { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(5)]
+ public IEnumerable? Content { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(6)]
+ public IEnumerable? ExpressionInfos { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(7)]
+ public bool? OverwriteActions { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(8)]
+ public bool? ReturnGeometry { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(9)]
+ public IEnumerable? Actions { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(10)]
+ public string? Id { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override PopupTemplate? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new PopupTemplate(Title, StringContent, OutFields?.ToList(),
+ FieldInfos?.Any(i => !i.IsNull) == true
+ ? FieldInfos.Select(f => f.FromSerializationRecord()!).ToList()
+ : null,
+ Content?.Any(c => !c.IsNull) == true
+ ? Content.Select(c => c.FromSerializationRecord()!).ToList()
+ : null,
+ ExpressionInfos?.Any(i => i.IsNull) == true
+ ? ExpressionInfos.Select(e => e.FromSerializationRecord()!).ToList()
+ : null,
+ OverwriteActions, ReturnGeometry,
+ Actions?.Any(a => !a.IsNull) == true
+ ? Actions?.Select(a => a.FromSerializationRecord()!).ToList()
+ : null);
+ }
+}
+
+[ProtoContract(Name = "PopupTemplateCollection")]
+internal record
+ PopupTemplateCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ PopupTemplateSerializationRecord>
+{
+ public PopupTemplateCollectionSerializationRecord()
+ {
+ }
+
+ public PopupTemplateCollectionSerializationRecord(PopupTemplateSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override PopupTemplateSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "Symbol")]
+public record SymbolSerializationRecord : MapComponentSerializationRecord
+{
+ public SymbolSerializationRecord()
+ {
+ }
+
+ public SymbolSerializationRecord(string Id,
+ string Type,
+ MapColorSerializationRecord? Color)
+ {
+ this.Id = Id;
+ this.Type = Type;
+ this.Color = Color;
+ }
+
+ [ProtoMember(1)]
+ public string Type { get; init; } = string.Empty;
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public MapColorSerializationRecord? Color { get; init; }
+
+ [ProtoMember(3)]
+ public SymbolSerializationRecord? Outline { get; init; }
+
+ [ProtoMember(4)]
+ public double? Size { get; init; }
+
+ [ProtoMember(5)]
+ public string? Style { get; init; }
+
+ [ProtoMember(6)]
+ public double? Angle { get; init; }
+
+ [ProtoMember(7)]
+ public double? Xoffset { get; init; }
+
+ [ProtoMember(8)]
+ public double? Yoffset { get; init; }
+
+ [ProtoMember(9)]
+ public double? Width { get; init; }
+
+ [ProtoMember(10)]
+ public string? LineStyle { get; init; }
+
+ [ProtoMember(11)]
+ public string? Text { get; init; }
+
+ [ProtoMember(12)]
+ public MapColorSerializationRecord? HaloColor { get; init; }
+
+ [ProtoMember(13)]
+ public double? HaloSize { get; init; }
+
+ [ProtoMember(14)]
+ public MapFontSerializationRecord? Font { get; init; }
+
+ [ProtoMember(15)]
+ public double? Height { get; init; }
+
+ [ProtoMember(16)]
+ public string? Url { get; init; }
+
+ [ProtoMember(17)]
+ public MapColorSerializationRecord? BackgroundColor { get; init; }
+
+ [ProtoMember(18)]
+ public double? BorderLineSize { get; init; }
+
+ [ProtoMember(19)]
+ public MapColorSerializationRecord? BorderLineColor { get; init; }
+
+ [ProtoMember(20)]
+ public string? HorizontalAlignment { get; init; }
+
+ [ProtoMember(21)]
+ public bool? Kerning { get; init; }
+
+ [ProtoMember(22)]
+ public double? LineHeight { get; init; }
+
+ [ProtoMember(23)]
+ public double? LineWidth { get; init; }
+
+ [ProtoMember(24)]
+ public bool? Rotated { get; init; }
+
+ [ProtoMember(25)]
+ public string? VerticalAlignment { get; init; }
+
+ [ProtoMember(26)]
+ public double? XScale { get; init; }
+
+ [ProtoMember(27)]
+ public double? YScale { get; init; }
+
+ [ProtoMember(28)]
+ public string? Id { get; init; }
+
+ [ProtoMember(29)]
+ public string? Name { get; init; }
+
+ [ProtoMember(30)]
+ public string? PortalUrl { get; init; }
+
+ [ProtoMember(31)]
+ public string? StyleName { get; init; }
+
+ [ProtoMember(32)]
+ public string? StyleUrl { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override Symbol? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return FromSerializationRecord();
+ }
+
+ public Symbol FromSerializationRecord(bool isOutline = false)
+ {
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guidId))
+ {
+ id = guidId;
+ }
+
+ if (Type == "web-style")
+ {
+ // WebStyleSymbol is in GeoBlazor Pro assembly, so we need to use reflection to get the type
+ var webStyleSymbolType = System.Type
+ .GetType("dymaptic.GeoBlazor.Pro.Components.Symbols.WebStyleSymbol, dymaptic.GeoBlazor.Pro");
+
+ if (webStyleSymbolType is not null)
+ {
+ var portal = PortalUrl is null ? null : new Portal(url: PortalUrl);
+
+ var webStyleSymbol = Activator.CreateInstance(webStyleSymbolType, Color?.FromSerializationRecord(),
+ Name, portal, StyleName, StyleUrl) as Symbol
+ ?? throw new InvalidOperationException("Failed to create WebStyleSymbol instance.");
+ webStyleSymbol.Id = id;
+
+ return webStyleSymbol;
+ }
+ }
+
+ return Type switch
+ {
+ "outline" => new Outline(Color?.FromSerializationRecord(), Width,
+ LineStyle is null ? null : Enum.Parse(LineStyle!, true)) { Id = id },
+ "simple-marker" => new SimpleMarkerSymbol(Outline?.FromSerializationRecord(true) as Outline,
+ Color?.FromSerializationRecord(), Size,
+ Style is null ? null : Enum.Parse(Style!, true),
+ Angle, Xoffset, Yoffset) { Id = id },
+ "simple-line" => isOutline
+ ? new Outline(Color?.FromSerializationRecord(), Width,
+ LineStyle is null ? null : Enum.Parse(LineStyle!, true)) { Id = id }
+ : new SimpleLineSymbol(Color?.FromSerializationRecord(), Width,
+ LineStyle is null ? null : Enum.Parse(LineStyle!, true)) { Id = id },
+ "simple-fill" => new SimpleFillSymbol(Outline?.FromSerializationRecord(true) as Outline,
+ Color?.FromSerializationRecord(),
+ Style is null ? null : Enum.Parse(Style!, true)) { Id = id },
+ "picture-marker" => new PictureMarkerSymbol(Url!, Width, Height, Angle, Xoffset, Yoffset) { Id = id },
+ "picture-fill" => new PictureFillSymbol(Url!, Width, Height, Xoffset, Yoffset, XScale, YScale,
+ Outline?.FromSerializationRecord(true) as Outline) { Id = id },
+ "text" => new TextSymbol(Text ?? string.Empty, Color?.FromSerializationRecord(),
+ HaloColor?.FromSerializationRecord(), HaloSize,
+ Font?.FromSerializationRecord(), Angle, BackgroundColor?.FromSerializationRecord(),
+ BorderLineColor?.FromSerializationRecord(),
+ BorderLineSize,
+ HorizontalAlignment is null ? null : Enum.Parse(HorizontalAlignment!, true),
+ Kerning, LineHeight, LineWidth, Rotated,
+ VerticalAlignment is null ? null : Enum.Parse(VerticalAlignment!, true),
+ Xoffset, Yoffset) { Id = id },
+ _ => throw new ArgumentException($"Unknown symbol type: {Type}")
+ };
+ }
+}
+
+[ProtoContract(Name = "SymbolCollection")]
+internal record
+ SymbolCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public SymbolCollectionSerializationRecord()
+ {
+ }
+
+ public SymbolCollectionSerializationRecord(SymbolSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override SymbolSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MapColor")]
+public record MapColorSerializationRecord : MapComponentSerializationRecord
+{
+ public MapColorSerializationRecord()
+ {
+ }
+
+ public MapColorSerializationRecord(double[]? rgbaValues, string? hexOrNameValue)
+ {
+ RgbaValues = rgbaValues;
+ HexOrNameValue = hexOrNameValue;
+ }
+
+ [ProtoMember(1)]
+ public double[]? RgbaValues { get; init; }
+
+ [ProtoMember(2)]
+ public string? HexOrNameValue { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MapColor? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ if (HexOrNameValue is not null)
+ {
+ return new MapColor(HexOrNameValue);
+ }
+
+ if (RgbaValues is not null)
+ {
+ return new MapColor(RgbaValues);
+ }
+
+ return new MapColor();
+ }
+}
+
+[ProtoContract(Name = "MapColorCollection")]
+public record MapColorCollectionSerializationRecord
+ : MapComponentCollectionSerializationRecord
+{
+ public MapColorCollectionSerializationRecord(MapColorSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ public sealed override MapColorSerializationRecord[]? Items { get; set; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "ActionBase")]
+public record ActionBaseSerializationRecord : MapComponentSerializationRecord
+{
+ public ActionBaseSerializationRecord()
+ {
+ }
+
+ public ActionBaseSerializationRecord(string Id,
+ string Type,
+ string? Title,
+ string? ClassName,
+ bool? Active,
+ bool? Disabled,
+ bool? Visible,
+ string? ActionId)
+ {
+ this.Id = Id;
+ this.Type = Type;
+ this.Title = Title;
+ this.ClassName = ClassName;
+ this.Active = Active;
+ this.Disabled = Disabled;
+ this.Visible = Visible;
+ this.ActionId = ActionId;
+ }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(1)]
+ public string Type { get; init; } = string.Empty;
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public string? Title { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public string? ClassName { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(4)]
+ public bool? Active { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(5)]
+ public bool? Disabled { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(6)]
+ public bool? Visible { get; init; }
+
+ [ProtoMember(7)]
+ public string? Id { get; init; }
+
+ [ProtoMember(8)]
+ public string? Image { get; init; }
+
+ [ProtoMember(9)]
+ public bool? Value { get; init; }
+
+ [ProtoMember(10)]
+ public string? ActionId { get; init; }
+
+ [ProtoMember(11)]
+ public string? Test { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override ActionBase? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guidId))
+ {
+ id = guidId;
+ }
+
+ return Type switch
+ {
+ "button" => new ActionButton(Title, Image, ActionId, null, ClassName, Active, Disabled, Visible)
+ {
+ Id = id
+ },
+ "toggle" => new ActionToggle(Title, ActionId, null, Value, Active, Disabled, Visible) { Id = id },
+ _ => throw new NotSupportedException()
+ };
+ }
+}
+
+[ProtoContract(Name = "ActionBaseCollection")]
+internal record
+ ActionBaseCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public ActionBaseCollectionSerializationRecord()
+ {
+ }
+
+ public ActionBaseCollectionSerializationRecord(ActionBaseSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override ActionBaseSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MediaInfoValue")]
+public record MediaInfoValueSerializationRecord : MapComponentSerializationRecord
+{
+ public MediaInfoValueSerializationRecord()
+ {
+ }
+
+ public MediaInfoValueSerializationRecord(string Id, IEnumerable? Fields = null,
+ string? NormalizeField = null, string? TooltipField = null,
+ IEnumerable? Series = null, string? LinkURL = null,
+ string? SourceURL = null)
+ {
+ this.Id = Id;
+ this.Fields = Fields;
+ this.NormalizeField = NormalizeField;
+ this.TooltipField = TooltipField;
+ this.Series = Series;
+ this.LinkURL = LinkURL;
+ this.SourceURL = SourceURL;
+ }
+
+ [ProtoMember(1)]
+ public IEnumerable? Fields { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public string? NormalizeField { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public string? TooltipField { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(4)]
+ public IEnumerable? Series { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(5)]
+ public string? LinkURL { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(6)]
+ public string? SourceURL { get; init; }
+
+ [ProtoMember(7)]
+ public string? Id { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override IMediaInfoValue? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guid))
+ {
+ id = guid;
+ }
+
+ if (LinkURL is not null || SourceURL is not null)
+ {
+ return new ImageMediaInfoValue(LinkURL, SourceURL) { Id = id };
+ }
+
+ return new ChartMediaInfoValue(Fields?.ToArray(), NormalizeField, TooltipField,
+ Series?.Any(s => !s.IsNull) == true
+ ? Series.Select(s => s.FromSerializationRecord()!).ToArray()
+ : null) { Id = id };
+ }
+}
+
+[ProtoContract(Name = "MediaInfoValueCollection")]
+internal record
+ MediaInfoValueCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ MediaInfoValueSerializationRecord>
+{
+ public MediaInfoValueCollectionSerializationRecord()
+ {
+ }
+
+ public MediaInfoValueCollectionSerializationRecord(MediaInfoValueSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MediaInfoValueSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "ChartMediaInfoValueSeries")]
+public record ChartMediaInfoValueSeriesSerializationRecord : MapComponentSerializationRecord
+{
+ public ChartMediaInfoValueSeriesSerializationRecord()
+ {
+ }
+
+ public ChartMediaInfoValueSeriesSerializationRecord(string Id, string? FieldName, string? Tooltip, double? Value)
+ {
+ this.Id = Id;
+ this.FieldName = FieldName;
+ this.Tooltip = Tooltip;
+ this.Value = Value;
+ }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(1)]
+ public string? FieldName { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public string? Tooltip { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public double? Value { get; init; }
+
+ [ProtoMember(4)]
+ public string? Id { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override ChartMediaInfoValueSeries? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guid))
+ {
+ id = guid;
+ }
+
+ return new ChartMediaInfoValueSeries(FieldName, Tooltip, Value) { Id = id };
+ }
+}
+
+[ProtoContract(Name = "ChartMediaInfoValueSeriesCollection")]
+internal record ChartMediaInfoValueSeriesCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ ChartMediaInfoValueSeriesSerializationRecord>
+{
+ public ChartMediaInfoValueSeriesCollectionSerializationRecord()
+ {
+ }
+
+ public ChartMediaInfoValueSeriesCollectionSerializationRecord(ChartMediaInfoValueSeriesSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override ChartMediaInfoValueSeriesSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "ElementExpressionInfo")]
+public record ElementExpressionInfoSerializationRecord : MapComponentSerializationRecord
+{
+ public ElementExpressionInfoSerializationRecord()
+ {
+ }
+
+ public ElementExpressionInfoSerializationRecord(string? expression, string? title)
+ {
+ Expression = expression;
+ Title = title;
+ }
+
+ [ProtoMember(1)]
+ public string? Expression { get; init; }
+
+ [ProtoMember(2)]
+ public string? Title { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override ElementExpressionInfo? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new ElementExpressionInfo(Expression, Title);
+ }
+}
+
+[ProtoContract(Name = "ElementExpressionInfoCollection")]
+internal record
+ ElementExpressionInfoCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ ElementExpressionInfoSerializationRecord>
+{
+ public ElementExpressionInfoCollectionSerializationRecord()
+ {
+ }
+
+ public ElementExpressionInfoCollectionSerializationRecord(ElementExpressionInfoSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override ElementExpressionInfoSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "FieldInfo")]
+public record FieldInfoSerializationRecord : MapComponentSerializationRecord
+{
+ public FieldInfoSerializationRecord()
+ {
+ }
+
+ public FieldInfoSerializationRecord(string Id, string? FieldName = null, string? Label = null,
+ string? Tooltip = null, string? StringFieldOption = null, FieldInfoFormatSerializationRecord? Format = null,
+ bool? IsEditable = null, bool? Visible = null)
+ {
+ this.Id = Id;
+ this.FieldName = FieldName;
+ this.Label = Label;
+ this.Tooltip = Tooltip;
+ this.StringFieldOption = StringFieldOption;
+ this.Format = Format;
+ this.IsEditable = IsEditable;
+ this.Visible = Visible;
+ }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(1)]
+ public string? FieldName { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public string? Label { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public string? Tooltip { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(4)]
+ public string? StringFieldOption { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(5)]
+ public FieldInfoFormatSerializationRecord? Format { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(6)]
+ public bool? IsEditable { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(7)]
+ public bool? Visible { get; init; }
+
+ [ProtoMember(8)]
+ public string? Id { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override FieldInfo? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guid))
+ {
+ id = guid;
+ }
+
+ StringFieldOption? sfo = StringFieldOption switch
+ {
+ "rich-text" => Enums.StringFieldOption.RichText,
+ "text-area" => Enums.StringFieldOption.TextArea,
+ "text-box" => Enums.StringFieldOption.TextBox,
+ _ => null
+ };
+
+ return new FieldInfo(FieldName, Label, Tooltip, sfo, Format?.FromSerializationRecord(), IsEditable, Visible)
+ {
+ Id = id
+ };
+ }
+}
+
+[ProtoContract(Name = "FieldInfoCollection")]
+internal record
+ FieldInfoCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public FieldInfoCollectionSerializationRecord()
+ {
+ }
+
+ public FieldInfoCollectionSerializationRecord(FieldInfoSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override FieldInfoSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "FieldInfoFormat")]
+public record FieldInfoFormatSerializationRecord : MapComponentSerializationRecord
+{
+ public FieldInfoFormatSerializationRecord()
+ {
+ }
+
+ public FieldInfoFormatSerializationRecord(string Id,
+ int? Places,
+ bool? DigitSeparator,
+ string? DateFormat)
+ {
+ this.Id = Id;
+ this.Places = Places;
+ this.DigitSeparator = DigitSeparator;
+ this.DateFormat = DateFormat;
+ }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(1)]
+ public int? Places { get; init; }
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public bool? DigitSeparator { get; init; }
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public string? DateFormat { get; init; }
+
+ [ProtoMember(4)]
+ public string? Id { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override FieldInfoFormat? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guidId))
+ {
+ id = guidId;
+ }
+
+ DateFormat? df = DateFormat switch
+ {
+ "short-date" => Enums.DateFormat.ShortDate,
+ "short-date-short-time.cs" => Enums.DateFormat.ShortDateShortTime,
+ "short-date-short-time-24" => Enums.DateFormat.ShortDateShortTime24,
+ "short-date-long-time" => Enums.DateFormat.ShortDateLongTime,
+ "short-date-long-time-24" => Enums.DateFormat.ShortDateLongTime24,
+ "short-date-le" => Enums.DateFormat.ShortDateLe,
+ "short-date-le-short-time" => Enums.DateFormat.ShortDateLeShortTime,
+ "short-date-le-short-time-24" => Enums.DateFormat.ShortDateLeShortTime24,
+ "short-date-le-long-time" => Enums.DateFormat.ShortDateLeLongTime,
+ "short-date-le-long-time-24" => Enums.DateFormat.ShortDateLeLongTime24,
+ "long-month-day-year" => Enums.DateFormat.LongMonthDayYear,
+ "long-month-day-year-short-time" => Enums.DateFormat.LongMonthDayYearShortTime,
+ "long-month-day-year-short-time-24" => Enums.DateFormat.LongMonthDayYearShortTime24,
+ "long-month-day-year-long-time" => Enums.DateFormat.LongMonthDayYearLongTime,
+ "long-month-day-year-long-time-24" => Enums.DateFormat.LongMonthDayYearLongTime24,
+ "day-short-month-year" => Enums.DateFormat.DayShortMonthYear,
+ "day-short-month-year-short-time" => Enums.DateFormat.DayShortMonthYearShortTime,
+ "day-short-month-year-short-time-24" => Enums.DateFormat.DayShortMonthYearShortTime24,
+ "day-short-month-year-long-time" => Enums.DateFormat.DayShortMonthYearLongTime,
+ "day-short-month-year-long-time-24" => Enums.DateFormat.DayShortMonthYearLongTime24,
+ "long-date" => Enums.DateFormat.LongDate,
+ "long-date-short-time" => Enums.DateFormat.LongDateShortTime,
+ "long-date-short-time-24" => Enums.DateFormat.LongDateShortTime24,
+ "long-date-long-time" => Enums.DateFormat.LongDateLongTime,
+ "long-date-long-time-24" => Enums.DateFormat.LongDateLongTime24,
+ "long-month-year" => Enums.DateFormat.LongMonthYear,
+ "short-month-year" => Enums.DateFormat.ShortMonthYear,
+ "year" => Enums.DateFormat.Year,
+ _ => null
+ };
+
+ return new FieldInfoFormat(Places, DigitSeparator, df) { Id = id };
+ }
+}
+
+[ProtoContract(Name = "FieldInfoFormatCollection")]
+internal record
+ FieldInfoFormatCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ FieldInfoFormatSerializationRecord>
+{
+ public FieldInfoFormatCollectionSerializationRecord()
+ {
+ }
+
+ public FieldInfoFormatCollectionSerializationRecord(FieldInfoFormatSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override FieldInfoFormatSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "Graphic")]
+public record GraphicSerializationRecord : MapComponentSerializationRecord
+{
+ public GraphicSerializationRecord()
+ {
+ }
+
+ public GraphicSerializationRecord(string Id, GeometrySerializationRecord? Geometry,
+ SymbolSerializationRecord? Symbol, PopupTemplateSerializationRecord? PopupTemplate,
+ AttributeSerializationRecord[]? Attributes, bool? Visible, string? AggregateGeometries,
+ GraphicOriginSerializationRecord? Origin, string? LayerId, string? ViewId)
+ {
+ this.Id = Id;
+ this.Geometry = Geometry;
+ this.Symbol = Symbol;
+ this.PopupTemplate = PopupTemplate;
+ this.Attributes = Attributes;
+ this.Visible = Visible;
+ this.AggregateGeometries = AggregateGeometries;
+ this.Origin = Origin;
+ this.LayerId = LayerId;
+ this.ViewId = ViewId;
+ }
+
+ [ProtoMember(1)]
+ public string? Id { get; set; } = string.Empty;
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public GeometrySerializationRecord? Geometry { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public SymbolSerializationRecord? Symbol { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(4)]
+ public PopupTemplateSerializationRecord? PopupTemplate { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(5)]
+ public AttributeSerializationRecord[]? Attributes { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(6)]
+ public bool? Visible { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(7)]
+ public string? AggregateGeometries { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(8)]
+ public GraphicOriginSerializationRecord? Origin { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(9)]
+ public string? LayerId { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(10)]
+ public string? ViewId { get; set; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(11)]
+ public AttributeSerializationRecord[]? StackedAttributes { get; set; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override Graphic? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ if (!Guid.TryParse(Id, out var graphicId))
+ {
+ graphicId = Guid.NewGuid();
+ }
+
+ Guid? layerId = null;
+
+ if (Guid.TryParse(LayerId, out var existingLayerId))
+ {
+ layerId = existingLayerId;
+ }
+
+ Guid? viewId = null;
+
+ if (Guid.TryParse(ViewId, out var existingViewId))
+ {
+ viewId = existingViewId;
+ }
+
+ return new Graphic(Geometry?.FromSerializationRecord(), Symbol?.FromSerializationRecord(),
+ PopupTemplate?.FromSerializationRecord(), new AttributesDictionary(Attributes),
+ Visible, null, AggregateGeometries, Origin?.FromSerializationRecord())
+ {
+ Id = graphicId,
+#pragma warning disable BL0005
+ LayerId = layerId,
+#pragma warning restore BL0005
+ ViewId = viewId
+ };
+ }
+}
+
+[ProtoContract(Name = "GraphicCollection")]
+internal record
+ GraphicCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public GraphicCollectionSerializationRecord()
+ {
+ }
+
+ public GraphicCollectionSerializationRecord(GraphicSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override GraphicSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MapFont")]
+public record MapFontSerializationRecord : MapComponentSerializationRecord
+{
+ public MapFontSerializationRecord()
+ {
+ }
+
+ public MapFontSerializationRecord(string Id, double? Size, string? Family, string? FontStyle, string? Weight,
+ string? Decoration)
+ {
+ this.Id = Id;
+ this.Size = Size;
+ this.Family = Family;
+ this.FontStyle = FontStyle;
+ this.Weight = Weight;
+ this.Decoration = Decoration;
+ }
+
+ [ProtoMember(1)]
+ public double? Size { get; init; }
+
+ [ProtoMember(2)]
+ public string? Family { get; init; }
+
+ [ProtoMember(3)]
+ public string? FontStyle { get; init; }
+
+ [ProtoMember(4)]
+ public string? Weight { get; init; }
+
+ [ProtoMember(5)]
+ public string? Decoration { get; init; }
+
+ [ProtoMember(6)]
+ public string? Id { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MapFont? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guid))
+ {
+ id = guid;
+ }
+
+ return new MapFont(Size, Family, FontStyle is null ? null : Enum.Parse(FontStyle),
+ Weight is null ? null : Enum.Parse(Weight),
+ Decoration is null ? null : Enum.Parse(Decoration)) { Id = id };
+ }
+}
+
+[ProtoContract(Name = "MapFontCollection")]
+internal record
+ MapFontCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public MapFontCollectionSerializationRecord()
+ {
+ }
+
+ public MapFontCollectionSerializationRecord(MapFontSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MapFontSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MediaInfo")]
+public record MediaInfoSerializationRecord : MapComponentSerializationRecord
+{
+ public MediaInfoSerializationRecord()
+ {
+ }
+
+ public MediaInfoSerializationRecord(string Id, string Type)
+ {
+ this.Id = Id;
+ this.Type = Type;
+ }
+
+ [ProtoMember(1)]
+ public string Type { get; init; } = string.Empty;
+
+ [ProtoMember(2)]
+ public string? AltText { get; init; }
+
+ [ProtoMember(3)]
+ public string? Caption { get; init; }
+
+ [ProtoMember(4)]
+ public string? Title { get; init; }
+
+ [ProtoMember(5)]
+ public MediaInfoValueSerializationRecord? Value { get; init; }
+
+ [ProtoMember(6)]
+ public double? RefreshInterval { get; init; }
+
+ [ProtoMember(7)]
+ public string? Id { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MediaInfo? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guid))
+ {
+ id = guid;
+ }
+
+ return Type switch
+ {
+ "bar-chart" => new BarChartMediaInfo(Title, Caption, AltText,
+ Value?.FromSerializationRecord() as ChartMediaInfoValue) { Id = id },
+ "column-chart" => new ColumnChartMediaInfo(Title, Caption, AltText,
+ Value?.FromSerializationRecord() as ChartMediaInfoValue) { Id = id },
+ "pie-chart" => new PieChartMediaInfo(Title, Caption, AltText,
+ Value?.FromSerializationRecord() as ChartMediaInfoValue) { Id = id },
+ "line-chart" => new LineChartMediaInfo(Title, Caption, AltText,
+ Value?.FromSerializationRecord() as ChartMediaInfoValue) { Id = id },
+ "image-media" => new ImageMediaInfo(Title, Caption, AltText,
+ Value?.FromSerializationRecord() as ImageMediaInfoValue,
+ RefreshInterval) { Id = id },
+ _ => throw new NotSupportedException($"MediaInfo type {Type} is not supported.")
+ };
+ }
+}
+
+[ProtoContract(Name = "MediaInfoCollection")]
+internal record
+ MediaInfoCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public MediaInfoCollectionSerializationRecord()
+ {
+ }
+
+ public MediaInfoCollectionSerializationRecord(MediaInfoSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MediaInfoSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "RelatedRecordsInfoFieldOrder")]
+public record RelatedRecordsInfoFieldOrderSerializationRecord(
+ [property: ProtoMember(1)] string? Field,
+ [property: ProtoMember(2)] string? Order,
+ [property: ProtoMember(3)] string Id) : MapComponentSerializationRecord
+{
+ public RelatedRecordsInfoFieldOrderSerializationRecord() : this(null, null, Guid.NewGuid().ToString())
+ {
+ }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override RelatedRecordsInfoFieldOrder? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ var id = Guid.NewGuid();
+
+ if (Guid.TryParse(Id, out var guid))
+ {
+ id = guid;
+ }
+
+ OrderBy? orderBy = Order is null ? null : Enum.Parse(Order!, true);
+
+ return new RelatedRecordsInfoFieldOrder(Field, orderBy) { Id = id };
+ }
+}
+
+[ProtoContract(Name = "RelatedRecordsInfoFieldOrderCollection")]
+internal record RelatedRecordsInfoFieldOrderCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ RelatedRecordsInfoFieldOrderSerializationRecord>
+{
+ public RelatedRecordsInfoFieldOrderCollectionSerializationRecord()
+ {
+ }
+
+ public RelatedRecordsInfoFieldOrderCollectionSerializationRecord(
+ RelatedRecordsInfoFieldOrderSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override RelatedRecordsInfoFieldOrderSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "SpatialReference")]
+public record SpatialReferenceSerializationRecord : MapComponentSerializationRecord
+{
+ public SpatialReferenceSerializationRecord()
+ {
+ }
+
+ public SpatialReferenceSerializationRecord(int? Wkid, string? Wkt = null, string? Wkt2 = null)
+ {
+ this.Wkid = Wkid;
+ this.Wkt = Wkt;
+ this.Wkt2 = Wkt2;
+ }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(1)]
+ public int? Wkid { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public string? Wkt { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public string? Wkt2 { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override SpatialReference? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new SpatialReference(Wkid ?? 4326, wkt: Wkt, wkt2: Wkt2);
+ }
+}
+
+[ProtoContract(Name = "SpatialReferenceCollection")]
+internal record
+ SpatialReferenceCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ SpatialReferenceSerializationRecord>
+{
+ public SpatialReferenceCollectionSerializationRecord()
+ {
+ }
+
+ public SpatialReferenceCollectionSerializationRecord(SpatialReferenceSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override SpatialReferenceSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "Attribute")]
+public record AttributeSerializationRecord : MapComponentSerializationRecord
+{
+ public AttributeSerializationRecord()
+ {
+ }
+
+ public AttributeSerializationRecord(string Key,
+ string? Value,
+ string ValueType)
+ {
+ this.Key = Key;
+ this.Value = Value;
+ this.ValueType = ValueType;
+ }
+
+ [ProtoMember(1)]
+ public string Key { get; init; } = string.Empty;
+ [ProtoMember(2)]
+ public string? Value { get; init; }
+ [ProtoMember(3)]
+ public string ValueType { get; init; } = string.Empty;
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public (string Key, object? Value) FromSerializationRecord()
+ {
+ if (Value is null)
+ {
+ return (Key, Value);
+ }
+
+ if (string.Equals("OBJECTID", Key, StringComparison.OrdinalIgnoreCase))
+ {
+ if (long.TryParse(Value, NumberStyles.None, CultureInfo.InvariantCulture, out var numVal))
+ {
+ return (Key, new ObjectId(numVal));
+ }
+
+ return (Key, new ObjectId(Value));
+ }
+
+ switch (ValueType)
+ {
+ case "System.Int32":
+ case "integer":
+ return (Key, int.Parse(Value!, CultureInfo.InvariantCulture));
+
+ case "System.Int16":
+ case "small-integer":
+ return (Key, short.Parse(Value!, CultureInfo.InvariantCulture));
+
+ case "System.Int64":
+ case "big-integer":
+ return (Key, long.Parse(Value!, CultureInfo.InvariantCulture));
+
+ case "System.Single":
+ case "single":
+ return (Key, float.Parse(Value!, CultureInfo.InvariantCulture));
+
+ case "System.Double":
+ case "double":
+ return (Key, double.Parse(Value!, CultureInfo.InvariantCulture));
+
+ case "[object Number]":
+ if (int.TryParse(Value, NumberStyles.None, CultureInfo.InvariantCulture, out var intVal))
+ {
+ return (Key, intVal);
+ }
+
+ if (long.TryParse(Value, NumberStyles.None, CultureInfo.InvariantCulture, out var longVal))
+ {
+ return (Key, longVal);
+ }
+
+ if (double.TryParse(Value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture,
+ out var doubleVal))
+ {
+ return (Key, doubleVal);
+ }
+
+ return (Key, Value);
+ case "System.Boolean":
+ case "[object Boolean]":
+ return (Key, bool.Parse(Value!));
+
+ case "guid":
+ return (Key, Guid.Parse(Value!));
+
+ case "System.DateTime":
+ case "date":
+ case "timestamp-offset":
+ case "[object Date]":
+ // Date is serialized in ArcGIS as a long unix timestamp, so we check for this first.
+ if (long.TryParse(Value, out var unixTimestamp))
+ {
+ return (Key, DateTimeOffset.FromUnixTimeMilliseconds(unixTimestamp).DateTime);
+ }
+
+ return (Key, DateTime.Parse(Value!, CultureInfo.InvariantCulture));
+
+ case "System.DateOnly":
+ case "date-only":
+ return (Key, DateOnly.Parse(Value!, CultureInfo.InvariantCulture));
+
+ case "System.TimeOnly":
+ case "time-only":
+ return (Key, TimeOnly.Parse(Value!, CultureInfo.InvariantCulture));
+
+ default:
+ if (Guid.TryParse(Value, out var guidValue))
+ {
+ return (Key, guidValue);
+ }
+
+ if (DateTime.TryParse(Value, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dateValue))
+ {
+ return (Key, dateValue);
+ }
+
+ return (Key, Value);
+ }
+ }
+}
+
+[ProtoContract(Name = "AttributeCollection")]
+public record
+ AttributeCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public AttributeCollectionSerializationRecord()
+ {
+ }
+
+ public AttributeCollectionSerializationRecord(AttributeSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override AttributeSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "GraphicOrigin")]
+public record GraphicOriginSerializationRecord : MapComponentSerializationRecord
+{
+ public GraphicOriginSerializationRecord()
+ {
+ }
+
+ public GraphicOriginSerializationRecord(string? LayerId, string? ArcGISLayerId, int? LayerIndex)
+ {
+ this.LayerId = LayerId;
+ this.ArcGISLayerId = ArcGISLayerId;
+ this.LayerIndex = LayerIndex;
+ }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(1)]
+ public string? LayerId { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(2)]
+ public string? ArcGISLayerId { get; init; }
+
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ [ProtoMember(3)]
+ public int? LayerIndex { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override GraphicOrigin? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new GraphicOrigin(LayerId is null ? null : Guid.Parse(LayerId),
+ ArcGISLayerId, LayerIndex);
+ }
+}
+
+[ProtoContract(Name = "GraphicOriginCollection")]
+internal record
+ GraphicOriginCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ GraphicOriginSerializationRecord>
+{
+ public GraphicOriginCollectionSerializationRecord()
+ {
+ }
+
+ public GraphicOriginCollectionSerializationRecord(GraphicOriginSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override GraphicOriginSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MapPath")]
+public record MapPathSerializationRecord : MapComponentSerializationRecord
+{
+ public MapPathSerializationRecord()
+ {
+ }
+
+ public MapPathSerializationRecord(MapPointSerializationRecord[] Points)
+ {
+ this.Points = Points;
+ }
+
+ [ProtoMember(1)]
+ public MapPointSerializationRecord[] Points { get; init; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MapPath? FromSerializationRecord()
+ {
+ if (IsNull || (Points.Length == 0) || Points.Any(p => p.IsNull))
+ {
+ return null;
+ }
+
+ return new MapPath(Points.Select(p => p.FromSerializationRecord()!));
+ }
+}
+
+[ProtoContract(Name = "MapPathCollection")]
+internal record
+ MapPathCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public MapPathCollectionSerializationRecord()
+ {
+ }
+
+ public MapPathCollectionSerializationRecord(MapPathSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MapPathSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MapPoint")]
+public record MapPointSerializationRecord : MapComponentSerializationRecord
+{
+ public MapPointSerializationRecord()
+ {
+ }
+
+ public MapPointSerializationRecord(double[] Coordinates)
+ {
+ this.Coordinates = Coordinates;
+ }
+
+ [ProtoMember(1)]
+ public double[] Coordinates { get; init; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MapPoint? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new MapPoint(Coordinates);
+ }
+}
+
+[ProtoContract(Name = "MapPointCollection")]
+internal record
+ MapPointCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public MapPointCollectionSerializationRecord()
+ {
+ }
+
+ public MapPointCollectionSerializationRecord(MapPointSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MapPointSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MeshComponent")]
+public record MeshComponentSerializationRecord : MapComponentSerializationRecord
+{
+ public MeshComponentSerializationRecord()
+ {
+ }
+
+ public MeshComponentSerializationRecord(byte[]? faces,
+ MeshComponentMaterialSerializationRecord? material,
+ string? name,
+ string? shading)
+ {
+ Faces = faces;
+ Material = material;
+ Name = name;
+ Shading = shading;
+ }
+
+ [ProtoMember(1)]
+ public byte[]? Faces { get; init; }
+
+ [ProtoMember(2)]
+ public MeshComponentMaterialSerializationRecord? Material { get; init; }
+
+ [ProtoMember(3)]
+ public string? Name { get; init; }
+
+ [ProtoMember(4)]
+ public string? Shading { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MeshComponent? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new MeshComponent(Faces,
+ Material?.FromSerializationRecord(),
+ Name,
+ Shading is null ? null : Enum.Parse(Shading));
+ }
+}
+
+[ProtoContract(Name = "MeshComponentCollection")]
+internal record
+ MeshComponentCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ MeshComponentSerializationRecord>
+{
+ public MeshComponentCollectionSerializationRecord(MeshComponentSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MeshComponentSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MeshComponentMaterial")]
+public record MeshComponentMaterialSerializationRecord : MapComponentSerializationRecord
+{
+ public MeshComponentMaterialSerializationRecord()
+ {
+ }
+
+ public MeshComponentMaterialSerializationRecord(double? alphaCutoff,
+ string? alphaMode,
+ MapColorSerializationRecord? color,
+ MeshTextureSerializationRecord? colorTexture,
+ MeshTextureTransformSerializationRecord? colorTextureTransform,
+ bool? doubleSided,
+ MeshTextureSerializationRecord? normalTexture,
+ MeshTextureTransformSerializationRecord? normalTextureTransform,
+ MapColorSerializationRecord? emissiveColor,
+ MeshTextureSerializationRecord? emissiveTexture,
+ MeshTextureTransformSerializationRecord? emissiveTextureTransform,
+ double? metallic,
+ MeshTextureSerializationRecord? metallicRoughnessTexture,
+ MeshTextureSerializationRecord? occlusionTexture,
+ MeshTextureTransformSerializationRecord? occlusionTextureTransform,
+ double? roughness)
+ {
+ AlphaCutoff = alphaCutoff;
+ AlphaMode = alphaMode;
+ Color = color;
+ ColorTexture = colorTexture;
+ ColorTextureTransform = colorTextureTransform;
+ DoubleSided = doubleSided;
+ NormalTexture = normalTexture;
+ NormalTextureTransform = normalTextureTransform;
+ EmissiveColor = emissiveColor;
+ EmissiveTexture = emissiveTexture;
+ EmissiveTextureTransform = emissiveTextureTransform;
+ Metallic = metallic;
+ MetallicRoughnessTexture = metallicRoughnessTexture;
+ OcclusionTexture = occlusionTexture;
+ OcclusionTextureTransform = occlusionTextureTransform;
+ Roughness = roughness;
+ }
+
+ [ProtoMember(1)]
+ public double? AlphaCutoff { get; init; }
+
+ [ProtoMember(2)]
+ public string? AlphaMode { get; init; }
+
+ [ProtoMember(3)]
+ public MapColorSerializationRecord? Color { get; init; }
+
+ [ProtoMember(4)]
+ public MeshTextureSerializationRecord? ColorTexture { get; init; }
+
+ [ProtoMember(5)]
+ public MeshTextureTransformSerializationRecord? ColorTextureTransform { get; init; }
+
+ [ProtoMember(6)]
+ public bool? DoubleSided { get; init; }
+
+ [ProtoMember(7)]
+ public MeshTextureSerializationRecord? NormalTexture { get; init; }
+
+ [ProtoMember(8)]
+ public MeshTextureTransformSerializationRecord? NormalTextureTransform { get; init; }
+
+ [ProtoMember(9)]
+ public MapColorSerializationRecord? EmissiveColor { get; init; }
+
+ [ProtoMember(10)]
+ public MeshTextureSerializationRecord? EmissiveTexture { get; init; }
+
+ [ProtoMember(11)]
+ public MeshTextureTransformSerializationRecord? EmissiveTextureTransform { get; init; }
+
+ [ProtoMember(12)]
+ public double? Metallic { get; init; }
+
+ [ProtoMember(13)]
+ public MeshTextureSerializationRecord? MetallicRoughnessTexture { get; init; }
+
+ [ProtoMember(14)]
+ public MeshTextureSerializationRecord? OcclusionTexture { get; init; }
+
+ [ProtoMember(15)]
+ public MeshTextureTransformSerializationRecord? OcclusionTextureTransform { get; init; }
+
+ [ProtoMember(16)]
+ public double? Roughness { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override IMeshComponentMaterial? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ if ((EmissiveColor != null) || (EmissiveTexture != null)
+ || (EmissiveTextureTransform != null) || (Metallic != null)
+ || (MetallicRoughnessTexture != null) || (OcclusionTexture != null)
+ || (OcclusionTextureTransform != null) || (Roughness != null))
+ {
+ return new MeshMaterialMetallicRoughness(AlphaCutoff,
+ AlphaMode is null ? null : Enum.Parse(AlphaMode),
+ Color?.FromSerializationRecord(),
+ ColorTexture?.FromSerializationRecord(),
+ ColorTextureTransform?.FromSerializationRecord(),
+ DoubleSided,
+ EmissiveColor?.FromSerializationRecord(),
+ EmissiveTexture?.FromSerializationRecord(),
+ EmissiveTextureTransform?.FromSerializationRecord(),
+ Metallic,
+ MetallicRoughnessTexture?.FromSerializationRecord(),
+ NormalTexture?.FromSerializationRecord(),
+ NormalTextureTransform?.FromSerializationRecord(),
+ OcclusionTexture?.FromSerializationRecord(),
+ OcclusionTextureTransform?.FromSerializationRecord(),
+ Roughness);
+ }
+
+ return new MeshMaterial(AlphaCutoff,
+ AlphaMode is null ? null : Enum.Parse(AlphaMode),
+ Color?.FromSerializationRecord(),
+ ColorTexture?.FromSerializationRecord(),
+ ColorTextureTransform?.FromSerializationRecord(),
+ DoubleSided,
+ NormalTexture?.FromSerializationRecord(),
+ NormalTextureTransform?.FromSerializationRecord());
+ }
+}
+
+[ProtoContract(Name = "MeshComponentMaterialCollection")]
+internal record
+ MeshComponentMaterialCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ MeshComponentMaterialSerializationRecord>
+{
+ public MeshComponentMaterialCollectionSerializationRecord(MeshComponentMaterialSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MeshComponentMaterialSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MeshTexture")]
+public record MeshTextureSerializationRecord : MapComponentSerializationRecord
+{
+ public MeshTextureSerializationRecord()
+ {
+ }
+
+ public MeshTextureSerializationRecord(ImageDataSerializationRecord? imageData,
+ string?[]? wrap,
+ bool? transparent,
+ string? url)
+ {
+ ImageData = imageData;
+ Wrap = wrap;
+ Transparent = transparent;
+ Url = url;
+ }
+
+ [ProtoMember(1)]
+ public ImageDataSerializationRecord? ImageData { get; init; }
+
+ [ProtoMember(2)]
+ public string?[]? Wrap { get; init; }
+
+ [ProtoMember(3)]
+ public bool? Transparent { get; init; }
+
+ [ProtoMember(4)]
+ public string? Url { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MeshTexture? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ SeparableWrapModes? wrapModes = null;
+
+ if (Wrap != null)
+ {
+ if (Wrap.Length == 2)
+ {
+ var first = Wrap[0];
+ var second = Wrap[1];
+
+ wrapModes = new SeparableWrapModes(first is null ? null : Enum.Parse(first),
+ second is null ? null : Enum.Parse(second));
+ }
+ else if (Wrap.Length == 1)
+ {
+ var value = Wrap[0];
+ WrapMode? wrapVal = value is null ? null : Enum.Parse(value);
+ wrapModes = new SeparableWrapModes(wrapVal, wrapVal);
+ }
+ }
+
+ return new MeshTexture(null, ImageData?.FromSerializationRecord(), wrapModes, Transparent, Url);
+ }
+}
+
+[ProtoContract(Name = "MeshTextureCollection")]
+internal record
+ MeshTextureCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public MeshTextureCollectionSerializationRecord(MeshTextureSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MeshTextureSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "ImageData")]
+public record ImageDataSerializationRecord : MapComponentSerializationRecord
+{
+ public ImageDataSerializationRecord()
+ {
+ }
+
+ public ImageDataSerializationRecord(byte[] data,
+ string colorSpace,
+ long height,
+ long width)
+ {
+ Data = data;
+ ColorSpace = colorSpace;
+ Height = height;
+ Width = width;
+ }
+
+ [ProtoMember(1)]
+ public byte[]? Data { get; init; }
+
+ [ProtoMember(2)]
+ public string? ColorSpace { get; init; }
+
+ [ProtoMember(3)]
+ public long Height { get; init; }
+
+ [ProtoMember(4)]
+ public long Width { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override ImageData? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new ImageData(Data ?? [], ColorSpace ?? string.Empty, Height, Width);
+ }
+}
+
+[ProtoContract(Name = "ImageDataCollection")]
+public record ImageDataCollectionSerializationRecord
+ : MapComponentCollectionSerializationRecord
+{
+ public ImageDataCollectionSerializationRecord(ImageDataSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ public sealed override ImageDataSerializationRecord[]? Items { get; set; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MeshTextureTransform")]
+public record MeshTextureTransformSerializationRecord : MapComponentSerializationRecord
+{
+ public MeshTextureTransformSerializationRecord()
+ {
+ }
+
+ public MeshTextureTransformSerializationRecord(double[]? offset,
+ double? rotation,
+ double[]? scale)
+ {
+ Offset = offset;
+ Rotation = rotation;
+ Scale = scale;
+ }
+
+ [ProtoMember(1)]
+ public double[]? Offset { get; init; }
+
+ [ProtoMember(2)]
+ public double? Rotation { get; init; }
+
+ [ProtoMember(3)]
+ public double[]? Scale { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MeshTextureTransform? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new MeshTextureTransform(Offset, Rotation, Scale);
+ }
+}
+
+[ProtoContract(Name = "MeshTextureTransformCollection")]
+internal record
+ MeshTextureTransformCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ MeshTextureTransformSerializationRecord>
+{
+ public MeshTextureTransformCollectionSerializationRecord(MeshTextureTransformSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MeshTextureTransformSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MeshTransform")]
+public record MeshTransformSerializationRecord : MapComponentSerializationRecord
+{
+ public MeshTransformSerializationRecord()
+ {
+ }
+
+ public MeshTransformSerializationRecord(double? rotationAngle,
+ double[]? rotationAxis,
+ double[]? scale,
+ double[]? translation)
+ {
+ RotationAngle = rotationAngle;
+ RotationAxis = rotationAxis;
+ Scale = scale;
+ Translation = translation;
+ }
+
+ [ProtoMember(1)]
+ public double? RotationAngle { get; init; }
+
+ [ProtoMember(2)]
+ public double[]? RotationAxis { get; init; }
+
+ [ProtoMember(3)]
+ public double[]? Scale { get; init; }
+
+ [ProtoMember(4)]
+ public double[]? Translation { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MeshTransform? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new MeshTransform(RotationAngle, RotationAxis, Scale, Translation);
+ }
+}
+
+[ProtoContract(Name = "MeshTransformCollection")]
+internal record
+ MeshTransformCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ MeshTransformSerializationRecord>
+{
+ public MeshTransformCollectionSerializationRecord(MeshTransformSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MeshTransformSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MeshVertexAttributes")]
+public record MeshVertexAttributesSerializationRecord : MapComponentSerializationRecord
+{
+ public MeshVertexAttributesSerializationRecord()
+ {
+ }
+
+ public MeshVertexAttributesSerializationRecord(byte[]? color,
+ double[]? normal,
+ double[]? position,
+ double[]? tangent,
+ double[]? uv)
+ {
+ Color = color;
+ Normal = normal;
+ Position = position;
+ Tangent = tangent;
+ Uv = uv;
+ }
+
+ [ProtoMember(1)]
+ public byte[]? Color { get; init; }
+
+ [ProtoMember(2)]
+ public double[]? Normal { get; init; }
+
+ [ProtoMember(3)]
+ public double[]? Position { get; init; }
+
+ [ProtoMember(4)]
+ public double[]? Tangent { get; init; }
+
+ [ProtoMember(5)]
+ public double[]? Uv { get; init; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override MeshVertexAttributes? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return new MeshVertexAttributes(Color, Normal, Position, Tangent, Uv);
+ }
+}
+
+[ProtoContract(Name = "MeshVertexAttributesCollection")]
+internal record
+ MeshVertexAttributesCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ MeshVertexAttributesSerializationRecord>
+{
+ public MeshVertexAttributesCollectionSerializationRecord(MeshVertexAttributesSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MeshVertexAttributesSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "MeshVertexSpace")]
+public record MeshVertexSpaceSerializationRecord : MapComponentSerializationRecord
+{
+ public MeshVertexSpaceSerializationRecord()
+ {
+ }
+
+ public MeshVertexSpaceSerializationRecord(string? type,
+ double[]? origin)
+ {
+ Type = type;
+ Origin = origin;
+ }
+
+ [ProtoMember(1)]
+ public string? Type { get; set; }
+
+ [ProtoMember(2)]
+ public double[]? Origin { get; set; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override IMeshVertexSpace? FromSerializationRecord()
+ {
+ if (IsNull)
+ {
+ return null;
+ }
+
+ return Type switch
+ {
+ "local" => new MeshLocalVertexSpace(Origin),
+ "georeferenced" => new MeshGeoreferencedVertexSpace(Origin),
+ _ => throw new NotSupportedException($"MeshVertexSpace type {Type} is not supported.")
+ };
+ }
+}
+
+[ProtoContract(Name = "MeshVertexSpaceCollection")]
+internal record
+ MeshVertexSpaceCollectionSerializationRecord : MapComponentCollectionSerializationRecord<
+ MeshVertexSpaceSerializationRecord>
+{
+ public MeshVertexSpaceCollectionSerializationRecord(MeshVertexSpaceSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override MeshVertexSpaceSerializationRecord[]? Items { get; set; } = [];
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "ViewHitCollection")]
+internal record
+ ViewHitCollectionSerializationRecord : MapComponentCollectionSerializationRecord
+{
+ public ViewHitCollectionSerializationRecord()
+ {
+ }
+
+ public ViewHitCollectionSerializationRecord(ViewHitSerializationRecord[] items)
+ {
+ Items = items;
+ }
+
+ [ProtoMember(1)]
+ public sealed override ViewHitSerializationRecord[]? Items { get; set; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+}
+
+[ProtoContract(Name = "ViewHit")]
+public record ViewHitSerializationRecord : MapComponentSerializationRecord
+{
+ public ViewHitSerializationRecord()
+ {
+ }
+
+ public ViewHitSerializationRecord(string? Type,
+ GeometrySerializationRecord? MapPoint,
+ GraphicSerializationRecord? Graphic,
+ string? LayerId,
+ double? Distance)
+ {
+ this.Type = Type;
+ this.MapPoint = MapPoint;
+ this.Graphic = Graphic;
+ this.LayerId = LayerId;
+ this.Distance = Distance;
+ }
+
+ [ProtoMember(1)]
+ public string? Type { get; set; }
+
+ [ProtoMember(2)]
+ public GeometrySerializationRecord? MapPoint { get; set; }
+
+ [ProtoMember(3)]
+ public GraphicSerializationRecord? Graphic { get; set; }
+
+ [ProtoMember(4)]
+ public string? LayerId { get; set; }
+
+ [ProtoMember(5)]
+ public double? Distance { get; set; }
+
+ [ProtoMember(1000)]
+ public override bool IsNull { get; init; }
+
+ public override ViewHit? FromSerializationRecord()
+ {
+ if (IsNull || MapPoint is null || MapPoint.IsNull)
+ {
+ return null;
+ }
+
+ if (Type == "graphic")
+ {
+ if (Graphic is null || Graphic.IsNull)
+ {
+ return null;
+ }
+
+ Guid? layerId = null;
+
+ if (Guid.TryParse(LayerId, out var layerGuid))
+ {
+ layerId = layerGuid;
+ }
+
+ return new GraphicHit(Graphic!.FromSerializationRecord()!, layerId,
+ (Point)MapPoint!.FromSerializationRecord()!, Distance);
+ }
+
+ return new ViewHit(Type!, (Point)MapPoint!.FromSerializationRecord()!);
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/copyProtobuf.ps1 b/src/dymaptic.GeoBlazor.Core/copyProtobuf.ps1
new file mode 100644
index 000000000..08c69d676
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/copyProtobuf.ps1
@@ -0,0 +1,14 @@
+param ([string]$Content)
+
+if ($null -eq $Content -or $Content -eq "") {
+ Write-Error "Content parameter is required."
+ exit 1
+}
+
+# Define the destination path
+$destinationPath = Join-Path $PSScriptRoot "Scripts" "geoblazorProto.ts"
+
+# Unescape any escaped characters in the content
+$Content = $Content -replace '\\"', '"' -replace '\\r\\n', "`r`n" -replace '\\n', "`n"
+
+Set-Content -Path $destinationPath -Value $Content -Encoding UTF8
\ No newline at end of file
From 4ebeb7b23e71c9596cf81d7f4759deb552a696f6 Mon Sep 17 00:00:00 2001
From: Tim Purdum
Date: Mon, 15 Dec 2025 21:03:49 -0600
Subject: [PATCH 2/7] Update protobuf implementation, samples and tests
---
Directory.Build.targets | 6 +
esBuildWaitForCompletion.ps1 | 27 +-
....GeoBlazor.Core.Sample.OAuth.Client.csproj | 3 -
.../Components/App.razor | 13 -
.../Program.cs | 5 +-
...ymaptic.GeoBlazor.Core.Sample.OAuth.csproj | 2 -
.../Pages/HitTests.razor | 2 +-
.../Pages/ManyGraphics.razor | 3 +-
.../Pages/ServerSideQueries.razor | 70 +-
.../Pages/Tests.razor | 24 +-
.../Pages/WFSLayers.razor | 18 +-
.../Shared/NavMenu.razor.cs | 24 +-
.../wwwroot/functions.js | 31 +-
...zor.Core.Sample.TokenRefresh.Client.csproj | 2 -
....GeoBlazor.Core.Sample.TokenRefresh.csproj | 2 -
src/.editorconfig | 2 +-
.../Properties/launchSettings.json | 9 +
.../ProtobufSourceGenerator.cs | 43 +-
src/dymaptic.GeoBlazor.Core.sln | 14 +
.../Components/ActionBase.cs | 91 +-
.../Components/ActionButton.cs | 6 +-
.../Components/ActionToggle.cs | 6 +-
.../Components/BarChartMediaInfo.cs | 9 +-
.../Components/BookmarksViewModel.cs | 2 +-
.../Components/ChartMediaInfoValue.cs | 83 +-
.../Components/ChartMediaInfoValueSeries.cs | 50 +-
.../Components/Circle.cs | 16 +-
.../Components/ColumnChartMediaInfo.cs | 9 +-
.../Components/CompassViewModel.cs | 2 +-
.../Components/ElementExpressionInfo.cs | 33 +-
.../Components/FeaturesViewModel.cs | 2 +-
.../Components/FeaturesViewModel.gb.cs | 2 +-
.../Components/FieldInfo.cs | 86 +-
.../Components/FieldInfoFormat.cs | 82 +-
.../Components/Geometries/Extent.cs | 6 +-
.../Components/Geometries/Geometry.cs | 207 +---
.../Components/Geometries/OldPolyLine.cs | 1 +
.../Components/Geometries/Point.cs | 10 +-
.../Components/Geometries/Polygon.cs | 12 +-
.../Components/Geometries/Polyline.cs | 12 +-
.../Components/Graphic.cs | 124 +--
.../Components/HomeViewModel.cs | 2 +-
.../Components/HomeViewModel.gb.cs | 2 +-
.../Components/ImageMediaInfo.cs | 10 +-
.../Components/ImageMediaInfoValue.cs | 12 +-
.../Components/JoinTableDataSource.cs | 2 -
.../Components/Label.cs | 2 +-
.../Components/LayerListViewModel.gb.cs | 2 +-
.../Components/Layers/BaseTileLayer.gb.cs | 2 +-
.../Components/Layers/CSVLayer.gb.cs | 2 +-
.../Components/Layers/FeatureLayer.gb.cs | 4 +-
.../Components/Layers/GeoJSONLayer.gb.cs | 4 +-
.../Components/Layers/GeoRSSLayer.gb.cs | 2 +-
.../Components/Layers/ImageryLayer.gb.cs | 2 +-
.../Components/Layers/Layer.cs | 2 +-
.../Components/Layers/Layer.gb.cs | 6 +-
.../Components/Layers/MapImageLayer.gb.cs | 2 +-
.../Components/Layers/TileLayer.gb.cs | 2 +-
.../Components/Layers/VectorTileLayer.gb.cs | 2 +-
.../Components/Layers/WFSLayer.gb.cs | 2 +-
.../Components/Layers/WMSLayer.gb.cs | 2 +-
.../Components/Layers/WebTileLayer.gb.cs | 2 +-
.../Components/LineChartMediaInfo.cs | 9 +-
.../Components/LocateViewModel.cs | 4 +-
.../Components/LocateViewModel.gb.cs | 2 +-
.../Components/LocationService.cs | 4 +-
.../Components/MapComponent.razor.cs | 52 +-
.../Components/MapFont.cs | 57 +-
.../Components/MediaInfo.cs | 65 +-
.../Components/MeshComponent.cs | 59 ++
.../Components/MeshComponent.gb.cs | 417 +++++++++
.../MeshGeoreferencedVertexSpace.cs | 24 +
.../Components/MeshLocalVertexSpace.cs | 20 +
.../Components/MeshMaterial.cs | 23 +
.../Components/MeshMaterial.gb.cs | 823 ++++++++++++++++
.../MeshMaterialMetallicRoughness.cs | 28 +
.../MeshMaterialMetallicRoughness.gb.cs | 883 ++++++++++++++++++
.../Components/MeshTexture.cs | 518 ++++++++++
.../Components/MeshTextureTransform.cs | 14 +
.../Components/MeshTextureTransform.gb.cs | 396 ++++++++
.../Components/MeshTransform.cs | 16 +
.../Components/MeshTransform.gb.cs | 519 ++++++++++
.../Components/MeshVertexAttributes.cs | 60 ++
.../Components/MeshVertexAttributes.gb.cs | 624 +++++++++++++
.../Components/PieChartMediaInfo.cs | 8 +-
.../Popups/AttachmentsPopupContent.cs | 6 +-
.../Popups/ExpressionPopupContent.cs | 8 +-
.../Components/Popups/FieldsPopupContent.cs | 8 +-
.../Components/Popups/MediaPopupContent.cs | 8 +-
.../Components/Popups/PopupContent.cs | 112 +--
.../Components/Popups/PopupExpressionInfo.cs | 57 +-
.../Components/Popups/PopupTemplate.cs | 95 +-
.../Popups/RelationshipPopupContent.cs | 8 +-
.../Components/Popups/TextPopupContent.cs | 6 +-
.../RelatedRecordsInfoFieldOrder.cs | 28 +-
.../Components/Renderers/SimpleRenderer.cs | 2 +-
.../Components/SearchViewModel.cs | 2 +-
.../Components/SearchViewModel.gb.cs | 12 +-
.../Components/SpatialReference.cs | 36 +-
.../Components/Symbols/FillSymbol.cs | 2 +-
.../Components/Symbols/LineSymbol.cs | 1 +
.../Components/Symbols/MarkerSymbol.cs | 1 +
.../Components/Symbols/Outline.cs | 1 +
.../Components/Symbols/PictureFillSymbol.cs | 8 +-
.../Components/Symbols/PictureMarkerSymbol.cs | 6 +-
.../Components/Symbols/SimpleFillSymbol.cs | 10 +-
.../Components/Symbols/SimpleLineSymbol.cs | 8 +-
.../Components/Symbols/SimpleMarkerSymbol.cs | 10 +-
.../Components/Symbols/Symbol.cs | 182 +---
.../Components/Symbols/TextSymbol.cs | 17 +-
.../Components/UniqueValueInfo.cs | 2 +-
.../Components/Views/MapView.razor | 4 +-
.../Components/Views/MapView.razor.cs | 253 +++--
.../Components/Views/SceneView.cs | 2 +-
.../Widgets/BasemapLayerListWidget.cs | 2 +-
.../Components/Widgets/BookmarksWidget.cs | 4 +-
.../Components/Widgets/BookmarksWidget.gb.cs | 2 +-
.../Components/Widgets/CompassWidget.cs | 2 +-
.../Components/Widgets/HomeWidget.cs | 4 +-
.../Components/Widgets/LayerListWidget.cs | 2 +-
.../Components/Widgets/LocateWidget.cs | 2 +-
.../Components/Widgets/LocateWidget.gb.cs | 4 +-
.../Components/Widgets/PopupWidget.cs | 6 +-
.../Components/Widgets/SearchWidget.cs | 22 +-
.../Components/Widgets/SearchWidget.gb.cs | 10 +-
.../Components/Widgets/SliderWidget.gb.cs | 22 +-
.../DependencyExtension.cs | 37 +-
.../Enums/{Shading.cs => MeshShading.cs} | 4 +-
.../Enums/{Horizontal.cs => WrapMode.cs} | 7 +-
.../Interfaces/IInteractiveRecord.cs | 2 +
.../Interfaces/IMediaInfoValue.cs | 9 +
.../Model/AttributesDictionary.cs | 32 +-
.../Model/FieldsIndex.gb.cs | 5 +
.../Model/GraphicHit.cs | 14 +-
.../Model/GraphicOrigin.cs | 40 +-
.../Model/Ground.gb.cs | 5 +
.../Model/ImageData.cs | 12 +-
src/dymaptic.GeoBlazor.Core/Model/MapColor.cs | 11 +-
src/dymaptic.GeoBlazor.Core/Model/MapPath.cs | 57 +-
.../Model/PortalGroup.gb.cs | 5 +
.../Model/PortalItemResource.gb.cs | 5 +
.../Model/SeparableWrapModes.cs | 32 +-
.../Model/SeparableWrapModes.gb.cs | 22 -
.../Results/HitTestResult.cs | 41 +-
.../Scripts/geoblazorProto.ts | 3 +
.../Serialization/EnumJsonConverters.cs | 38 +
.../Serialization/IJSStreamReferenceHelper.cs | 17 +-
.../Serialization/JsSyncManager.cs | 96 +-
.../ProtobufSerializationBase.cs | 77 --
.../dymaptic.GeoBlazor.Core.csproj | 16 +-
.../ArcGISVersionInfoSourceGeneratorTests.cs | 10 +-
.../CoreSourceGeneratorTests.cs | 208 +++++
.../ESBuildLauncherTests.cs | 180 ----
.../Utils/RoslynUtility.cs | 55 ++
...eoBlazor.Core.SourceGenerator.Tests.csproj | 25 +-
.../Components/FeatureLayerViewTests.razor | 4 +-
.../Components/GeometryEngineTests.cs | 400 +++++---
.../MapComponentTests.cs | 8 +-
.../SerializationUnitTests.cs | 15 +-
.../Components/App.razor | 16 +-
.../Program.cs | 14 +-
.../Properties/launchSettings.json | 2 +-
162 files changed, 5927 insertions(+), 2418 deletions(-)
create mode 100644 Directory.Build.targets
create mode 100644 src/dymaptic.GeoBlazor.Core.SourceGenerator/Properties/launchSettings.json
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshComponent.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshComponent.gb.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshGeoreferencedVertexSpace.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshLocalVertexSpace.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshMaterial.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshMaterial.gb.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshMaterialMetallicRoughness.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshMaterialMetallicRoughness.gb.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshTexture.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshTextureTransform.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshTextureTransform.gb.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshTransform.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshTransform.gb.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshVertexAttributes.cs
create mode 100644 src/dymaptic.GeoBlazor.Core/Components/MeshVertexAttributes.gb.cs
rename src/dymaptic.GeoBlazor.Core/Enums/{Shading.cs => MeshShading.cs} (88%)
rename src/dymaptic.GeoBlazor.Core/Enums/{Horizontal.cs => WrapMode.cs} (74%)
create mode 100644 src/dymaptic.GeoBlazor.Core/Interfaces/IMediaInfoValue.cs
delete mode 100644 src/dymaptic.GeoBlazor.Core/Model/SeparableWrapModes.gb.cs
delete mode 100644 src/dymaptic.GeoBlazor.Core/Serialization/ProtobufSerializationBase.cs
create mode 100644 test/dymaptic.GeoBlazor.Core.SourceGenerator.Tests/CoreSourceGeneratorTests.cs
delete mode 100644 test/dymaptic.GeoBlazor.Core.SourceGenerator.Tests/ESBuildLauncherTests.cs
create mode 100644 test/dymaptic.GeoBlazor.Core.SourceGenerator.Tests/Utils/RoslynUtility.cs
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 000000000..e87e93a45
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/esBuildWaitForCompletion.ps1 b/esBuildWaitForCompletion.ps1
index 370398507..c782fe43e 100644
--- a/esBuildWaitForCompletion.ps1
+++ b/esBuildWaitForCompletion.ps1
@@ -1,30 +1,21 @@
# PowerShell
-param([string][Alias("c")]$Configuration = "Debug",
- [switch]$Pro)
+param([string][Alias("c")]$Configuration = "Debug")
-if ($Pro) {
- $RootDir = Join-Path -Path $PSScriptRoot "..\src\dymaptic.GeoBlazor.Pro"
-} else {
- $RootDir = Join-Path -Path $PSScriptRoot "src\dymaptic.GeoBlazor.Core"
-}
-
-$LockFilePath = Join-Path -Path $RootDir "esBuild.$Configuration.lock"
+$CoreRootDir = Join-Path -Path $PSScriptRoot "src\dymaptic.GeoBlazor.Core"
+$ProRootDir = Join-Path -Path $PSScriptRoot "..\src\dymaptic.GeoBlazor.Pro"
+$CoreLockFilePath = Join-Path -Path $CoreRootDir "esBuild.$Configuration.lock"
+$ProLockFilePath = Join-Path -Path $ProRootDir "esBuild.$Configuration.lock"
Write-Host "Waiting for lock file:" $LockFilePath
-if (Test-Path -Path $LockFilePath) {
+if ((Test-Path -Path $CoreLockFilePath) -or (Test-Path -Path $ProLockFilePath)) {
Write-Host "Lock file found. Waiting for release."
} else {
- Start-Sleep -Seconds 1
- if (Test-Path -Path $LockFilePath) {
- Write-Host "Lock file found. Waiting for release."
- } else {
- Write-Host "No lock file found. Exiting."
- return 0
- }
+ Write-Host "No lock file found. Exiting."
+ return 0
}
-while (Test-Path -Path $LockFilePath) {
+while ((Test-Path -Path $CoreLockFilePath) -or (Test-Path -Path $ProLockFilePath)) {
Start-Sleep -Seconds 1
Write-Host -NoNewline "."
}
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth.Client/dymaptic.GeoBlazor.Core.Sample.OAuth.Client.csproj b/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth.Client/dymaptic.GeoBlazor.Core.Sample.OAuth.Client.csproj
index 3069e457d..b975e17ec 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth.Client/dymaptic.GeoBlazor.Core.Sample.OAuth.Client.csproj
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth.Client/dymaptic.GeoBlazor.Core.Sample.OAuth.Client.csproj
@@ -2,11 +2,8 @@
net9.0
- enable
- enable
true
Default
- true
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/Components/App.razor b/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/Components/App.razor
index 7e62d9074..0ac0ea974 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/Components/App.razor
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/Components/App.razor
@@ -5,24 +5,11 @@
- @{
-#if ENABLE_COMPRESSION
- }
- @{
-#else
- }
-
-
-
-
- @{
-#endif
- }
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/Program.cs b/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/Program.cs
index f4ef327f0..376a37a91 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/Program.cs
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/Program.cs
@@ -30,11 +30,8 @@
app.UseAntiforgery();
-#if ENABLE_COMPRESSION
-app.MapStaticAssets();
-#else
app.UseStaticFiles();
-#endif
+app.MapStaticAssets();
app.MapRazorComponents()
.AddInteractiveServerRenderMode()
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth.csproj b/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth.csproj
index 7c841b53f..3ff1fc065 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth.csproj
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth/dymaptic.GeoBlazor.Core.Sample.OAuth.csproj
@@ -2,8 +2,6 @@
net9.0
- enable
- enable
aspnet-dymaptic.GeoBlazor.Core.Sample.OAuth-881b5a42-0b71-4c8c-9901-8d12693bd109
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/HitTests.razor b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/HitTests.razor
index 4187d614a..d82effc2e 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/HitTests.razor
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/HitTests.razor
@@ -64,7 +64,7 @@
{
HitTestOptions options = new()
{
- IncludeByGeoBlazorId = new[] { _hurricaneLayer!.Id }
+ IncludeByGeoBlazorId = [_hurricaneLayer!.Id]
};
HitTestResult result = await _mapView!.HitTest(pointerEvent, options);
Graphic? graphic = result.Results.OfType().FirstOrDefault()?.Graphic;
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/ManyGraphics.razor b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/ManyGraphics.razor
index 1caf501aa..4784210d9 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/ManyGraphics.razor
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/ManyGraphics.razor
@@ -52,7 +52,7 @@
{
if (firstRender)
{
- _chunkSize = _view?.IsMaui == true ? 100 : 200;
+ _chunkSize = IsMaui ? 100 : 200;
}
}
@@ -178,4 +178,5 @@
private string _geometryType = "Point";
private readonly List _graphics = new();
private bool _generating;
+ private bool IsMaui => _view?.JsRuntime!.GetType().Name.Contains("WebView") ?? false;
}
\ No newline at end of file
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/ServerSideQueries.razor b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/ServerSideQueries.razor
index c1c7751c6..8f5dfad64 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/ServerSideQueries.razor
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/ServerSideQueries.razor
@@ -11,10 +11,9 @@
+ OnLayerViewCreate="OnLayerViewCreate"
+ Class="map-view">
@@ -29,7 +28,7 @@
Ymin="4536523.6511999965">
-
+
@@ -50,68 +49,55 @@
-
@code {
+
+ [Inject]
+ public required IJSRuntime JsRuntime { get; set; }
private async Task OnLayerViewCreate(LayerViewCreateEvent createEvent)
{
if (createEvent.Layer?.Id == _featureLayer?.Id)
{
- PopupTemplate popupTemplate = await _featureLayer!.CreatePopupTemplate();
- await _featureLayer!.SetPopupTemplate(popupTemplate);
await _mapView!.SetExtent(_featureLayer!.FullExtent!);
}
}
private async Task OnClick(ClickEvent clickEvent)
{
- var query = new Query
- {
- Geometry = clickEvent.MapPoint,
- Distance = Distance,
- Units = Unit,
- SpatialRelationship = SpatialRelationship.Intersects,
- ReturnGeometry = false,
- ReturnQueryGeometry = true,
- OutFields = new HashSet { "*" }
- };
+ Query query = await _featureLayer!.CreateQuery();
+ query.Geometry = clickEvent.MapPoint;
+ query.Distance = Distance;
+ query.Units = Unit;
+ query.SpatialRelationship = SpatialRelationship.Intersects;
+ query.ReturnGeometry = true;
+ query.ReturnQueryGeometry = true;
+ query.OutFields = ["*"];
+
FeatureSet result = (await _featureLayer!.QueryFeatures(query))!;
- await _pointGraphic.SetGeometry(clickEvent.MapPoint);
- if (!_mapView!.Graphics.Contains(_pointGraphic))
- {
- await _mapView.AddGraphic(_pointGraphic);
- }
+ await _mapView!.ClearGraphics();
+ Graphic pointGraphic = new(clickEvent.MapPoint, _markerSymbol);
- if (result.QueryGeometry is not null)
+ if (_queryType == "distance")
{
- await _bufferGraphic.SetGeometry(result.QueryGeometry);
- if (!_mapView.Graphics.Contains(_bufferGraphic))
- {
- await _mapView.AddGraphic(_bufferGraphic);
- }
+ Graphic buffer = new(result.QueryGeometry, _bufferSymbol);
+ await _mapView.AddGraphics([pointGraphic, buffer]);
}
- else if (_mapView.Graphics.Contains(_bufferGraphic))
+ else
{
- await _mapView.RemoveGraphic(_bufferGraphic);
+ await _mapView.AddGraphic(pointGraphic);
}
- await _mapView.OpenPopup(new PopupOpenOptions
- {
- Location = clickEvent.MapPoint,
- Features = result.Features,
- FeatureMenuOpen = true
- });
+ await _popup!.SetFeatures(result.Features);
}
private double? Distance => _queryType == "distance" ? 0.5 : null;
private QueryUnits? Unit => _queryType == "distance" ? QueryUnits.Miles : null;
private MapView? _mapView;
+ private PopupWidget? _popup;
private FeatureLayer? _featureLayer;
- private readonly Graphic _pointGraphic = new(symbol: new SimpleMarkerSymbol(
- new Outline(new MapColor(255, 255, 255), 1),
- new MapColor(0, 0, 139)));
- private readonly Graphic _bufferGraphic = new(symbol: new SimpleFillSymbol(
- new Outline(new MapColor(255, 255, 255), 1.5),
- new MapColor(173, 216, 230, 0.2)));
+ private readonly SimpleMarkerSymbol _markerSymbol = new(new Outline(new MapColor(255, 255, 255), 1),
+ new MapColor(0, 0, 139));
+ private readonly SimpleFillSymbol _bufferSymbol = new(new Outline(new MapColor(255, 255, 255), 1.5),
+ new MapColor(173, 216, 230, 0.2));
private string? _queryType;
}
\ No newline at end of file
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/Tests.razor b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/Tests.razor
index 4690fc13a..083e1309a 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/Tests.razor
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/Tests.razor
@@ -148,29 +148,27 @@
}
private MapView? _view;
- private readonly FeatureLayer _localFeatureLayer = new(source: new[]
- {
- new Graphic(new Point(11.967162, 49.201448),
+ private readonly FeatureLayer _localFeatureLayer = new(source:
+ [
+ new Graphic(new Point(11.967162, 49.201448),
new SimpleMarkerSymbol(new Outline(new MapColor("white")),
new MapColor("red"), 6))
- },
+ ],
objectIdField: "OBJECTID");
private readonly FeatureLayer _remoteFeatureLayer =
new("https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/weather_stations_010417/FeatureServer/0");
- private readonly GraphicsLayer _graphicsLayer = new(new[]
- {
+ private readonly GraphicsLayer _graphicsLayer = new([
new Graphic(new Point(11.888650, 52.451825),
new SimpleMarkerSymbol(new Outline(new MapColor("white")),
new MapColor("green"), 6)),
- new Graphic(new Polyline(new[]
- {
- new MapPath(new MapPoint(11, 52),
+ new Graphic(new Polyline([
+ new MapPath(new MapPoint(11, 52),
new MapPoint(11.5, 53),
new MapPoint(12, 55),
new MapPoint(10, 55),
new MapPoint(10.5, 51),
new MapPoint(11, 56))
- }),
+ ]),
new SimpleLineSymbol(new MapColor("blue"), 2)),
new Graphic(new Point(7.274721, 59.614991),
new PictureMarkerSymbol("https://static.arcgis.com/images/Symbols/Shapes/BluePin1LargeB.png",
@@ -178,7 +176,7 @@
new Graphic(new Point(29.437639, 55.469513),
new TextSymbol("Hello World", new MapColor("red"),
new MapColor("yellow"), 12))
- });
+ ]);
private async void On3Click(ClickEvent clickEvent)
{
@@ -206,8 +204,8 @@
private bool _map3Rendered;
private bool _showGraphicsMarkupLayer;
private readonly Random _random = new();
- private readonly List _lats = new() { 49.201448, 52.451825, 59.614991, 55.469513 };
- private readonly List _longs = new() { 11.967162, 11.888650, 7.274721, 29.437639 };
+ private readonly List _lats = [49.201448, 52.451825, 59.614991, 55.469513];
+ private readonly List _longs = [11.967162, 11.888650, 7.274721, 29.437639];
private MapView? _view3;
private int _graphicsCount = 1;
}
\ No newline at end of file
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/WFSLayers.razor b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/WFSLayers.razor
index bcf3d1ca6..8a6faf149 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/WFSLayers.razor
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Pages/WFSLayers.razor
@@ -4,22 +4,28 @@
To create a WFSLayer, all you need is the URL to a WFS service that supports WFS 2.0.0 and has GeoJSON output format enabled. Optionally, you can set the name to the FeatureType you want to access in the service. If no name is provided, the layer will default to the first FeatureType in the service.
+
+ Source: Office for National Statistics licensed under the Open Government Licence v.3.0
+
+
+ Contains OS data © Crown copyright and database right @DateTime.Now.Year
+
+ Longitude="-2"
+ Latitude="53"
+ Zoom="5">
-
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor.cs b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor.cs
index 99f584103..b9a85f5e4 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor.cs
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/Shared/NavMenu.razor.cs
@@ -4,7 +4,7 @@
namespace dymaptic.GeoBlazor.Core.Sample.Shared.Shared;
-public partial class NavMenu: IDisposable
+public partial class NavMenu
{
[Inject]
public required IJSRuntime JsRuntime { get; set; }
@@ -21,17 +21,6 @@ public partial class NavMenu: IDisposable
protected IEnumerable FilteredPages => string.IsNullOrWhiteSpace(SearchText)
? Pages
: Pages.Where(p => p.Title.Contains(SearchText, StringComparison.OrdinalIgnoreCase));
-
- public void Dispose()
- {
- _dotNetRef?.Dispose();
- }
-
- [JSInvokable]
- public void OnScroll(double scrollTop)
- {
- _scrollTop = scrollTop;
- }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
@@ -47,9 +36,12 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
string currentPage = NavigationManager
.ToBaseRelativePath(NavigationManager.Uri)
.Replace("source-code/", "");
- await JsRuntime.InvokeVoidAsync("scrollToNav", currentPage);
- _dotNetRef = DotNetObjectReference.Create(this);
- await JsRuntime.InvokeVoidAsync("trackScrollPosition", Navbar, _dotNetRef);
+
+ if (currentPage != string.Empty)
+ {
+ await JsRuntime.InvokeVoidAsync("scrollToNav", currentPage);
+ }
+
StateHasChanged();
}
@@ -89,8 +81,6 @@ await InvokeAsync(async () =>
protected virtual bool CollapseNavMenu { get; set; } = true;
protected ElementReference? Navbar;
- private DotNetObjectReference? _dotNetRef;
- private double _scrollTop;
public virtual PageLink[] Pages =>
[
new("", "Home", "oi-home"),
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/wwwroot/functions.js b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/wwwroot/functions.js
index ee6861ed6..6615257b5 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.Shared/wwwroot/functions.js
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.Shared/wwwroot/functions.js
@@ -1,33 +1,4 @@
-let navbarRef;
-let navbar;
-
-window.trackScrollPosition = (navbarElem, dotNetRef) => {
- navbar = navbarElem;
- navbarRef = dotNetRef;
- navbar.addEventListener('scroll', onScroll);
- // Initial call to set the position
- _ = onScroll();
-}
-
-window.removeScrollTracking = () => {
- if (navbar) {
- navbar.removeEventListener('scroll', onScroll);
- navbar = null;
- }
- navbarRef = null;
-}
-
-window.scrollToPosition = (position) => {
- if (navbar) {
- navbar.scrollTop = position;
- }
-}
-
-async function onScroll() {
- await navbarRef.invokeMethodAsync('OnScroll', navbar.scrollTop);
-}
-
-window.scrollToNav = (page) => {
+window.scrollToNav = (page) => {
let navItems = document.getElementsByTagName('a');
let navItem = Array.from(navItems).find(i => i.href.endsWith(page));
if (navigator.userAgent.indexOf('Firefox') === -1) {
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.Client/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.Client.csproj b/samples/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.Client/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.Client.csproj
index 2a264af04..30734100f 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.Client/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.Client.csproj
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.Client/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.Client.csproj
@@ -2,8 +2,6 @@
net9.0
- enable
- enable
true
Default
diff --git a/samples/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.csproj b/samples/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.csproj
index bcc4c0109..7823798f2 100644
--- a/samples/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.csproj
+++ b/samples/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh/dymaptic.GeoBlazor.Core.Sample.TokenRefresh.csproj
@@ -2,8 +2,6 @@
net9.0
- enable
- enable
09852c49-58ad-4029-956b-1e18661fd6b3
diff --git a/src/.editorconfig b/src/.editorconfig
index b499c6efd..16ef9aec1 100644
--- a/src/.editorconfig
+++ b/src/.editorconfig
@@ -130,7 +130,7 @@ csharp_style_prefer_readonly_struct_member = true
csharp_prefer_braces = true
csharp_prefer_simple_using_statement = true
csharp_prefer_system_threading_lock = true
-csharp_style_namespace_declarations = block_scoped
+csharp_style_namespace_declarations = file_scoped
csharp_style_prefer_method_group_conversion = true
csharp_style_prefer_primary_constructors = true
csharp_style_prefer_simple_property_accessors = true
diff --git a/src/dymaptic.GeoBlazor.Core.SourceGenerator/Properties/launchSettings.json b/src/dymaptic.GeoBlazor.Core.SourceGenerator/Properties/launchSettings.json
new file mode 100644
index 000000000..bfb3c206b
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core.SourceGenerator/Properties/launchSettings.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "Generators": {
+ "commandName": "DebugRoslynComponent",
+ "targetProject": "../../test/dymaptic.GeoBlazor.Core.SourceGenerator.Tests/dymaptic.GeoBlazor.Core.SourceGenerator.Tests.csproj"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core.SourceGenerator/ProtobufSourceGenerator.cs b/src/dymaptic.GeoBlazor.Core.SourceGenerator/ProtobufSourceGenerator.cs
index 40abeecf1..fbdf13f9f 100644
--- a/src/dymaptic.GeoBlazor.Core.SourceGenerator/ProtobufSourceGenerator.cs
+++ b/src/dymaptic.GeoBlazor.Core.SourceGenerator/ProtobufSourceGenerator.cs
@@ -51,39 +51,40 @@ private void FilesChanged(SourceProductionContext context,
((ImmutableArray Types, string? ProjectDirectory) Data,
Compilation Compilation) pipeline)
{
- // Skip if not running from the Core project
if (pipeline.Compilation.AssemblyName != "dymaptic.GeoBlazor.Core")
- {
- return;
- }
-
- // Skip source generation if the project path is not available
- if (string.IsNullOrEmpty(pipeline.Data.ProjectDirectory))
{
ProcessHelper.Log(nameof(ProtobufSourceGenerator),
- "CoreProjectPath not set. Skipping protobuf source generation.",
- DiagnosticSeverity.Warning,
+ $"Run from project {pipeline.Compilation.AssemblyName}.",
+ DiagnosticSeverity.Info,
context);
- return;
+
+ _isTest = true;
}
- // Log that protobuf types were found (infrastructure ready for future implementation)
+ _corePath = pipeline.Data.ProjectDirectory;
+
+ ProcessHelper.Log(nameof(ProtobufSourceGenerator),
+ "Source Generation triggered.",
+ DiagnosticSeverity.Info,
+ context);
+
if (pipeline.Data.Types.Length > 0)
{
- ProcessHelper.Log(nameof(ProtobufSourceGenerator),
- $"Found {pipeline.Data.Types.Length} protobuf-serializable types.",
- DiagnosticSeverity.Info,
- context);
+ var protoDefinitions = ProtobufDefinitionsGenerator
+ .UpdateProtobufDefinitions(context, pipeline.Data.Types, _corePath!);
+
+ context.CancellationToken.ThrowIfCancellationRequested();
- // TODO: Generate protobuf serialization records and registration code.
- // This will include:
- // 1. Generating *SerializationRecord classes for each protobuf-attributed type
- // 2. Generating ToProtobuf()/FromProtobuf() extension methods
- // 3. Generating JsSyncManager registration code for ProtoContractTypes dictionary
- // 4. Copying .proto definitions to TypeScript for JS-side deserialization
+ SerializationGenerator.GenerateSerializationDataClass(context,
+ pipeline.Data.Types, protoDefinitions, false,
+ _isTest);
+
+ context.CancellationToken.ThrowIfCancellationRequested();
}
}
+ private static string? _corePath;
+ private static bool _isTest;
private const string ProtoContractAttribute = "ProtoContract";
private const string ProtoSerializableAttribute = "ProtobufSerializable";
private const string SerializedMethodAttributeName = "SerializedMethod";
diff --git a/src/dymaptic.GeoBlazor.Core.sln b/src/dymaptic.GeoBlazor.Core.sln
index 94fea22b8..d6770235b 100644
--- a/src/dymaptic.GeoBlazor.Core.sln
+++ b/src/dymaptic.GeoBlazor.Core.sln
@@ -42,6 +42,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dymaptic.GeoBlazor.Core.Sam
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dymaptic.GeoBlazor.Core.Analyzers", "dymaptic.GeoBlazor.Core.Analyzers\dymaptic.GeoBlazor.Core.Analyzers.csproj", "{468F9CE4-A24F-4EE0-9C5B-2AF88A369C30}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dymaptic.GeoBlazor.Core.SourceGenerator.Shared", "dymaptic.GeoBlazor.Core.SourceGenerator.Shared\dymaptic.GeoBlazor.Core.SourceGenerator.Shared.csproj", "{8FDFC824-2365-4467-9326-DFDFF6D6B775}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -258,6 +260,18 @@ Global
{468F9CE4-A24F-4EE0-9C5B-2AF88A369C30}.Release|x64.Build.0 = Release|Any CPU
{468F9CE4-A24F-4EE0-9C5B-2AF88A369C30}.Release|x86.ActiveCfg = Release|Any CPU
{468F9CE4-A24F-4EE0-9C5B-2AF88A369C30}.Release|x86.Build.0 = Release|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Debug|x64.Build.0 = Debug|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Debug|x86.Build.0 = Debug|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Release|x64.ActiveCfg = Release|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Release|x64.Build.0 = Release|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Release|x86.ActiveCfg = Release|Any CPU
+ {8FDFC824-2365-4467-9326-DFDFF6D6B775}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ActionBase.cs b/src/dymaptic.GeoBlazor.Core/Components/ActionBase.cs
index 01b7613e5..8bdff5798 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ActionBase.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ActionBase.cs
@@ -2,7 +2,8 @@ namespace dymaptic.GeoBlazor.Core.Components;
[JsonConverter(typeof(ActionBaseConverter))]
[CodeGenerationIgnore]
-public abstract partial class ActionBase : MapComponent
+[ProtobufSerializable]
+public abstract partial class ActionBase : MapComponent, IProtobufSerializable
{
///
/// The title of the action.
@@ -65,92 +66,8 @@ public async Task OnJsTriggerAction(PopupTriggerActionEvent triggerActionEvent)
///
public abstract string Type { get; }
- internal abstract ActionBaseSerializationRecord ToSerializationRecord();
-}
-
-[ProtoContract(Name = "Action")]
-internal record ActionBaseSerializationRecord : MapComponentSerializationRecord
-{
- public ActionBaseSerializationRecord()
- {
- }
-
- public ActionBaseSerializationRecord(string Id,
- string Type,
- string? Title,
- string? ClassName,
- bool? Active,
- bool? Disabled,
- bool? Visible,
- string? ActionId)
- {
- this.Id = Id;
- this.Type = Type;
- this.Title = Title;
- this.ClassName = ClassName;
- this.Active = Active;
- this.Disabled = Disabled;
- this.Visible = Visible;
- this.ActionId = ActionId;
- }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(1)]
- public string Type { get; init; } = string.Empty;
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(2)]
- public string? Title { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(3)]
- public string? ClassName { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(4)]
- public bool? Active { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(5)]
- public bool? Disabled { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(6)]
- public bool? Visible { get; init; }
-
- [ProtoMember(7)]
- public string? Id { get; init; }
-
- [ProtoMember(8)]
- public string? Image { get; init; }
-
- [ProtoMember(9)]
- public bool? Value { get; init; }
-
- [ProtoMember(10)]
- public string? ActionId { get; init; }
-
- public ActionBase FromSerializationRecord()
- {
- Guid id = Guid.NewGuid();
- if (Guid.TryParse(Id, out Guid guidId))
- {
- id = guidId;
- }
-
- return Type switch
- {
- "button" => new ActionButton(Title, Image, ActionId, null, ClassName, Active, Disabled, Visible)
- {
- Id = id
- },
- "toggle" => new ActionToggle(Title, ActionId, null, Value, Active, Disabled, Visible)
- {
- Id = id
- },
- _ => throw new NotSupportedException()
- };
- }
+ ///
+ public abstract ActionBaseSerializationRecord ToProtobuf();
}
internal class ActionBaseConverter : JsonConverter
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ActionButton.cs b/src/dymaptic.GeoBlazor.Core/Components/ActionButton.cs
index 3e67715c3..ac748e136 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ActionButton.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ActionButton.cs
@@ -1,10 +1,9 @@
namespace dymaptic.GeoBlazor.Core.Components;
[CodeGenerationIgnore]
+[ProtobufSerializable]
public partial class ActionButton : ActionBase
{
-
-
///
public override string Type => "button";
@@ -15,7 +14,8 @@ public partial class ActionButton : ActionBase
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? Image { get; set; }
- internal override ActionBaseSerializationRecord ToSerializationRecord()
+ ///
+ public override ActionBaseSerializationRecord ToProtobuf()
{
return new ActionBaseSerializationRecord(Id.ToString(), Type, Title, ClassName, Active, Disabled, Visible, ActionId)
{
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ActionToggle.cs b/src/dymaptic.GeoBlazor.Core/Components/ActionToggle.cs
index 1d3314604..a3b94f848 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ActionToggle.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ActionToggle.cs
@@ -1,10 +1,9 @@
namespace dymaptic.GeoBlazor.Core.Components;
[CodeGenerationIgnore]
+[ProtobufSerializable]
public partial class ActionToggle : ActionBase
{
-
-
///
public override string Type => "toggle";
@@ -15,7 +14,8 @@ public partial class ActionToggle : ActionBase
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public bool? Value { get; set; }
- internal override ActionBaseSerializationRecord ToSerializationRecord()
+ ///
+ public override ActionBaseSerializationRecord ToProtobuf()
{
return new ActionBaseSerializationRecord(Id.ToString(), Type, Title, null, Active, Disabled, Visible, ActionId)
{
diff --git a/src/dymaptic.GeoBlazor.Core/Components/BarChartMediaInfo.cs b/src/dymaptic.GeoBlazor.Core/Components/BarChartMediaInfo.cs
index 94f144631..a1222d8fc 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/BarChartMediaInfo.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/BarChartMediaInfo.cs
@@ -1,21 +1,20 @@
namespace dymaptic.GeoBlazor.Core.Components;
+[ProtobufSerializable]
public partial class BarChartMediaInfo : MediaInfo
{
-
-
///
public override string Type => "bar-chart";
-
- internal override MediaInfoSerializationRecord ToSerializationRecord()
+ ///
+ public override MediaInfoSerializationRecord ToProtobuf()
{
return new MediaInfoSerializationRecord(Id.ToString(), "bar-chart")
{
AltText = AltText,
Caption = Caption,
Title = Title,
- Value = Value?.ToSerializationRecord()
+ Value = Value?.ToProtobuf()
};
}
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/BookmarksViewModel.cs b/src/dymaptic.GeoBlazor.Core/Components/BookmarksViewModel.cs
index 0c0f142b9..b7826fb6e 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/BookmarksViewModel.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/BookmarksViewModel.cs
@@ -22,7 +22,7 @@ public partial class BookmarksViewModel : MapComponent, IViewModel
[CodeGenerationIgnore]
public async Task OnJsGoToOverride(IJSStreamReference jsStreamRef)
{
- GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReference();
+ GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (GoToOverride is not null && goToParameters != null)
{
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ChartMediaInfoValue.cs b/src/dymaptic.GeoBlazor.Core/Components/ChartMediaInfoValue.cs
index 41c5014bc..f4993d96e 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ChartMediaInfoValue.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ChartMediaInfoValue.cs
@@ -1,9 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components;
-public partial class ChartMediaInfoValue : MapComponent
+[ProtobufSerializable]
+public partial class ChartMediaInfoValue : MapComponent, IMediaInfoValue
{
-
-
///
/// A string containing the name of a field. The values of all fields in the chart will be normalized (divided) by the value of this field.
///
@@ -17,79 +16,11 @@ public partial class ChartMediaInfoValue : MapComponent
[Parameter]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? TooltipField { get; set; }
-
-
- internal ChartMediaInfoValueSerializationRecord ToSerializationRecord()
- {
- return new ChartMediaInfoValueSerializationRecord(Id.ToString(), Fields, NormalizeField, TooltipField,
- Series?.Select(s => s.ToSerializationRecord()));
- }
-}
-
-[ProtoContract(Name = "ChartMediaInfoValue")]
-internal record ChartMediaInfoValueSerializationRecord : MapComponentSerializationRecord
-{
- public ChartMediaInfoValueSerializationRecord()
- {
- }
-
- public ChartMediaInfoValueSerializationRecord(string Id, IEnumerable? Fields = null,
- string? NormalizeField = null, string? TooltipField = null,
- IEnumerable? Series = null, string? LinkURL = null,
- string? SourceURL = null)
- {
- this.Id = Id;
- this.Fields = Fields;
- this.NormalizeField = NormalizeField;
- this.TooltipField = TooltipField;
- this.Series = Series;
- this.LinkURL = LinkURL;
- this.SourceURL = SourceURL;
- }
-
- public object FromSerializationRecord()
+
+ ///
+ public MediaInfoValueSerializationRecord ToProtobuf()
{
- Guid id = Guid.NewGuid();
- if (Guid.TryParse(Id, out Guid guid))
- {
- id = guid;
- }
-
- if (LinkURL is not null || SourceURL is not null)
- {
- return new ImageMediaInfoValue(LinkURL, SourceURL) { Id = id };
- }
-
- return new ChartMediaInfoValue(Fields?.ToArray(), NormalizeField, TooltipField,
- Series?.Select(s => s.FromSerializationRecord()).ToArray())
- {
- Id = id
- };
+ return new MediaInfoValueSerializationRecord(Id.ToString(), Fields, NormalizeField, TooltipField,
+ Series?.Select(s => s.ToProtobuf()));
}
-
- [ProtoMember(1)]
- public IEnumerable? Fields { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(2)]
- public string? NormalizeField { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(3)]
- public string? TooltipField { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(4)]
- public IEnumerable? Series { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(5)]
- public string? LinkURL { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(6)]
- public string? SourceURL { get; init; }
-
- [ProtoMember(7)]
- public string? Id { get; init; }
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ChartMediaInfoValueSeries.cs b/src/dymaptic.GeoBlazor.Core/Components/ChartMediaInfoValueSeries.cs
index 791b8543c..a57ddab4c 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ChartMediaInfoValueSeries.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ChartMediaInfoValueSeries.cs
@@ -1,6 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components;
-public partial class ChartMediaInfoValueSeries : MapComponent
+[ProtobufSerializable]
+public partial class ChartMediaInfoValueSeries : MapComponent,
+ IProtobufSerializable
{
@@ -24,50 +26,10 @@ public partial class ChartMediaInfoValueSeries : MapComponent
[Parameter]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public double? Value { get; set; }
-
- internal ChartMediaInfoValueSeriesSerializationRecord ToSerializationRecord()
+
+ ///
+ public ChartMediaInfoValueSeriesSerializationRecord ToProtobuf()
{
return new ChartMediaInfoValueSeriesSerializationRecord(Id.ToString(), FieldName, Tooltip, Value);
}
-}
-
-[ProtoContract(Name = "ChartMediaInfoValueSeries")]
-internal record ChartMediaInfoValueSeriesSerializationRecord : MapComponentSerializationRecord
-{
- public ChartMediaInfoValueSeriesSerializationRecord()
- {
- }
-
- public ChartMediaInfoValueSeriesSerializationRecord(string Id, string? FieldName, string? Tooltip, double? Value)
- {
- this.Id = Id;
- this.FieldName = FieldName;
- this.Tooltip = Tooltip;
- this.Value = Value;
- }
-
- public ChartMediaInfoValueSeries FromSerializationRecord()
- {
- Guid id = Guid.NewGuid();
- if (Guid.TryParse(Id, out Guid guid))
- {
- id = guid;
- }
- return new ChartMediaInfoValueSeries(FieldName, Tooltip, Value) { Id = id };
- }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(1)]
- public string? FieldName { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(2)]
- public string? Tooltip { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(3)]
- public double? Value { get; init; }
-
- [ProtoMember(4)]
- public string? Id { get; init; }
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Circle.cs b/src/dymaptic.GeoBlazor.Core/Components/Circle.cs
index ca78ef636..90c0e9116 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Circle.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Circle.cs
@@ -1,5 +1,6 @@
namespace dymaptic.GeoBlazor.Core.Components;
+[ProtobufSerializable]
public partial class Circle
{
// Add custom code to this file to override generated code
@@ -116,18 +117,19 @@ public Circle(
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[CodeGenerationIgnore]
public int? NumberOfPoints { get; set; }
-
- internal override GeometrySerializationRecord ToSerializationRecord()
+
+ ///
+ public override GeometrySerializationRecord ToProtobuf()
{
return new GeometrySerializationRecord(Id.ToString(), Type.ToString().ToKebabCase(),
- Extent?.ToSerializationRecord(),
- SpatialReference?.ToSerializationRecord())
+ Extent?.ToProtobuf(),
+ SpatialReference?.ToProtobuf())
{
- Rings = Rings.Select(p => p.ToSerializationRecord()).ToArray(),
+ Rings = Rings.Select(p => p.ToProtobuf()).ToArray(),
HasM = HasM,
HasZ = HasZ,
- Centroid = Centroid?.ToSerializationRecord(),
- Center = Center?.ToSerializationRecord(),
+ Centroid = Centroid?.ToProtobuf(),
+ Center = Center?.ToProtobuf(),
Geodesic = Geodesic,
NumberOfPoints = NumberOfPoints,
Radius = Radius,
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ColumnChartMediaInfo.cs b/src/dymaptic.GeoBlazor.Core/Components/ColumnChartMediaInfo.cs
index d5c34d31e..e9b9a5c15 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ColumnChartMediaInfo.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ColumnChartMediaInfo.cs
@@ -1,21 +1,20 @@
namespace dymaptic.GeoBlazor.Core.Components;
+[ProtobufSerializable]
public partial class ColumnChartMediaInfo : MediaInfo
{
-
-
///
public override string Type => "column-chart";
-
- internal override MediaInfoSerializationRecord ToSerializationRecord()
+ ///
+ public override MediaInfoSerializationRecord ToProtobuf()
{
return new MediaInfoSerializationRecord(Id.ToString(), "column-chart")
{
AltText = AltText,
Caption = Caption,
Title = Title,
- Value = Value?.ToSerializationRecord()
+ Value = Value?.ToProtobuf()
};
}
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/CompassViewModel.cs b/src/dymaptic.GeoBlazor.Core/Components/CompassViewModel.cs
index 935cd78ba..ed9094d71 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/CompassViewModel.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/CompassViewModel.cs
@@ -22,7 +22,7 @@ public partial class CompassViewModel: IViewModel
[CodeGenerationIgnore]
public async Task OnJsGoToOverride(IJSStreamReference jsStreamRef)
{
- GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReference();
+ GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (GoToOverride is not null && goToParameters is not null)
{
await GoToOverride.Invoke(goToParameters);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ElementExpressionInfo.cs b/src/dymaptic.GeoBlazor.Core/Components/ElementExpressionInfo.cs
index c2f78e6fb..e34913e9f 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ElementExpressionInfo.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ElementExpressionInfo.cs
@@ -1,36 +1,13 @@
namespace dymaptic.GeoBlazor.Core.Components;
-public partial class ElementExpressionInfo
+[ProtobufSerializable]
+public partial class ElementExpressionInfo: IProtobufSerializable
{
// Add custom code to this file to override generated code
- internal ElementExpressionInfoSerializationRecord ToSerializationRecord()
+ ///
+ public ElementExpressionInfoSerializationRecord ToProtobuf()
{
- return new ElementExpressionInfoSerializationRecord(Expression, Title);
+ return new ElementExpressionInfoSerializationRecord(Expression, Title);
}
-}
-
-[ProtoContract(Name = "ElementExpressionInfo")]
-internal record ElementExpressionInfoSerializationRecord: MapComponentSerializationRecord
-{
- public ElementExpressionInfoSerializationRecord()
- {
- }
-
- public ElementExpressionInfoSerializationRecord(string? expression, string? title)
- {
- Expression = expression;
- Title = title;
- }
-
- [ProtoMember(1)]
- public string? Expression { get; init; }
-
- [ProtoMember(2)]
- public string? Title { get; init; }
-
- public ElementExpressionInfo FromSerializationRecord()
- {
- return new ElementExpressionInfo(Expression, Title);
- }
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/FeaturesViewModel.cs b/src/dymaptic.GeoBlazor.Core/Components/FeaturesViewModel.cs
index dd34cdba1..ab91acf82 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/FeaturesViewModel.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/FeaturesViewModel.cs
@@ -21,7 +21,7 @@ public partial class FeaturesViewModel : IViewModel
[CodeGenerationIgnore]
public async Task OnJsGoToOverride(IJSStreamReference jsStreamRef)
{
- GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReference();
+ GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (GoToOverride is not null && goToParameters is not null)
{
diff --git a/src/dymaptic.GeoBlazor.Core/Components/FeaturesViewModel.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/FeaturesViewModel.gb.cs
index be012c8fd..30c75926d 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/FeaturesViewModel.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/FeaturesViewModel.gb.cs
@@ -3338,7 +3338,7 @@ public async Task OnJsTriggerAction(IJSStreamReference jsStreamRef)
return;
}
- FeaturesViewModelTriggerActionEvent? triggerActionEvent = await jsStreamRef.ReadJsStreamReference();
+ FeaturesViewModelTriggerActionEvent? triggerActionEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (triggerActionEvent is not null)
{
await OnTriggerAction.InvokeAsync(triggerActionEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/FieldInfo.cs b/src/dymaptic.GeoBlazor.Core/Components/FieldInfo.cs
index 013c1e716..4d06e1f6e 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/FieldInfo.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/FieldInfo.cs
@@ -1,9 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components;
-public partial class FieldInfo : MapComponent
+[ProtobufSerializable]
+public partial class FieldInfo : MapComponent, IProtobufSerializable
{
-
-
///
/// The field name as defined by the service or the name of an Arcade expression.
///
@@ -38,84 +37,11 @@ public partial class FieldInfo : MapComponent
[Parameter]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public StringFieldOption? StringFieldOption { get; set; }
-
-
- internal FieldInfoSerializationRecord ToSerializationRecord()
+
+ ///
+ public FieldInfoSerializationRecord ToProtobuf()
{
return new FieldInfoSerializationRecord(Id.ToString(), FieldName, Label, Tooltip,
- StringFieldOption?.ToString().ToKebabCase(), Format?.ToSerializationRecord(), IsEditable, Visible);
- }
-}
-
-[ProtoContract(Name = "FieldInfo")]
-internal record FieldInfoSerializationRecord : MapComponentSerializationRecord
-{
- public FieldInfoSerializationRecord()
- {
+ StringFieldOption?.ToString().ToKebabCase(), Format?.ToProtobuf(), IsEditable, Visible);
}
-
- public FieldInfoSerializationRecord(string Id, string? FieldName = null, string? Label = null,
- string? Tooltip = null, string? StringFieldOption = null, FieldInfoFormatSerializationRecord? Format = null,
- bool? IsEditable = null, bool? Visible = null)
- {
- this.Id = Id;
- this.FieldName = FieldName;
- this.Label = Label;
- this.Tooltip = Tooltip;
- this.StringFieldOption = StringFieldOption;
- this.Format = Format;
- this.IsEditable = IsEditable;
- this.Visible = Visible;
- }
-
- public FieldInfo FromSerializationRecord()
- {
- Guid id = Guid.NewGuid();
- if (Guid.TryParse(Id, out Guid guid))
- {
- id = guid;
- }
- StringFieldOption? sfo = StringFieldOption switch
- {
- "rich-text" => Enums.StringFieldOption.RichText,
- "text-area" => Enums.StringFieldOption.TextArea,
- "text-box" => Enums.StringFieldOption.TextBox,
- _ => null
- };
- return new FieldInfo(FieldName, Label, Tooltip, sfo, Format?.FromSerializationRecord(), IsEditable, Visible)
- {
- Id = id
- };
- }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(1)]
- public string? FieldName { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(2)]
- public string? Label { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(3)]
- public string? Tooltip { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(4)]
- public string? StringFieldOption { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(5)]
- public FieldInfoFormatSerializationRecord? Format { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(6)]
- public bool? IsEditable { get; init; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(7)]
- public bool? Visible { get; init; }
-
- [ProtoMember(8)]
- public string? Id { get; init; }
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/FieldInfoFormat.cs b/src/dymaptic.GeoBlazor.Core/Components/FieldInfoFormat.cs
index bc7cdba41..b99bb59c3 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/FieldInfoFormat.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/FieldInfoFormat.cs
@@ -1,9 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components;
-public partial class FieldInfoFormat : MapComponent
+[ProtobufSerializable]
+public partial class FieldInfoFormat : MapComponent, IProtobufSerializable
{
-
-
///
/// Used only with Number fields to specify the number of supported decimal places that should appear in popups.
///
@@ -25,7 +24,8 @@ public partial class FieldInfoFormat : MapComponent
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public DateFormat? DateFormat { get; set; }
- internal FieldInfoFormatSerializationRecord ToSerializationRecord()
+ ///
+ public FieldInfoFormatSerializationRecord ToProtobuf()
{
string? dateFormat = DateFormat switch
{
@@ -61,78 +61,4 @@ internal FieldInfoFormatSerializationRecord ToSerializationRecord()
};
return new FieldInfoFormatSerializationRecord(Id.ToString(), Places, DigitSeparator, dateFormat);
}
-}
-
-[ProtoContract(Name = "FieldInfoFormat")]
-internal record FieldInfoFormatSerializationRecord : MapComponentSerializationRecord
-{
- public FieldInfoFormatSerializationRecord()
- {
- }
-
- public FieldInfoFormatSerializationRecord(string Id,
- int? Places,
- bool? DigitSeparator,
- string? DateFormat)
- {
- this.Id = Id;
- this.Places = Places;
- this.DigitSeparator = DigitSeparator;
- this.DateFormat = DateFormat;
- }
-
- public FieldInfoFormat FromSerializationRecord()
- {
- Guid id = Guid.NewGuid();
- if (Guid.TryParse(Id, out Guid guidId))
- {
- id = guidId;
- }
- DateFormat? df = DateFormat switch
- {
- "short-date" => Enums.DateFormat.ShortDate,
- "short-date-short-time.cs" => Enums.DateFormat.ShortDateShortTime,
- "short-date-short-time-24" => Enums.DateFormat.ShortDateShortTime24,
- "short-date-long-time" => Enums.DateFormat.ShortDateLongTime,
- "short-date-long-time-24" => Enums.DateFormat.ShortDateLongTime24,
- "short-date-le" => Enums.DateFormat.ShortDateLe,
- "short-date-le-short-time" => Enums.DateFormat.ShortDateLeShortTime,
- "short-date-le-short-time-24" => Enums.DateFormat.ShortDateLeShortTime24,
- "short-date-le-long-time" => Enums.DateFormat.ShortDateLeLongTime,
- "short-date-le-long-time-24" => Enums.DateFormat.ShortDateLeLongTime24,
- "long-month-day-year" => Enums.DateFormat.LongMonthDayYear,
- "long-month-day-year-short-time" => Enums.DateFormat.LongMonthDayYearShortTime,
- "long-month-day-year-short-time-24" => Enums.DateFormat.LongMonthDayYearShortTime24,
- "long-month-day-year-long-time" => Enums.DateFormat.LongMonthDayYearLongTime,
- "long-month-day-year-long-time-24" => Enums.DateFormat.LongMonthDayYearLongTime24,
- "day-short-month-year" => Enums.DateFormat.DayShortMonthYear,
- "day-short-month-year-short-time" => Enums.DateFormat.DayShortMonthYearShortTime,
- "day-short-month-year-short-time-24" => Enums.DateFormat.DayShortMonthYearShortTime24,
- "day-short-month-year-long-time" => Enums.DateFormat.DayShortMonthYearLongTime,
- "day-short-month-year-long-time-24" => Enums.DateFormat.DayShortMonthYearLongTime24,
- "long-date" => Enums.DateFormat.LongDate,
- "long-date-short-time" => Enums.DateFormat.LongDateShortTime,
- "long-date-short-time-24" => Enums.DateFormat.LongDateShortTime24,
- "long-date-long-time" => Enums.DateFormat.LongDateLongTime,
- "long-date-long-time-24" => Enums.DateFormat.LongDateLongTime24,
- "long-month-year" => Enums.DateFormat.LongMonthYear,
- "short-month-year" => Enums.DateFormat.ShortMonthYear,
- "year" => Enums.DateFormat.Year,
- _ => null
- };
- return new FieldInfoFormat(Places, DigitSeparator, df) { Id = id };
- }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(1)]
- public int? Places { get; init; }
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(2)]
- public bool? DigitSeparator { get; init; }
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(3)]
- public string? DateFormat { get; init; }
-
- [ProtoMember(4)]
- public string? Id { get; init; }
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Extent.cs b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Extent.cs
index a3b5a7ba1..974b72fc9 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Extent.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Extent.cs
@@ -1,5 +1,6 @@
namespace dymaptic.GeoBlazor.Core.Components.Geometries;
+[ProtobufSerializable]
public partial class Extent : Geometry
{
///
@@ -131,10 +132,11 @@ public Extent Clone()
return new Extent(Xmax, Xmin, Ymax, Ymin, Zmax, Zmin, Mmax, Mmin, SpatialReference?.Clone());
}
- internal override GeometrySerializationRecord ToSerializationRecord()
+ ///
+ public override GeometrySerializationRecord ToProtobuf()
{
return new GeometrySerializationRecord(Id.ToString(), Type.ToString().ToKebabCase(), null,
- SpatialReference?.ToSerializationRecord())
+ SpatialReference?.ToProtobuf())
{
Xmax = Xmax,
Xmin = Xmin,
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Geometry.cs b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Geometry.cs
index 5425cde14..4de14fa63 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Geometry.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Geometry.cs
@@ -1,7 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components.Geometries;
[JsonConverter(typeof(GeometryConverter))]
-public abstract partial class Geometry : MapComponent
+[ProtobufSerializable]
+public abstract partial class Geometry : MapComponent, IProtobufSerializable
{
///
/// The of the geometry.
@@ -128,207 +129,7 @@ public override void ValidateRequiredChildren()
#pragma warning restore BL0005
return Extent;
}
-
- internal abstract GeometrySerializationRecord ToSerializationRecord();
-}
-
-[ProtoContract(Name = "Geometry")]
-internal record GeometrySerializationRecord : MapComponentSerializationRecord
-{
- public GeometrySerializationRecord()
- {
- }
-
- public GeometrySerializationRecord(string Id, string Type, GeometrySerializationRecord? Extent,
- SpatialReferenceSerializationRecord? SpatialReference)
- {
- this.Id = Id;
- this.Type = Type;
- this.Extent = Extent;
- this.SpatialReference = SpatialReference;
- }
-
- [ProtoMember(1)]
- public string Type { get; set; } = string.Empty;
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(2)]
- public GeometrySerializationRecord? Extent { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(3)]
- public SpatialReferenceSerializationRecord? SpatialReference { get; set; }
-
- [ProtoMember(4)]
- public double? Longitude { get; set; }
-
- [ProtoMember(5)]
- public double? Latitude { get; set; }
-
- [ProtoMember(6)]
- public double? X { get; set; }
-
- [ProtoMember(7)]
- public double? Y { get; set; }
-
- [ProtoMember(8)]
- public double? Z { get; set; }
-
- [ProtoMember(9)]
- public MapPathSerializationRecord[]? Paths { get; set; }
-
- [ProtoMember(10)]
- public MapPathSerializationRecord[]? Rings { get; set; }
-
- [ProtoMember(11)]
- public double? Xmax { get; set; }
-
- [ProtoMember(12)]
- public double? Xmin { get; set; }
-
- [ProtoMember(13)]
- public double? Ymax { get; set; }
-
- [ProtoMember(14)]
- public double? Ymin { get; set; }
-
- [ProtoMember(15)]
- public double? Zmax { get; set; }
-
- [ProtoMember(16)]
- public double? Zmin { get; set; }
-
- [ProtoMember(17)]
- public double? Mmax { get; set; }
-
- [ProtoMember(18)]
- public double? Mmin { get; set; }
-
- [ProtoMember(19)]
- public bool? HasM { get; set; }
-
- [ProtoMember(20)]
- public bool? HasZ { get; set; }
-
- [ProtoMember(21)]
- public double? M { get; set; }
-
- [ProtoMember(22)]
- public GeometrySerializationRecord? Centroid { get; set; }
-
- [ProtoMember(23)]
- public bool? IsSelfIntersecting { get; set; }
-
- [ProtoMember(24)]
- public GeometrySerializationRecord? Center { get; set; }
-
- [ProtoMember(25)]
- public bool? Geodesic { get; set; }
-
- [ProtoMember(26)]
- public int? NumberOfPoints { get; set; }
-
- [ProtoMember(27)]
- public double? Radius { get; set; }
- [ProtoMember(28)]
- public string? RadiusUnit { get; set; }
-
- [ProtoMember(29)]
- public string? Id { get; set; }
-
- ///
- /// Multipoint geometry points.
- ///
- [ProtoMember(30)]
- public MapPointSerializationRecord[]? Points { get; set; }
-
- [ProtoMember(31)]
- public bool? IsSimple { get; set; }
-
- public Geometry FromSerializationRecord()
- {
- Extent? extent = Extent?.FromSerializationRecord() as Extent;
- Guid id = Guid.NewGuid();
-
- if (Guid.TryParse(Id, out Guid guidId))
- {
- id = guidId;
- }
-
- if (Type == "multipoint")
- {
- // Multipoint is in GeoBlazor Pro assembly, so we need to use reflection to get the type
- Type? multipointType = System.Type.GetType("dymaptic.GeoBlazor.Pro.Components.Geometries.Multipoint, " +
- "dymaptic.GeoBlazor.Pro");
-
- if (multipointType is not null && multipointType.IsSubclassOf(typeof(Geometry)))
- {
- Point[]? points = Points?.Select(p =>
- {
- MapPoint mp = p.FromSerializationRecord();
-
- return new Point(x: mp[0], y: mp[1]);
- })
- .ToArray();
-
- if (Activator.CreateInstance(multipointType,
- args: [HasM, HasZ, points, SpatialReference?.FromSerializationRecord()])
- is not Geometry multipoint)
- {
- throw new InvalidOperationException(
- "Multipoint could not be created. Ensure the type is correct and the assembly is loaded.");
- }
- multipoint.Extent = extent;
- multipoint.Id = id;
- multipoint.IsSimple = IsSimple;
-
- return multipoint;
- }
- }
-
- return Type switch
- {
- "point" => new Point(Longitude, Latitude, X, Y, Z, SpatialReference?.FromSerializationRecord(), HasM, HasZ, M)
- {
- Extent = extent,
- Id = id
- },
- "polyline" => new Polyline(Paths!.Select(x => x.FromSerializationRecord()).ToArray(),
- SpatialReference?.FromSerializationRecord(), HasM, HasZ)
- {
- Extent = extent,
- Id = id,
- IsSimple = IsSimple
- },
- "polygon" => Center is not null && Radius is not null
- ? new Circle((Point)Center.FromSerializationRecord(), Radius.Value,
- Centroid?.FromSerializationRecord() as Point,
- Geodesic, HasM, HasZ, NumberOfPoints,
- RadiusUnit is null ? null : Enum.Parse(RadiusUnit),
- Rings!.Select(x => x.FromSerializationRecord()).ToArray(),
- SpatialReference?.FromSerializationRecord())
- {
- Extent = extent,
- Id = id,
- IsSimple = IsSimple
- }
- : new Polygon(Rings!.Select(x => x.FromSerializationRecord()).ToArray(),
- SpatialReference?.FromSerializationRecord(),
- Centroid?.FromSerializationRecord() as Point,
- HasM, HasZ)
- {
- Extent = extent,
- Id = id,
- IsSimple = IsSimple
- },
- "extent" => new Extent(Xmax!.Value, Xmin!.Value, Ymax!.Value, Ymin!.Value, Zmax,
- Zmin, Mmax, Mmin, SpatialReference?.FromSerializationRecord(), HasM, HasZ)
- {
- Id = id,
- IsSimple = IsSimple
- },
- _ => throw new ArgumentOutOfRangeException()
- };
- }
+ ///
+ public abstract GeometrySerializationRecord ToProtobuf();
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Geometries/OldPolyLine.cs b/src/dymaptic.GeoBlazor.Core/Components/Geometries/OldPolyLine.cs
index 076356f7b..1c4732506 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Geometries/OldPolyLine.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Geometries/OldPolyLine.cs
@@ -5,6 +5,7 @@ namespace dymaptic.GeoBlazor.Core.Components.Geometries;
///
///
[Obsolete("Renamed to Polyline (lowercase 'l') to match the JavaScript API")]
+[ProtobufSerializable]
public class PolyLine : Polyline
{
///
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Point.cs b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Point.cs
index 560b534c5..3d5870811 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Point.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Point.cs
@@ -1,9 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components.Geometries;
+[ProtobufSerializable]
public partial class Point : Geometry
{
-
-
///
/// The latitude of the point.
///
@@ -64,11 +63,12 @@ public Point Clone()
return new Point(Longitude, Latitude, X, Y, Z, SpatialReference?.Clone(), HasM, HasZ, M);
}
- internal override GeometrySerializationRecord ToSerializationRecord()
+ ///
+ public override GeometrySerializationRecord ToProtobuf()
{
return new GeometrySerializationRecord(Id.ToString(), Type.ToString().ToKebabCase(),
- Extent?.ToSerializationRecord(),
- SpatialReference?.ToSerializationRecord())
+ Extent?.ToProtobuf(),
+ SpatialReference?.ToProtobuf())
{
Longitude = Longitude,
Latitude = Latitude,
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Polygon.cs b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Polygon.cs
index 418b8b3fc..1b94b989b 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Polygon.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Polygon.cs
@@ -1,5 +1,6 @@
namespace dymaptic.GeoBlazor.Core.Components.Geometries;
+[ProtobufSerializable]
public partial class Polygon : Geometry
{
///
@@ -116,16 +117,17 @@ public Polygon Clone()
Centroid, HasM, HasZ);
}
- internal override GeometrySerializationRecord ToSerializationRecord()
+ ///
+ public override GeometrySerializationRecord ToProtobuf()
{
return new GeometrySerializationRecord(Id.ToString(), Type.ToString().ToKebabCase(),
- Extent?.ToSerializationRecord(),
- SpatialReference?.ToSerializationRecord())
+ Extent?.ToProtobuf(),
+ SpatialReference?.ToProtobuf())
{
- Rings = Rings.Select(p => p.ToSerializationRecord()).ToArray(),
+ Rings = Rings.Select(p => p.ToProtobuf()).ToArray(),
HasM = HasM,
HasZ = HasZ,
- Centroid = Centroid?.ToSerializationRecord(),
+ Centroid = Centroid?.ToProtobuf(),
#pragma warning disable CS0618 // Type or member is obsolete
IsSelfIntersecting = IsSelfIntersecting
#pragma warning restore CS0618 // Type or member is obsolete
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Polyline.cs b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Polyline.cs
index d6d656e86..6ff2ea79b 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Geometries/Polyline.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Geometries/Polyline.cs
@@ -1,9 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components.Geometries;
+[ProtobufSerializable]
public partial class Polyline : Geometry
{
-
-
///
/// An array of paths, or line segments, that make up the polyline.
///
@@ -32,13 +31,14 @@ public Polyline Clone()
HasM, HasZ);
}
- internal override GeometrySerializationRecord ToSerializationRecord()
+ ///
+ public override GeometrySerializationRecord ToProtobuf()
{
return new GeometrySerializationRecord(Id.ToString(), Type.ToString().ToKebabCase(),
- Extent?.ToSerializationRecord(),
- SpatialReference?.ToSerializationRecord())
+ Extent?.ToProtobuf(),
+ SpatialReference?.ToProtobuf())
{
- Paths = Paths.Select(p => p.ToSerializationRecord()).ToArray(),
+ Paths = Paths.Select(p => p.ToProtobuf()).ToArray(),
HasM = HasM,
HasZ = HasZ
};
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Graphic.cs b/src/dymaptic.GeoBlazor.Core/Components/Graphic.cs
index a48d2bfd3..bbf88eaad 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Graphic.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Graphic.cs
@@ -2,7 +2,8 @@
namespace dymaptic.GeoBlazor.Core.Components;
-public partial class Graphic: MapComponent, IEquatable
+[ProtobufSerializable]
+public partial class Graphic: MapComponent, IEquatable, IProtobufSerializable
{
///
/// Parameterless constructor for use as a Razor Component.
@@ -320,7 +321,7 @@ public async Task SetGeometry(Geometry geometry)
if (CoreJsModule is not null)
{
await CoreJsModule.InvokeVoidAsync("setGraphicGeometry", Id, LayerId, View?.Id,
- Geometry.ToSerializationRecord());
+ Geometry.ToProtobuf());
}
else
{
@@ -343,7 +344,7 @@ public async Task SetSymbol(Symbol symbol)
Symbol = symbol;
if (CoreJsModule is not null)
{
- await CoreJsModule.InvokeVoidAsync("setGraphicSymbol", Id, Symbol.ToSerializationRecord(),
+ await CoreJsModule.InvokeVoidAsync("setGraphicSymbol", Id, Symbol.ToProtobuf(),
LayerId, View?.Id);
}
else
@@ -378,7 +379,7 @@ public async Task SetPopupTemplate(PopupTemplate popupTemplate)
if (CoreJsModule is not null)
{
await CoreJsModule.InvokeVoidAsync("setGraphicPopupTemplate", Id,
- PopupTemplate.ToSerializationRecord(), PopupTemplate.DotNetComponentReference, LayerId, View?.Id);
+ PopupTemplate.ToProtobuf(), PopupTemplate.DotNetComponentReference, LayerId, View?.Id);
}
else
{
@@ -676,13 +677,21 @@ internal GraphicSerializationRecord ToSerializationRecord(bool refresh = false)
{
if (_serializationRecord is null || refresh)
{
- _serializationRecord = new GraphicSerializationRecord(Id.ToString(), Geometry?.ToSerializationRecord(),
- Symbol?.ToSerializationRecord(), PopupTemplate?.ToSerializationRecord(),
- Attributes.ToSerializationRecord(), Visible,
- AggregateGeometries is null ? null : JsonSerializer.Serialize(AggregateGeometries),
- Origin?.ToSerializationRecord(), LayerId?.ToString(), ViewId?.ToString());
+ return ToProtobuf();
}
+
+ return _serializationRecord;
+ }
+ ///
+ public virtual GraphicSerializationRecord ToProtobuf()
+ {
+ _serializationRecord = new GraphicSerializationRecord(Id.ToString(), Geometry?.ToProtobuf(),
+ Symbol?.ToProtobuf(), PopupTemplate?.ToProtobuf(),
+ Attributes.ToProtobufArray(), Visible,
+ AggregateGeometries is null ? null : JsonSerializer.Serialize(AggregateGeometries),
+ Origin?.ToProtobuf(), LayerId?.ToString(), ViewId?.ToString());
+
return _serializationRecord;
}
@@ -784,101 +793,4 @@ public override int GetHashCode()
{
return !Equals(left, right);
}
-}
-
-[ProtoContract(Name = "Graphic")]
-internal record GraphicSerializationRecord : MapComponentSerializationRecord
-{
- public GraphicSerializationRecord()
- {
- }
-
- public GraphicSerializationRecord(string Id, GeometrySerializationRecord? Geometry,
- SymbolSerializationRecord? Symbol, PopupTemplateSerializationRecord? PopupTemplate,
- AttributeSerializationRecord[]? Attributes, bool? Visible, string? AggregateGeometries,
- GraphicOriginSerializationRecord? Origin, string? LayerId, string? ViewId)
- {
- this.Id = Id;
- this.Geometry = Geometry;
- this.Symbol = Symbol;
- this.PopupTemplate = PopupTemplate;
- this.Attributes = Attributes;
- this.Visible = Visible;
- this.AggregateGeometries = AggregateGeometries;
- this.Origin = Origin;
- this.LayerId = LayerId;
- this.ViewId = ViewId;
- }
-
- public Graphic FromSerializationRecord()
- {
- if (!Guid.TryParse(Id, out Guid graphicId))
- {
- graphicId = Guid.NewGuid();
- }
-
- Guid? layerId = null;
-
- if (Guid.TryParse(LayerId, out Guid existingLayerId))
- {
- layerId = existingLayerId;
- }
-
- Guid? viewId = null;
-
- if (Guid.TryParse(ViewId, out Guid existingViewId))
- {
- viewId = existingViewId;
- }
-
- return new Graphic(Geometry?.FromSerializationRecord(), Symbol?.FromSerializationRecord(),
- PopupTemplate?.FromSerializationRecord(), new AttributesDictionary(Attributes),
- Visible, null, AggregateGeometries, Origin?.FromSerializationRecord())
- {
- Id = graphicId,
-#pragma warning disable BL0005
- LayerId = layerId,
-#pragma warning restore BL0005
- ViewId = viewId
- };
- }
-
- [ProtoMember(1)]
- public string? Id { get; set; } = string.Empty;
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(2)]
- public GeometrySerializationRecord? Geometry { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(3)]
- public SymbolSerializationRecord? Symbol { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(4)]
- public PopupTemplateSerializationRecord? PopupTemplate { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(5)]
- public AttributeSerializationRecord[]? Attributes { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(6)]
- public bool? Visible { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(7)]
- public string? AggregateGeometries { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(8)]
- public GraphicOriginSerializationRecord? Origin { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(9)]
- public string? LayerId { get; set; }
-
- [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
- [ProtoMember(10)]
- public string? ViewId { get; set; }
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/HomeViewModel.cs b/src/dymaptic.GeoBlazor.Core/Components/HomeViewModel.cs
index 862ebbcea..bcdbb415a 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/HomeViewModel.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/HomeViewModel.cs
@@ -21,7 +21,7 @@ public partial class HomeViewModel : MapComponent, IViewModel
[CodeGenerationIgnore]
public async Task OnJsGoToOverride(IJSStreamReference jsStreamRef)
{
- GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReference();
+ GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (GoToOverride is not null && goToParameters is not null)
{
await GoToOverride.Invoke(goToParameters);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/HomeViewModel.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/HomeViewModel.gb.cs
index 3f7a02ab5..4531044d3 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/HomeViewModel.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/HomeViewModel.gb.cs
@@ -290,7 +290,7 @@ public async Task OnJsGo(IJSStreamReference jsStreamRef)
return;
}
- HomeViewModelGoEvent? goEvent = await jsStreamRef.ReadJsStreamReference();
+ HomeViewModelGoEvent? goEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (goEvent is not null)
{
await OnGo.InvokeAsync(goEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ImageMediaInfo.cs b/src/dymaptic.GeoBlazor.Core/Components/ImageMediaInfo.cs
index 1630aafdb..d23ca1044 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ImageMediaInfo.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ImageMediaInfo.cs
@@ -1,13 +1,11 @@
namespace dymaptic.GeoBlazor.Core.Components;
+[ProtobufSerializable]
public partial class ImageMediaInfo : MediaInfo
{
-
-
///
public override string Type => "image-media";
-
///
/// Refresh interval of the layer in minutes. Non-zero value indicates automatic layer refresh at the specified interval. Value of 0 indicates auto refresh is not enabled. If the property does not exist, it is equivalent to having a value of 0.
///
@@ -15,15 +13,15 @@ public partial class ImageMediaInfo : MediaInfo
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public double? RefreshInterval { get; set; }
-
- internal override MediaInfoSerializationRecord ToSerializationRecord()
+ ///
+ public override MediaInfoSerializationRecord ToProtobuf()
{
return new MediaInfoSerializationRecord(Id.ToString(), "image-media")
{
AltText = AltText,
Caption = Caption,
Title = Title,
- Value = Value?.ToSerializationRecord(),
+ Value = Value?.ToProtobuf(),
RefreshInterval = RefreshInterval
};
}
diff --git a/src/dymaptic.GeoBlazor.Core/Components/ImageMediaInfoValue.cs b/src/dymaptic.GeoBlazor.Core/Components/ImageMediaInfoValue.cs
index 523f06a3c..9350210bf 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/ImageMediaInfoValue.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/ImageMediaInfoValue.cs
@@ -1,9 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components;
-public partial class ImageMediaInfoValue : MapComponent
+[ProtobufSerializable]
+public partial class ImageMediaInfoValue : MapComponent, IMediaInfoValue
{
-
-
///
/// A string containing a URL to be launched in a browser when a user clicks the image.
///
@@ -17,9 +16,10 @@ public partial class ImageMediaInfoValue : MapComponent
[Parameter]
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? SourceURL { get; set; }
-
- internal ChartMediaInfoValueSerializationRecord ToSerializationRecord()
+
+ ///
+ public MediaInfoValueSerializationRecord ToProtobuf()
{
- return new ChartMediaInfoValueSerializationRecord(Id.ToString(), LinkURL: LinkURL, SourceURL: SourceURL);
+ return new MediaInfoValueSerializationRecord(Id.ToString(), LinkURL: LinkURL, SourceURL: SourceURL);
}
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/JoinTableDataSource.cs b/src/dymaptic.GeoBlazor.Core/Components/JoinTableDataSource.cs
index 140024966..021aa651c 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/JoinTableDataSource.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/JoinTableDataSource.cs
@@ -2,8 +2,6 @@ namespace dymaptic.GeoBlazor.Core.Components;
public partial class JoinTableDataSource : DynamicDataSource
{
-
-
///
public override DynamicDataSourceType Type => DynamicDataSourceType.JoinTable;
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Label.cs b/src/dymaptic.GeoBlazor.Core/Components/Label.cs
index c7d151f49..fe1a210d6 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Label.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Label.cs
@@ -114,7 +114,7 @@ public virtual async Task SetSymbol(Symbol symbol)
Symbol = symbol;
if (CoreJsModule is not null)
{
- await CoreJsModule.InvokeVoidAsync("setGraphicSymbol", Id, Symbol.ToSerializationRecord());
+ await CoreJsModule.InvokeVoidAsync("setGraphicSymbol", Id, Symbol.ToProtobuf());
}
else
{
diff --git a/src/dymaptic.GeoBlazor.Core/Components/LayerListViewModel.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/LayerListViewModel.gb.cs
index 2a106ee68..51232f8a1 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/LayerListViewModel.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/LayerListViewModel.gb.cs
@@ -421,7 +421,7 @@ public async Task OnJsTriggerAction(IJSStreamReference jsStreamRef)
return;
}
- LayerListViewModelTriggerActionEvent? triggerActionEvent = await jsStreamRef.ReadJsStreamReference();
+ LayerListViewModelTriggerActionEvent? triggerActionEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (triggerActionEvent is not null)
{
await OnTriggerAction.InvokeAsync(triggerActionEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/BaseTileLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/BaseTileLayer.gb.cs
index da5ca219e..468f4c563 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/BaseTileLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/BaseTileLayer.gb.cs
@@ -694,7 +694,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/CSVLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/CSVLayer.gb.cs
index b8bc5370a..1dadc9ac4 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/CSVLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/CSVLayer.gb.cs
@@ -4098,7 +4098,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/FeatureLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/FeatureLayer.gb.cs
index ea5ebc1a2..38ebfb5e4 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/FeatureLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/FeatureLayer.gb.cs
@@ -6266,7 +6266,7 @@ public async Task OnJsEdits(IJSStreamReference jsStreamRef)
return;
}
- FeatureLayerEditsEvent? editsEvent = await jsStreamRef.ReadJsStreamReference();
+ FeatureLayerEditsEvent? editsEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (editsEvent is not null)
{
await OnEdits.InvokeAsync(editsEvent);
@@ -6300,7 +6300,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/GeoJSONLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/GeoJSONLayer.gb.cs
index aa4510050..f4ef65f90 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/GeoJSONLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/GeoJSONLayer.gb.cs
@@ -4040,7 +4040,7 @@ public async Task OnJsEdits(IJSStreamReference jsStreamRef)
return;
}
- GeoJSONLayerEditsEvent? editsEvent = await jsStreamRef.ReadJsStreamReference();
+ GeoJSONLayerEditsEvent? editsEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (editsEvent is not null)
{
await OnEdits.InvokeAsync(editsEvent);
@@ -4073,7 +4073,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/GeoRSSLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/GeoRSSLayer.gb.cs
index b0780b8ff..e76f696f5 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/GeoRSSLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/GeoRSSLayer.gb.cs
@@ -1144,7 +1144,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/ImageryLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/ImageryLayer.gb.cs
index 493f4b81b..483b80152 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/ImageryLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/ImageryLayer.gb.cs
@@ -3978,7 +3978,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/Layer.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/Layer.cs
index 5edce7e0f..c60becd34 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/Layer.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/Layer.cs
@@ -340,7 +340,7 @@ await CoreJsModule.InvokeAsync("buildJsLayer",
IJSStreamReference streamRef = await JsComponentReference!.InvokeAsync("load",
cancellationToken, abortSignal);
Type type = GetType();
- Layer? deserializedLayer = await streamRef.ReadJsStreamReference(type) as Layer;
+ Layer? deserializedLayer = await streamRef.ReadJsStreamReferenceAsJSON(type) as Layer;
if (deserializedLayer is null)
{
throw new InvalidOperationException($"Could not load layer of type {type.Name}");
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/Layer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/Layer.gb.cs
index b19d8b7cb..d856dc179 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/Layer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/Layer.gb.cs
@@ -410,7 +410,7 @@ public async Task OnJsCreate(IJSStreamReference jsStreamRef)
return;
}
- LayerViewCreateEvent? createEvent = await jsStreamRef.ReadJsStreamReference();
+ LayerViewCreateEvent? createEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (createEvent is not null)
{
await OnCreate.InvokeAsync(createEvent);
@@ -442,7 +442,7 @@ public async Task OnJsCreateError(IJSStreamReference jsStreamRef)
return;
}
- LayerViewCreateErrorEvent? createErrorEvent = await jsStreamRef.ReadJsStreamReference();
+ LayerViewCreateErrorEvent? createErrorEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (createErrorEvent is not null)
{
await OnCreateError.InvokeAsync(createErrorEvent);
@@ -475,7 +475,7 @@ public async Task OnJsDestroy(IJSStreamReference jsStreamRef)
return;
}
- LayerViewDestroyEvent? destroyEvent = await jsStreamRef.ReadJsStreamReference();
+ LayerViewDestroyEvent? destroyEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (destroyEvent is not null)
{
await OnDestroy.InvokeAsync(destroyEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/MapImageLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/MapImageLayer.gb.cs
index 155431bc8..7e11f7d0f 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/MapImageLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/MapImageLayer.gb.cs
@@ -2635,7 +2635,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/TileLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/TileLayer.gb.cs
index 164ae5bcf..59993c728 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/TileLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/TileLayer.gb.cs
@@ -1978,7 +1978,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/VectorTileLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/VectorTileLayer.gb.cs
index b7e8b0081..68abf794d 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/VectorTileLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/VectorTileLayer.gb.cs
@@ -1394,7 +1394,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/WFSLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/WFSLayer.gb.cs
index 2afb69fac..0d3425c3c 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/WFSLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/WFSLayer.gb.cs
@@ -3791,7 +3791,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/WMSLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/WMSLayer.gb.cs
index 8f6c3b9cd..17c7b185d 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/WMSLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/WMSLayer.gb.cs
@@ -3085,7 +3085,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/Layers/WebTileLayer.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/Layers/WebTileLayer.gb.cs
index bc2ff6570..f9a3fd4e4 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/Layers/WebTileLayer.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/Layers/WebTileLayer.gb.cs
@@ -1213,7 +1213,7 @@ public async Task OnJsRefresh(IJSStreamReference jsStreamRef)
return;
}
- RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReference();
+ RefreshEvent? refreshEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (refreshEvent is not null)
{
await OnRefresh.InvokeAsync(refreshEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/LineChartMediaInfo.cs b/src/dymaptic.GeoBlazor.Core/Components/LineChartMediaInfo.cs
index 5f08207d2..c2320d521 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/LineChartMediaInfo.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/LineChartMediaInfo.cs
@@ -1,21 +1,20 @@
namespace dymaptic.GeoBlazor.Core.Components;
+[ProtobufSerializable]
public partial class LineChartMediaInfo : MediaInfo
{
-
-
///
public override string Type => "line-chart";
-
- internal override MediaInfoSerializationRecord ToSerializationRecord()
+ ///
+ public override MediaInfoSerializationRecord ToProtobuf()
{
return new MediaInfoSerializationRecord(Id.ToString(), "line-chart")
{
AltText = AltText,
Caption = Caption,
Title = Title,
- Value = Value?.ToSerializationRecord()
+ Value = Value?.ToProtobuf()
};
}
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/LocateViewModel.cs b/src/dymaptic.GeoBlazor.Core/Components/LocateViewModel.cs
index 5e93def85..ba16b9b1e 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/LocateViewModel.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/LocateViewModel.cs
@@ -21,7 +21,7 @@ public partial class LocateViewModel : MapComponent
[CodeGenerationIgnore]
public async Task OnJsGoToOverride(IJSStreamReference jsStreamRef)
{
- GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReference();
+ GoToOverrideParameters? goToParameters = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (GoToOverride is not null && goToParameters is not null)
{
await GoToOverride.Invoke(goToParameters);
@@ -41,7 +41,7 @@ public async Task OnJsGoToOverride(IJSStreamReference jsStreamRef)
[CodeGenerationIgnore]
public async Task OnJsLocate(IJSStreamReference jsStreamRef)
{
- LocateViewModelLocateEvent? locateEvent = await jsStreamRef.ReadJsStreamReference();
+ LocateViewModelLocateEvent? locateEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
View!.ExtentChangedInJs = true;
await OnLocate.InvokeAsync(locateEvent);
}
diff --git a/src/dymaptic.GeoBlazor.Core/Components/LocateViewModel.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/LocateViewModel.gb.cs
index e8885d6d1..c05b5fddf 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/LocateViewModel.gb.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/LocateViewModel.gb.cs
@@ -857,7 +857,7 @@ public async Task OnJsLocateError(IJSStreamReference jsStreamRef)
return;
}
- LocateViewModelLocateErrorEvent? locateErrorEvent = await jsStreamRef.ReadJsStreamReference();
+ LocateViewModelLocateErrorEvent? locateErrorEvent = await jsStreamRef.ReadJsStreamReferenceAsJSON();
if (locateErrorEvent is not null)
{
await OnLocateError.InvokeAsync(locateErrorEvent);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/LocationService.cs b/src/dymaptic.GeoBlazor.Core/Components/LocationService.cs
index d3176ffe0..5d2b681f9 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/LocationService.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/LocationService.cs
@@ -2179,7 +2179,7 @@ private async Task> AddressToLocations(string url, object
categories, countryCode, forStorage, location, locationType, magicKey,
maxLocations, outFields, outSpatialReference, searchExtent, requestOptions, addressSearchStringParameterName);
- return await streamRef.ReadJsStreamReference>() ?? [];
+ return await streamRef.ReadJsStreamReferenceAsJSON>() ?? [];
}
///
@@ -2218,7 +2218,7 @@ public async Task> AddressesToLocations(string url, objec
addresses, countryCode, categories, locationType,
outSpatialReference, requestOptions, addressSearchStringParameterName);
- return await streamRef.ReadJsStreamReference>() ?? [];
+ return await streamRef.ReadJsStreamReferenceAsJSON>() ?? [];
}
private const string ESRIGeoLocationUrl = "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer";
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MapComponent.razor.cs b/src/dymaptic.GeoBlazor.Core/Components/MapComponent.razor.cs
index 6b63fa749..e34dae179 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/MapComponent.razor.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/MapComponent.razor.cs
@@ -11,14 +11,38 @@ public abstract partial class MapComponent : ComponentBase, IAsyncDisposable, IM
///
[Inject]
[JsonIgnore]
- public IJSRuntime? JsRuntime { get; set; }
+ public IJSRuntime? JsRuntime
+ {
+ get
+ {
+ if (field is null && Parent?.JsRuntime is not null)
+ {
+ field = Parent.JsRuntime;
+ }
+
+ return field;
+ }
+ set;
+ }
///
/// Manages references to JavaScript modules.
///
[Inject]
[JsonIgnore]
- public JsModuleManager? JsModuleManager { get; set; }
+ public JsModuleManager? JsModuleManager
+ {
+ get
+ {
+ if (field is null && Parent?.JsModuleManager is not null)
+ {
+ field = Parent.JsModuleManager;
+ }
+
+ return field;
+ }
+ set;
+ }
///
/// ChildContent defines the ability to add other components within this component in the razor syntax.
@@ -131,6 +155,21 @@ public Guid? ViewId
///
[JsonIgnore]
public bool IsDisposed { get; private set; }
+
+ ///
+ /// Boolean flag to identify if GeoBlazor is running in Blazor Server mode
+ ///
+ protected internal bool IsServer => JsRuntime?.GetType().Name.Contains("Remote") ?? false;
+
+ ///
+ /// Boolean flag to identify if GeoBlazor is running in Blazor WebAssembly (client) mode
+ ///
+ protected internal bool IsWebAssembly => OperatingSystem.IsBrowser();
+
+ ///
+ /// Boolean flag to identify if GeoBlazor is running in Blazor Hybrid (MAUI) mode
+ ///
+ protected internal bool IsMaui => JsRuntime!.GetType().Name.Contains("WebView");
///
/// Implements the `IAsyncDisposable` pattern.
@@ -668,7 +707,7 @@ public Task SetVisible(bool visible)
try
{
- if (await jsonStreamReference.ReadJsStreamReference(MapComponentType) is MapComponent deserialized)
+ if (await jsonStreamReference.ReadJsStreamReferenceAsJSON(MapComponentType) is MapComponent deserialized)
{
if (IsDisposed)
{
@@ -991,6 +1030,7 @@ protected override void OnParametersSet()
{
record.CoreJsModule = CoreJsModule;
record.AbortManager = new AbortManager(CoreJsModule!);
+ record.IsServer = IsServer;
}
}
}
@@ -1037,7 +1077,7 @@ protected virtual async Task RenderView(bool forceRender = false)
///
/// Properties that were modified in code, and should no longer be set via markup, but instead set to the value here.
///
- protected readonly internal Dictionary ModifiedParameters = new();
+ protected internal readonly Dictionary ModifiedParameters = new();
///
/// Creates a cancellation token to control external calls
@@ -1378,7 +1418,7 @@ public async Task OnReactiveWatcherUpdate(string watchExpression, IJSStreamRefer
if (jsStreamReference is not null)
{
- typedValue = await jsStreamReference.ReadJsStreamReference(returnType);
+ typedValue = await jsStreamReference.ReadJsStreamReferenceAsJSON(returnType);
}
handler.DynamicInvoke(typedValue);
@@ -1511,7 +1551,7 @@ public async Task OnReactiveListenerTriggered(string eventName, IJSStreamReferen
if (jsStreamReference is not null)
{
- typedValue = await jsStreamReference.ReadJsStreamReference(returnType);
+ typedValue = await jsStreamReference.ReadJsStreamReferenceAsJSON(returnType);
}
handler.DynamicInvoke(typedValue);
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MapFont.cs b/src/dymaptic.GeoBlazor.Core/Components/MapFont.cs
index 297fae3ea..ff67283fa 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/MapFont.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/MapFont.cs
@@ -1,9 +1,8 @@
namespace dymaptic.GeoBlazor.Core.Components;
-public partial class MapFont : MapComponent
+[ProtobufSerializable]
+public partial class MapFont : MapComponent, IProtobufSerializable
{
-
-
///
/// The text decoration.
/// default none
@@ -46,58 +45,10 @@ public partial class MapFont : MapComponent
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public FontWeight? Weight { get; set; }
- internal MapFontSerializationRecord ToSerializationRecord()
+ ///
+ public MapFontSerializationRecord ToProtobuf()
{
return new MapFontSerializationRecord(Id.ToString(), Size?.Points, Family, Style?.ToString().ToKebabCase(),
Weight?.ToString().ToKebabCase(), Decoration?.ToString().ToKebabCase());
}
-}
-
-[ProtoContract]
-internal record MapFontSerializationRecord
-{
- public MapFontSerializationRecord()
- {
- }
-
- public MapFontSerializationRecord(string Id, double? Size, string? Family, string? FontStyle, string? Weight,
- string? Decoration)
- {
- this.Id = Id;
- this.Size = Size;
- this.Family = Family;
- this.FontStyle = FontStyle;
- this.Weight = Weight;
- this.Decoration = Decoration;
- }
-
- [ProtoMember(1)]
- public double? Size { get; init; }
-
- [ProtoMember(2)]
- public string? Family { get; init; }
-
- [ProtoMember(3)]
- public string? FontStyle { get; init; }
-
- [ProtoMember(4)]
- public string? Weight { get; init; }
-
- [ProtoMember(5)]
- public string? Decoration { get; init; }
-
- [ProtoMember(6)]
- public string? Id { get; init; }
-
- public MapFont FromSerializationRecord()
- {
- Guid id = Guid.NewGuid();
- if (Guid.TryParse(Id, out Guid guid))
- {
- id = guid;
- }
- return new MapFont(Size, Family, FontStyle is null ? null : Enum.Parse(FontStyle),
- Weight is null ? null : Enum.Parse(Weight),
- Decoration is null ? null : Enum.Parse(Decoration)) { Id = id };
- }
}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MediaInfo.cs b/src/dymaptic.GeoBlazor.Core/Components/MediaInfo.cs
index b858e3217..ae1b3d94a 100644
--- a/src/dymaptic.GeoBlazor.Core/Components/MediaInfo.cs
+++ b/src/dymaptic.GeoBlazor.Core/Components/MediaInfo.cs
@@ -1,73 +1,16 @@
namespace dymaptic.GeoBlazor.Core.Components;
[JsonConverter(typeof(MediaInfoConverter))]
-public abstract partial class MediaInfo : MapComponent
+[ProtobufSerializable]
+public abstract partial class MediaInfo : MapComponent, IProtobufSerializable
{
///
/// Indicates the type of media
///
public abstract string Type { get; }
- internal abstract MediaInfoSerializationRecord ToSerializationRecord();
-}
-
-[ProtoContract(Name = "MediaInfo")]
-internal record MediaInfoSerializationRecord : MapComponentSerializationRecord
-{
- public MediaInfoSerializationRecord()
- {
- }
-
- public MediaInfoSerializationRecord(string Id, string Type)
- {
- this.Id = Id;
- this.Type = Type;
- }
-
- [ProtoMember(1)]
- public string Type { get; init; } = string.Empty;
-
- [ProtoMember(2)]
- public string? AltText { get; init; }
-
- [ProtoMember(3)]
- public string? Caption { get; init; }
-
- [ProtoMember(4)]
- public string? Title { get; init; }
-
- [ProtoMember(5)]
- public ChartMediaInfoValueSerializationRecord? Value { get; init; }
-
- [ProtoMember(6)]
- public double? RefreshInterval { get; init; }
-
- [ProtoMember(7)]
- public string? Id { get; init; }
-
- public MediaInfo FromSerializationRecord()
- {
- Guid id = Guid.NewGuid();
- if (Guid.TryParse(Id, out Guid guid))
- {
- id = guid;
- }
- return Type switch
- {
- "bar-chart" => new BarChartMediaInfo(Title, Caption, AltText,
- Value?.FromSerializationRecord() as ChartMediaInfoValue) { Id = id },
- "column-chart" => new ColumnChartMediaInfo(Title, Caption, AltText,
- Value?.FromSerializationRecord() as ChartMediaInfoValue) { Id = id },
- "pie-chart" => new PieChartMediaInfo(Title, Caption, AltText,
- Value?.FromSerializationRecord() as ChartMediaInfoValue) { Id = id },
- "line-chart" => new LineChartMediaInfo(Title, Caption, AltText,
- Value?.FromSerializationRecord() as ChartMediaInfoValue) { Id = id },
- "image-media" => new ImageMediaInfo(Title, Caption, AltText,
- Value?.FromSerializationRecord() as ImageMediaInfoValue,
- RefreshInterval) { Id = id },
- _ => throw new NotSupportedException($"MediaInfo type {Type} is not supported.")
- };
- }
+ ///
+ public abstract MediaInfoSerializationRecord ToProtobuf();
}
internal class MediaInfoConverter : JsonConverter
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshComponent.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshComponent.cs
new file mode 100644
index 000000000..41a68f24f
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshComponent.cs
@@ -0,0 +1,59 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+[ProtobufSerializable]
+public partial class MeshComponent: IProtobufSerializable
+{
+ // Add custom code to this file to override generated code
+ ///
+ public MeshComponentSerializationRecord ToProtobuf()
+ {
+ MeshComponentMaterialSerializationRecord? materialRecord = Material switch
+ {
+ MeshMaterialMetallicRoughness metallicRoughness => metallicRoughness.ToProtobuf(),
+ MeshMaterial material => material.ToProtobuf(),
+ _ => null
+ };
+ return new MeshComponentSerializationRecord(Faces,
+ materialRecord, Name, Shading?.ToString().ToKebabCase());
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Material property.
+ ///
+ [CodeGenerationIgnore]
+ public async Task GetMaterial()
+ {
+ if (CoreJsModule is null)
+ {
+ return Material;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Material;
+ }
+
+ IMeshComponentMaterial? result = await JsComponentReference.InvokeAsync(
+ "getMaterial", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Material = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Material)] = Material;
+ }
+
+ return Material;
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshComponent.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshComponent.gb.cs
new file mode 100644
index 000000000..18fed5f08
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshComponent.gb.cs
@@ -0,0 +1,417 @@
+// File auto-generated by dymaptic tooling. Any changes made here will be lost on future generation. To override functionality, use the relevant root .cs file.
+
+namespace dymaptic.GeoBlazor.Core.Components;
+
+
+///
+/// GeoBlazor Docs
+/// The MeshComponent class is used to apply one or more materials to
+/// a single Mesh .
+/// ArcGIS Maps SDK for JavaScript
+///
+public partial class MeshComponent : MapComponent
+{
+
+ ///
+ /// Parameterless constructor for use as a Razor Component.
+ ///
+ [ActivatorUtilitiesConstructor]
+ public MeshComponent()
+ {
+ }
+
+ ///
+ /// Constructor for use in C# code. Use named parameters (e.g., item1: value1, item2: value2) to set properties in any order.
+ ///
+ ///
+ /// A flat array of indices that refer to vertices in the
+ /// vertexAttributes of the
+ /// mesh to which the component belongs.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// The material determines how the component is visualized.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a name of the component.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies the type of normals used for lighting.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ public MeshComponent(
+ byte[]? faces = null,
+ IMeshComponentMaterial? material = null,
+ string? name = null,
+ MeshShading? shading = null)
+ {
+ AllowRender = false;
+#pragma warning disable BL0005
+ Faces = faces;
+ Material = material;
+ Name = name;
+ Shading = shading;
+#pragma warning restore BL0005
+ }
+
+
+#region Public Properties / Blazor Parameters
+
+ ///
+ /// GeoBlazor Docs
+ /// A flat array of indices that refer to vertices in the
+ /// vertexAttributes of the
+ /// mesh to which the component belongs.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public byte[]? Faces { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// The material determines how the component is visualized.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public IMeshComponentMaterial? Material { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies a name of the component.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Name { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies the type of normals used for lighting.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshShading? Shading { get; set; }
+
+#endregion
+
+#region Property Getters
+
+ ///
+ /// Asynchronously retrieve the current value of the Faces property.
+ ///
+ public async Task GetFaces()
+ {
+ if (CoreJsModule is null)
+ {
+ return Faces;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Faces;
+ }
+
+ // get the property value
+ byte[]? result = await JsComponentReference!.InvokeAsync("getProperty",
+ CancellationTokenSource.Token, "faces");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Faces = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Faces)] = Faces;
+ }
+
+ return Faces;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Name property.
+ ///
+ public async Task GetName()
+ {
+ if (CoreJsModule is null)
+ {
+ return Name;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Name;
+ }
+
+ // get the property value
+ string? result = await JsComponentReference!.InvokeAsync("getProperty",
+ CancellationTokenSource.Token, "name");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Name = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Name)] = Name;
+ }
+
+ return Name;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Shading property.
+ ///
+ public async Task GetShading()
+ {
+ if (CoreJsModule is null)
+ {
+ return Shading;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Shading;
+ }
+
+ // get the property value
+ JsNullableEnumWrapper? result = await CoreJsModule!.InvokeAsync?>("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "shading");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ Shading = (MeshShading)result.Value.Value!;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Shading)] = Shading;
+ }
+
+ return Shading;
+ }
+
+#endregion
+
+#region Property Setters
+
+ ///
+ /// Asynchronously set the value of the Faces property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetFaces(byte[]? value)
+ {
+#pragma warning disable BL0005
+ Faces = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Faces)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "faces", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Material property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetMaterial(IMeshComponentMaterial? value)
+ {
+#pragma warning disable BL0005
+ Material = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Material)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "material", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Name property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetName(string? value)
+ {
+#pragma warning disable BL0005
+ Name = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Name)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "name", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Shading property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetShading(MeshShading? value)
+ {
+#pragma warning disable BL0005
+ Shading = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Shading)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "shading", value);
+ }
+
+#endregion
+
+#region Add to Collection Methods
+
+ ///
+ /// Asynchronously adds elements to the Faces property.
+ ///
+ ///
+ /// The elements to add.
+ ///
+ public async Task AddToFaces(params byte[] values)
+ {
+ byte[] join = Faces is null
+ ? values
+ : [..Faces, ..values];
+ await SetFaces(join);
+ }
+
+#endregion
+
+#region Remove From Collection Methods
+
+
+ ///
+ /// Asynchronously remove an element from the Faces property.
+ ///
+ ///
+ /// The elements to remove.
+ ///
+ public async Task RemoveFromFaces(params byte[] values)
+ {
+ if (Faces is null)
+ {
+ return;
+ }
+ await SetFaces(Faces.Except(values).ToArray());
+ }
+
+#endregion
+
+}
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshGeoreferencedVertexSpace.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshGeoreferencedVertexSpace.cs
new file mode 100644
index 000000000..52e5d7ad9
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshGeoreferencedVertexSpace.cs
@@ -0,0 +1,24 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+///
+/// A mesh vertex space indicating that mesh vertices are either absolute georeferenced map coordinates or relative offsets in map space to a fully georeferenced origin. The map space is identified by the spatial reference of the mesh.
+/// The vertex space of a mesh allows users to specify how the coordinates of the mesh vertices are interpreted. Use the georeferenced vertex space if the coordinates are already in the spatial reference of the mesh. The coordinates can be relative to the origin or absolute coordinates if the origin is not defined.
+///
+///
+/// Origin of the vertex space. This will be interpreted as coordinates in the SpatialReference of the Mesh using the vertex space. If this is null, the coordinates are expected to be absolute. If not, then the coordinates are expected to be deltas relative to the origin.
+///
+[CodeGenerationIgnore]
+[ProtobufSerializable]
+public record MeshGeoreferencedVertexSpace(double[]? Origin) : IMeshVertexSpace
+{
+ ///
+ /// The type of Vertex Space
+ ///
+ public string Type => "georeferenced";
+
+ ///
+ public MeshVertexSpaceSerializationRecord ToProtobuf()
+ {
+ return new MeshVertexSpaceSerializationRecord(Type, Origin);
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshLocalVertexSpace.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshLocalVertexSpace.cs
new file mode 100644
index 000000000..25f02fe79
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshLocalVertexSpace.cs
@@ -0,0 +1,20 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+///
+/// A mesh vertex space that indicates mesh vertices to be in a plain cartesian space as often encountered in 3D modeling and CAD applications. Georeferencing is done by using the coordinates in the local tangent plane reference frame at the fully georeferenced origin of the vertex space.
+///
+///
+/// Origin of the vertex space. This will be interpreted as coordinates in the SpatialReference of the Mesh using the vertex space.
+///
+[CodeGenerationIgnore]
+[ProtobufSerializable]
+public record MeshLocalVertexSpace(double[]? Origin) : IMeshVertexSpace
+{
+ public string Type => "local";
+
+ ///
+ public MeshVertexSpaceSerializationRecord ToProtobuf()
+ {
+ return new MeshVertexSpaceSerializationRecord(Type, Origin);
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshMaterial.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshMaterial.cs
new file mode 100644
index 000000000..021b766ec
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshMaterial.cs
@@ -0,0 +1,23 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+[ProtobufSerializable]
+public partial class MeshMaterial: MapComponent, IMeshComponentMaterial
+{
+ // Add custom code to this file to override generated code
+
+ ///
+ public virtual MeshComponentMaterialSerializationRecord ToProtobuf()
+ {
+ return new MeshComponentMaterialSerializationRecord(AlphaCutoff,
+ AlphaMode?.ToString().ToKebabCase(),
+ Color?.ToProtobuf(),
+ ColorTexture?.ToProtobuf(),
+ ColorTextureTransform?.ToProtobuf(),
+ DoubleSided,
+ NormalTexture?.ToProtobuf(),
+ NormalTextureTransform?.ToProtobuf(),
+ null, null, null,
+ null, null, null,
+ null, null);
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshMaterial.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshMaterial.gb.cs
new file mode 100644
index 000000000..b94ca04b8
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshMaterial.gb.cs
@@ -0,0 +1,823 @@
+// File auto-generated by dymaptic tooling. Any changes made here will be lost on future generation. To override functionality, use the relevant root .cs file.
+
+namespace dymaptic.GeoBlazor.Core.Components;
+
+
+///
+/// GeoBlazor Docs
+/// The material determines how a MeshComponent is visualized.
+/// ArcGIS Maps SDK for JavaScript
+///
+public partial class MeshMaterial
+{
+
+ ///
+ /// Parameterless constructor for use as a Razor Component.
+ ///
+ [ActivatorUtilitiesConstructor]
+ public MeshMaterial()
+ {
+ }
+
+ ///
+ /// Constructor for use in C# code. Use named parameters (e.g., item1: value1, item2: value2) to set properties in any order.
+ ///
+ ///
+ /// Specifies how transparency on the object is handled.
+ /// default 0.5
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies how transparency on the object is handled.
+ /// default "auto"
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a single, uniform color for the mesh component.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a texture from which to get color information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// A transformation of UV mesh coordinates used to sample the color texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies whether both sides of each triangle are displayed, or only the front sides.
+ /// default true
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a texture from which to get normal information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// A transformation of UV mesh coordinates used to sample the normal texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ public MeshMaterial(
+ double? alphaCutoff = null,
+ AlphaMode? alphaMode = null,
+ MapColor? color = null,
+ MeshTexture? colorTexture = null,
+ MeshTextureTransform? colorTextureTransform = null,
+ bool? doubleSided = null,
+ MeshTexture? normalTexture = null,
+ MeshTextureTransform? normalTextureTransform = null)
+ {
+ AllowRender = false;
+#pragma warning disable BL0005
+ AlphaCutoff = alphaCutoff;
+ AlphaMode = alphaMode;
+ Color = color;
+ ColorTexture = colorTexture;
+ ColorTextureTransform = colorTextureTransform;
+ DoubleSided = doubleSided;
+ NormalTexture = normalTexture;
+ NormalTextureTransform = normalTextureTransform;
+#pragma warning restore BL0005
+ }
+
+
+#region Public Properties / Blazor Parameters
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies how transparency on the object is handled.
+ /// default 0.5
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public double? AlphaCutoff { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies how transparency on the object is handled.
+ /// default "auto"
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public AlphaMode? AlphaMode { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies a single, uniform color for the mesh component.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MapColor? Color { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies a texture from which to get color information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTexture? ColorTexture { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// A transformation of UV mesh coordinates used to sample the color texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTextureTransform? ColorTextureTransform { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies whether both sides of each triangle are displayed, or only the front sides.
+ /// default true
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public bool? DoubleSided { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies a texture from which to get normal information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTexture? NormalTexture { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// A transformation of UV mesh coordinates used to sample the normal texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTextureTransform? NormalTextureTransform { get; set; }
+
+#endregion
+
+#region Property Getters
+
+ ///
+ /// Asynchronously retrieve the current value of the AlphaCutoff property.
+ ///
+ public async Task GetAlphaCutoff()
+ {
+ if (CoreJsModule is null)
+ {
+ return AlphaCutoff;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return AlphaCutoff;
+ }
+
+ // get the property value
+ JsNullableDoubleWrapper? result = await CoreJsModule!.InvokeAsync("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "alphaCutoff");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ AlphaCutoff = result.Value.Value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(AlphaCutoff)] = AlphaCutoff;
+ }
+
+ return AlphaCutoff;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the AlphaMode property.
+ ///
+ public async Task GetAlphaMode()
+ {
+ if (CoreJsModule is null)
+ {
+ return AlphaMode;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return AlphaMode;
+ }
+
+ // get the property value
+ JsNullableEnumWrapper? result = await CoreJsModule!.InvokeAsync?>("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "alphaMode");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ AlphaMode = (AlphaMode)result.Value.Value!;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(AlphaMode)] = AlphaMode;
+ }
+
+ return AlphaMode;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Color property.
+ ///
+ public async Task GetColor()
+ {
+ if (CoreJsModule is null)
+ {
+ return Color;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Color;
+ }
+
+ // get the property value
+ MapColor? result = await JsComponentReference!.InvokeAsync("getProperty",
+ CancellationTokenSource.Token, "color");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Color = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Color)] = Color;
+ }
+
+ return Color;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the ColorTexture property.
+ ///
+ public async Task GetColorTexture()
+ {
+ if (CoreJsModule is null)
+ {
+ return ColorTexture;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return ColorTexture;
+ }
+
+ MeshTexture? result = await JsComponentReference.InvokeAsync(
+ "getColorTexture", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ ColorTexture = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(ColorTexture)] = ColorTexture;
+ }
+
+ return ColorTexture;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the ColorTextureTransform property.
+ ///
+ public async Task GetColorTextureTransform()
+ {
+ if (CoreJsModule is null)
+ {
+ return ColorTextureTransform;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return ColorTextureTransform;
+ }
+
+ MeshTextureTransform? result = await JsComponentReference.InvokeAsync(
+ "getColorTextureTransform", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ ColorTextureTransform = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(ColorTextureTransform)] = ColorTextureTransform;
+ }
+
+ return ColorTextureTransform;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the DoubleSided property.
+ ///
+ public async Task GetDoubleSided()
+ {
+ if (CoreJsModule is null)
+ {
+ return DoubleSided;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return DoubleSided;
+ }
+
+ // get the property value
+ JsNullableBoolWrapper? result = await CoreJsModule!.InvokeAsync("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "doubleSided");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ DoubleSided = result.Value.Value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(DoubleSided)] = DoubleSided;
+ }
+
+ return DoubleSided;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the NormalTexture property.
+ ///
+ public async Task GetNormalTexture()
+ {
+ if (CoreJsModule is null)
+ {
+ return NormalTexture;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return NormalTexture;
+ }
+
+ MeshTexture? result = await JsComponentReference.InvokeAsync(
+ "getNormalTexture", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ NormalTexture = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(NormalTexture)] = NormalTexture;
+ }
+
+ return NormalTexture;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the NormalTextureTransform property.
+ ///
+ public async Task GetNormalTextureTransform()
+ {
+ if (CoreJsModule is null)
+ {
+ return NormalTextureTransform;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return NormalTextureTransform;
+ }
+
+ MeshTextureTransform? result = await JsComponentReference.InvokeAsync(
+ "getNormalTextureTransform", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ NormalTextureTransform = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(NormalTextureTransform)] = NormalTextureTransform;
+ }
+
+ return NormalTextureTransform;
+ }
+
+#endregion
+
+#region Property Setters
+
+ ///
+ /// Asynchronously set the value of the AlphaCutoff property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetAlphaCutoff(double? value)
+ {
+#pragma warning disable BL0005
+ AlphaCutoff = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(AlphaCutoff)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "alphaCutoff", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the AlphaMode property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetAlphaMode(AlphaMode? value)
+ {
+#pragma warning disable BL0005
+ AlphaMode = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(AlphaMode)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "alphaMode", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Color property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetColor(MapColor? value)
+ {
+#pragma warning disable BL0005
+ Color = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Color)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "color", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the ColorTexture property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetColorTexture(MeshTexture? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ ColorTexture = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(ColorTexture)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "colorTexture", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the ColorTextureTransform property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetColorTextureTransform(MeshTextureTransform? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ ColorTextureTransform = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(ColorTextureTransform)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "colorTextureTransform", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the DoubleSided property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetDoubleSided(bool? value)
+ {
+#pragma warning disable BL0005
+ DoubleSided = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(DoubleSided)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "doubleSided", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the NormalTexture property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetNormalTexture(MeshTexture? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ NormalTexture = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(NormalTexture)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "normalTexture", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the NormalTextureTransform property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetNormalTextureTransform(MeshTextureTransform? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ NormalTextureTransform = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(NormalTextureTransform)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "normalTextureTransform", value);
+ }
+
+#endregion
+
+}
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshMaterialMetallicRoughness.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshMaterialMetallicRoughness.cs
new file mode 100644
index 000000000..ebad95c13
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshMaterialMetallicRoughness.cs
@@ -0,0 +1,28 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+[ProtobufSerializable]
+public partial class MeshMaterialMetallicRoughness
+{
+ // Add custom code to this file to override generated code
+
+ ///
+ public override MeshComponentMaterialSerializationRecord ToProtobuf()
+ {
+ return new MeshComponentMaterialSerializationRecord(AlphaCutoff,
+ AlphaMode?.ToString().ToKebabCase(),
+ Color?.ToProtobuf(),
+ ColorTexture?.ToProtobuf(),
+ ColorTextureTransform?.ToProtobuf(),
+ DoubleSided,
+ NormalTexture?.ToProtobuf(),
+ NormalTextureTransform?.ToProtobuf(),
+ EmissiveColor?.ToProtobuf(),
+ EmissiveTexture?.ToProtobuf(),
+ EmissiveTextureTransform?.ToProtobuf(),
+ Metallic,
+ MetallicRoughnessTexture?.ToProtobuf(),
+ OcclusionTexture?.ToProtobuf(),
+ OcclusionTextureTransform?.ToProtobuf(),
+ Roughness);
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshMaterialMetallicRoughness.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshMaterialMetallicRoughness.gb.cs
new file mode 100644
index 000000000..de08efab5
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshMaterialMetallicRoughness.gb.cs
@@ -0,0 +1,883 @@
+// File auto-generated by dymaptic tooling. Any changes made here will be lost on future generation. To override functionality, use the relevant root .cs file.
+
+namespace dymaptic.GeoBlazor.Core.Components;
+
+
+///
+/// GeoBlazor Docs
+/// A material determines how a MeshComponent is visualized.
+/// ArcGIS Maps SDK for JavaScript
+///
+public partial class MeshMaterialMetallicRoughness : MeshMaterial,
+ IMeshComponentMaterial
+{
+
+ ///
+ /// Parameterless constructor for use as a Razor Component.
+ ///
+ [ActivatorUtilitiesConstructor]
+ public MeshMaterialMetallicRoughness()
+ {
+ }
+
+ ///
+ /// Constructor for use in C# code. Use named parameters (e.g., item1: value1, item2: value2) to set properties in any order.
+ ///
+ ///
+ /// Specifies how transparency on the object is handled.
+ /// default 0.5
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies how transparency on the object is handled.
+ /// default "auto"
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a single, uniform color for the mesh component.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a texture from which to get color information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// A transformation of UV mesh coordinates used to sample the color texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies whether both sides of each triangle are displayed, or only the front sides.
+ /// default true
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a single, uniform emissive color for the MeshComponent .
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a texture from which to get emissive color information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// A transformation of UV mesh coordinates used to sample the emissive texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies how much the material behaves like a metal.
+ /// default 1
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a texture from which to get the combined metallic/roughness information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies a texture from which to get normal information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// A transformation of UV mesh coordinates used to sample the normal texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Allows to specify a texture to get the occlusion information from.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// A transformation of UV mesh coordinates used to sample the occlusion texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Indicates how rough the surface of the material is.
+ /// default 1
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ public MeshMaterialMetallicRoughness(
+ double? alphaCutoff = null,
+ AlphaMode? alphaMode = null,
+ MapColor? color = null,
+ MeshTexture? colorTexture = null,
+ MeshTextureTransform? colorTextureTransform = null,
+ bool? doubleSided = null,
+ MapColor? emissiveColor = null,
+ MeshTexture? emissiveTexture = null,
+ MeshTextureTransform? emissiveTextureTransform = null,
+ double? metallic = null,
+ MeshTexture? metallicRoughnessTexture = null,
+ MeshTexture? normalTexture = null,
+ MeshTextureTransform? normalTextureTransform = null,
+ MeshTexture? occlusionTexture = null,
+ MeshTextureTransform? occlusionTextureTransform = null,
+ double? roughness = null)
+ {
+ AllowRender = false;
+#pragma warning disable BL0005
+ AlphaCutoff = alphaCutoff;
+ AlphaMode = alphaMode;
+ Color = color;
+ ColorTexture = colorTexture;
+ ColorTextureTransform = colorTextureTransform;
+ DoubleSided = doubleSided;
+ EmissiveColor = emissiveColor;
+ EmissiveTexture = emissiveTexture;
+ EmissiveTextureTransform = emissiveTextureTransform;
+ Metallic = metallic;
+ MetallicRoughnessTexture = metallicRoughnessTexture;
+ NormalTexture = normalTexture;
+ NormalTextureTransform = normalTextureTransform;
+ OcclusionTexture = occlusionTexture;
+ OcclusionTextureTransform = occlusionTextureTransform;
+ Roughness = roughness;
+#pragma warning restore BL0005
+ }
+
+
+#region Public Properties / Blazor Parameters
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies a single, uniform emissive color for the MeshComponent .
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MapColor? EmissiveColor { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies a texture from which to get emissive color information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTexture? EmissiveTexture { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// A transformation of UV mesh coordinates used to sample the emissive texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTextureTransform? EmissiveTextureTransform { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies how much the material behaves like a metal.
+ /// default 1
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public double? Metallic { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Specifies a texture from which to get the combined metallic/roughness information.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTexture? MetallicRoughnessTexture { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Allows to specify a texture to get the occlusion information from.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTexture? OcclusionTexture { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// A transformation of UV mesh coordinates used to sample the occlusion texture.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public MeshTextureTransform? OcclusionTextureTransform { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Indicates how rough the surface of the material is.
+ /// default 1
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public double? Roughness { get; set; }
+
+#endregion
+
+#region Property Getters
+
+ ///
+ /// Asynchronously retrieve the current value of the EmissiveColor property.
+ ///
+ public async Task GetEmissiveColor()
+ {
+ if (CoreJsModule is null)
+ {
+ return EmissiveColor;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return EmissiveColor;
+ }
+
+ // get the property value
+ MapColor? result = await JsComponentReference!.InvokeAsync("getProperty",
+ CancellationTokenSource.Token, "emissiveColor");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ EmissiveColor = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(EmissiveColor)] = EmissiveColor;
+ }
+
+ return EmissiveColor;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the EmissiveTexture property.
+ ///
+ public async Task GetEmissiveTexture()
+ {
+ if (CoreJsModule is null)
+ {
+ return EmissiveTexture;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return EmissiveTexture;
+ }
+
+ MeshTexture? result = await JsComponentReference.InvokeAsync(
+ "getEmissiveTexture", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ EmissiveTexture = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(EmissiveTexture)] = EmissiveTexture;
+ }
+
+ return EmissiveTexture;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the EmissiveTextureTransform property.
+ ///
+ public async Task GetEmissiveTextureTransform()
+ {
+ if (CoreJsModule is null)
+ {
+ return EmissiveTextureTransform;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return EmissiveTextureTransform;
+ }
+
+ MeshTextureTransform? result = await JsComponentReference.InvokeAsync(
+ "getEmissiveTextureTransform", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ EmissiveTextureTransform = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(EmissiveTextureTransform)] = EmissiveTextureTransform;
+ }
+
+ return EmissiveTextureTransform;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Metallic property.
+ ///
+ public async Task GetMetallic()
+ {
+ if (CoreJsModule is null)
+ {
+ return Metallic;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Metallic;
+ }
+
+ // get the property value
+ JsNullableDoubleWrapper? result = await CoreJsModule!.InvokeAsync("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "metallic");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ Metallic = result.Value.Value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Metallic)] = Metallic;
+ }
+
+ return Metallic;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the MetallicRoughnessTexture property.
+ ///
+ public async Task GetMetallicRoughnessTexture()
+ {
+ if (CoreJsModule is null)
+ {
+ return MetallicRoughnessTexture;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return MetallicRoughnessTexture;
+ }
+
+ MeshTexture? result = await JsComponentReference.InvokeAsync(
+ "getMetallicRoughnessTexture", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ MetallicRoughnessTexture = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(MetallicRoughnessTexture)] = MetallicRoughnessTexture;
+ }
+
+ return MetallicRoughnessTexture;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the OcclusionTexture property.
+ ///
+ public async Task GetOcclusionTexture()
+ {
+ if (CoreJsModule is null)
+ {
+ return OcclusionTexture;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return OcclusionTexture;
+ }
+
+ MeshTexture? result = await JsComponentReference.InvokeAsync(
+ "getOcclusionTexture", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ OcclusionTexture = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(OcclusionTexture)] = OcclusionTexture;
+ }
+
+ return OcclusionTexture;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the OcclusionTextureTransform property.
+ ///
+ public async Task GetOcclusionTextureTransform()
+ {
+ if (CoreJsModule is null)
+ {
+ return OcclusionTextureTransform;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return OcclusionTextureTransform;
+ }
+
+ MeshTextureTransform? result = await JsComponentReference.InvokeAsync(
+ "getOcclusionTextureTransform", CancellationTokenSource.Token);
+
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ OcclusionTextureTransform = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(OcclusionTextureTransform)] = OcclusionTextureTransform;
+ }
+
+ return OcclusionTextureTransform;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Roughness property.
+ ///
+ public async Task GetRoughness()
+ {
+ if (CoreJsModule is null)
+ {
+ return Roughness;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Roughness;
+ }
+
+ // get the property value
+ JsNullableDoubleWrapper? result = await CoreJsModule!.InvokeAsync("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "roughness");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ Roughness = result.Value.Value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Roughness)] = Roughness;
+ }
+
+ return Roughness;
+ }
+
+#endregion
+
+#region Property Setters
+
+ ///
+ /// Asynchronously set the value of the EmissiveColor property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetEmissiveColor(MapColor? value)
+ {
+#pragma warning disable BL0005
+ EmissiveColor = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(EmissiveColor)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "emissiveColor", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the EmissiveTexture property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetEmissiveTexture(MeshTexture? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ EmissiveTexture = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(EmissiveTexture)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "emissiveTexture", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the EmissiveTextureTransform property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetEmissiveTextureTransform(MeshTextureTransform? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ EmissiveTextureTransform = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(EmissiveTextureTransform)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "emissiveTextureTransform", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Metallic property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetMetallic(double? value)
+ {
+#pragma warning disable BL0005
+ Metallic = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Metallic)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "metallic", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the MetallicRoughnessTexture property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetMetallicRoughnessTexture(MeshTexture? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ MetallicRoughnessTexture = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(MetallicRoughnessTexture)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "metallicRoughnessTexture", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the OcclusionTexture property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetOcclusionTexture(MeshTexture? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ OcclusionTexture = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(OcclusionTexture)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "occlusionTexture", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the OcclusionTextureTransform property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetOcclusionTextureTransform(MeshTextureTransform? value)
+ {
+ if (value is not null)
+ {
+ value.CoreJsModule = CoreJsModule;
+ value.Parent = this;
+ value.Layer = Layer;
+ value.View = View;
+ }
+
+#pragma warning disable BL0005
+ OcclusionTextureTransform = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(OcclusionTextureTransform)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "occlusionTextureTransform", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Roughness property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetRoughness(double? value)
+ {
+#pragma warning disable BL0005
+ Roughness = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Roughness)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "roughness", value);
+ }
+
+#endregion
+
+}
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshTexture.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshTexture.cs
new file mode 100644
index 000000000..c800ef64f
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshTexture.cs
@@ -0,0 +1,518 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+///
+/// GeoBlazor Docs
+/// MeshTexture represents image data to be used for MeshMaterial or MeshMaterialMetallicRoughness .
+/// ArcGIS Maps SDK for JavaScript
+///
+[CodeGenerationIgnore]
+[ProtobufSerializable]
+public class MeshTexture : MapComponent, IProtobufSerializable
+{
+
+ ///
+ /// Parameterless constructor for use as a Razor Component.
+ ///
+ [ActivatorUtilitiesConstructor]
+ public MeshTexture()
+ {
+ }
+
+ ///
+ /// Constructor for use in C# code. Use named parameters (e.g., item1: value1, item2: value2) to set properties in any order.
+ ///
+ ///
+ /// A direct reference to the image or video element.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// A direct reference to the image data.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Specifies how uv coordinates outside the [0, 1] range are handled.
+ /// default "repeat"
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Indicates whether the image data should be interpreted as being semi-transparent.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// The url to the image resource.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ public MeshTexture(
+ ElementReference? htmlData = null,
+ ImageData? imageData = null,
+ SeparableWrapModes? wrap = null,
+ bool? transparent = null,
+ string? url = null)
+ {
+ AllowRender = false;
+#pragma warning disable BL0005
+ HtmlData = htmlData;
+ ImageData = imageData;
+ Wrap = wrap;
+ Transparent = transparent;
+ Url = url;
+#pragma warning restore BL0005
+ }
+
+
+#region Public Properties / Blazor Parameters
+
+ ///
+ /// A direct reference to the image or video data.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public ElementReference? HtmlData { get; set; }
+
+ ///
+ /// A direct reference to the image or video data.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public ImageData? ImageData { get; set; }
+
+ ///
+ /// Specifies how uv coordinates outside the [0, 1] range are handled.
+ /// default "repeat"
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public SeparableWrapModes? Wrap { get; set; }
+
+ ///
+ /// Indicates whether the image data should be interpreted as being semi-transparent.
+ /// default undefined
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public bool? Transparent { get; set; }
+
+ ///
+ /// The url to the image resource.
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public string? Url { get; set; }
+
+#endregion
+
+#region Property Getters
+
+ ///
+ /// Asynchronously retrieve the current value of the HtmlData property.
+ ///
+ public async Task GetHtmlData()
+ {
+ if (CoreJsModule is null)
+ {
+ return HtmlData;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return HtmlData;
+ }
+
+ // get the property value
+ JsNullableElementReferenceWrapper? result = await CoreJsModule!.InvokeAsync(
+ "getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "htmlData");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ HtmlData = result.Value.Value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(HtmlData)] = HtmlData;
+ }
+
+ return HtmlData;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the ImageData property.
+ ///
+ public async Task GetImageData()
+ {
+ if (CoreJsModule is null)
+ {
+ return ImageData;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return ImageData;
+ }
+
+ // get the property value
+ ImageData? result = await JsComponentReference!.InvokeAsync("getProperty",
+ CancellationTokenSource.Token, "data");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ ImageData = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(ImageData)] = ImageData;
+ }
+
+ return ImageData;
+ }
+
+
+ ///
+ /// Asynchronously retrieve the current value of the SeparableWrapModesWrap property.
+ ///
+ public async Task GetWrap()
+ {
+ if (CoreJsModule is null)
+ {
+ return Wrap;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Wrap;
+ }
+
+ // get the property value
+ SeparableWrapModes? result = await JsComponentReference!.InvokeAsync("getProperty",
+ CancellationTokenSource.Token, "wrap");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Wrap = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Wrap)] = Wrap;
+ }
+
+ return Wrap;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Transparent property.
+ ///
+ public async Task GetTransparent()
+ {
+ if (CoreJsModule is null)
+ {
+ return Transparent;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Transparent;
+ }
+
+ // get the property value
+ JsNullableBoolWrapper? result = await CoreJsModule!.InvokeAsync("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "transparent");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ Transparent = result.Value.Value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Transparent)] = Transparent;
+ }
+
+ return Transparent;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Url property.
+ ///
+ public async Task GetUrl()
+ {
+ if (CoreJsModule is null)
+ {
+ return Url;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Url;
+ }
+
+ // get the property value
+ string? result = await JsComponentReference!.InvokeAsync("getProperty",
+ CancellationTokenSource.Token, "url");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Url = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Url)] = Url;
+ }
+
+ return Url;
+ }
+
+#endregion
+
+#region Property Setters
+
+ ///
+ /// Asynchronously set the value of the HtmlData property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetHtmlData(ElementReference? value)
+ {
+#pragma warning disable BL0005
+ HtmlData = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(HtmlData)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "data", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the ImageData property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetImageData(ImageData? value)
+ {
+#pragma warning disable BL0005
+ ImageData = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(ImageData)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "data", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the SeparableWrapModesWrap property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetSeparableWrapModesWrap(SeparableWrapModes? value)
+ {
+#pragma warning disable BL0005
+ Wrap = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Wrap)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "wrap", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Transparent property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetTransparent(bool? value)
+ {
+#pragma warning disable BL0005
+ Transparent = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Transparent)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "transparent", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Url property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetUrl(string? value)
+ {
+#pragma warning disable BL0005
+ Url = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Url)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "url", value);
+ }
+
+#endregion
+
+ ///
+ public MeshTextureSerializationRecord ToProtobuf()
+ {
+ return new MeshTextureSerializationRecord(ImageData?.ToProtobuf(),
+ Wrap is null
+ ? null
+ : [
+ Wrap?.Horizontal?.ToString().ToKebabCase(),
+ Wrap?.Vertical?.ToString().ToKebabCase()
+ ],
+ Transparent,
+ Url);
+ }
+}
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshTextureTransform.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshTextureTransform.cs
new file mode 100644
index 000000000..7f8746fd6
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshTextureTransform.cs
@@ -0,0 +1,14 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+[ProtobufSerializable]
+public partial class MeshTextureTransform: IProtobufSerializable
+{
+ // Add custom code to this file to override generated code
+
+ ///
+ public MeshTextureTransformSerializationRecord ToProtobuf()
+ {
+ return new MeshTextureTransformSerializationRecord(Offset?.ToArray(), Rotation,
+ Scale?.ToArray());
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshTextureTransform.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshTextureTransform.gb.cs
new file mode 100644
index 000000000..c51bed4f7
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshTextureTransform.gb.cs
@@ -0,0 +1,396 @@
+// File auto-generated by dymaptic tooling. Any changes made here will be lost on future generation. To override functionality, use the relevant root .cs file.
+
+namespace dymaptic.GeoBlazor.Core.Components;
+
+
+///
+/// GeoBlazor Docs
+/// MeshTextureTransform represents a transformation of UV mesh coordinates used to sample a
+/// MeshTexture .
+/// ArcGIS Maps SDK for JavaScript
+///
+public partial class MeshTextureTransform : MapComponent
+{
+
+ ///
+ /// Parameterless constructor for use as a Razor Component.
+ ///
+ [ActivatorUtilitiesConstructor]
+ public MeshTextureTransform()
+ {
+ }
+
+ ///
+ /// Constructor for use in C# code. Use named parameters (e.g., item1: value1, item2: value2) to set properties in any order.
+ ///
+ ///
+ /// The offset of the UV coordinate origin as a factor of the texture dimensions.
+ /// default [0, 0]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// The rotation of the UV coordinates in degrees, counter-clockwise around the origin.
+ /// default 0
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// The scale factor applied to the components of the UV coordinates.
+ /// default [1, 1]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ public MeshTextureTransform(
+ IReadOnlyList? offset = null,
+ double? rotation = null,
+ IReadOnlyList? scale = null)
+ {
+ AllowRender = false;
+#pragma warning disable BL0005
+ Offset = offset;
+ Rotation = rotation;
+ Scale = scale;
+#pragma warning restore BL0005
+ }
+
+
+#region Public Properties / Blazor Parameters
+
+ ///
+ /// GeoBlazor Docs
+ /// The offset of the UV coordinate origin as a factor of the texture dimensions.
+ /// default [0, 0]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public IReadOnlyList? Offset { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// The rotation of the UV coordinates in degrees, counter-clockwise around the origin.
+ /// default 0
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public double? Rotation { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// The scale factor applied to the components of the UV coordinates.
+ /// default [1, 1]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public IReadOnlyList? Scale { get; set; }
+
+#endregion
+
+#region Property Getters
+
+ ///
+ /// Asynchronously retrieve the current value of the Offset property.
+ ///
+ public async Task?> GetOffset()
+ {
+ if (CoreJsModule is null)
+ {
+ return Offset;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Offset;
+ }
+
+ // get the property value
+ IReadOnlyList? result = await JsComponentReference!.InvokeAsync?>("getProperty",
+ CancellationTokenSource.Token, "offset");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Offset = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Offset)] = Offset;
+ }
+
+ return Offset;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Rotation property.
+ ///
+ public async Task GetRotation()
+ {
+ if (CoreJsModule is null)
+ {
+ return Rotation;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Rotation;
+ }
+
+ // get the property value
+ JsNullableDoubleWrapper? result = await CoreJsModule!.InvokeAsync("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "rotation");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ Rotation = result.Value.Value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Rotation)] = Rotation;
+ }
+
+ return Rotation;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Scale property.
+ ///
+ public async Task?> GetScale()
+ {
+ if (CoreJsModule is null)
+ {
+ return Scale;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Scale;
+ }
+
+ // get the property value
+ IReadOnlyList? result = await JsComponentReference!.InvokeAsync?>("getProperty",
+ CancellationTokenSource.Token, "scale");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Scale = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Scale)] = Scale;
+ }
+
+ return Scale;
+ }
+
+#endregion
+
+#region Property Setters
+
+ ///
+ /// Asynchronously set the value of the Offset property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetOffset(IReadOnlyList? value)
+ {
+#pragma warning disable BL0005
+ Offset = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Offset)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "offset", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Rotation property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetRotation(double? value)
+ {
+#pragma warning disable BL0005
+ Rotation = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Rotation)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "rotation", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Scale property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetScale(IReadOnlyList? value)
+ {
+#pragma warning disable BL0005
+ Scale = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Scale)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "scale", value);
+ }
+
+#endregion
+
+#region Add to Collection Methods
+
+ ///
+ /// Asynchronously adds elements to the Offset property.
+ ///
+ ///
+ /// The elements to add.
+ ///
+ public async Task AddToOffset(params double[] values)
+ {
+ double[] join = Offset is null
+ ? values
+ : [..Offset, ..values];
+ await SetOffset(join);
+ }
+
+ ///
+ /// Asynchronously adds elements to the Scale property.
+ ///
+ ///
+ /// The elements to add.
+ ///
+ public async Task AddToScale(params double[] values)
+ {
+ double[] join = Scale is null
+ ? values
+ : [..Scale, ..values];
+ await SetScale(join);
+ }
+
+#endregion
+
+#region Remove From Collection Methods
+
+
+ ///
+ /// Asynchronously remove an element from the Offset property.
+ ///
+ ///
+ /// The elements to remove.
+ ///
+ public async Task RemoveFromOffset(params double[] values)
+ {
+ if (Offset is null)
+ {
+ return;
+ }
+ await SetOffset(Offset.Except(values).ToArray());
+ }
+
+
+ ///
+ /// Asynchronously remove an element from the Scale property.
+ ///
+ ///
+ /// The elements to remove.
+ ///
+ public async Task RemoveFromScale(params double[] values)
+ {
+ if (Scale is null)
+ {
+ return;
+ }
+ await SetScale(Scale.Except(values).ToArray());
+ }
+
+#endregion
+
+}
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshTransform.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshTransform.cs
new file mode 100644
index 000000000..db8a44295
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshTransform.cs
@@ -0,0 +1,16 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+[ProtobufSerializable]
+public partial class MeshTransform: IProtobufSerializable
+{
+ // Add custom code to this file to override generated code
+ ///
+ public MeshTransformSerializationRecord ToProtobuf()
+ {
+ return new MeshTransformSerializationRecord(
+ RotationAngle,
+ RotationAxis?.ToArray(),
+ Scale?.ToArray(),
+ Translation?.ToArray());
+ }
+}
\ No newline at end of file
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshTransform.gb.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshTransform.gb.cs
new file mode 100644
index 000000000..2a1e33410
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshTransform.gb.cs
@@ -0,0 +1,519 @@
+// File auto-generated by dymaptic tooling. Any changes made here will be lost on future generation. To override functionality, use the relevant root .cs file.
+
+namespace dymaptic.GeoBlazor.Core.Components;
+
+
+///
+/// GeoBlazor Docs
+/// A mesh transform.
+/// ArcGIS Maps SDK for JavaScript
+///
+public partial class MeshTransform : MapComponent
+{
+
+ ///
+ /// Parameterless constructor for use as a Razor Component.
+ ///
+ [ActivatorUtilitiesConstructor]
+ public MeshTransform()
+ {
+ }
+
+ ///
+ /// Constructor for use in C# code. Use named parameters (e.g., item1: value1, item2: value2) to set properties in any order.
+ ///
+ ///
+ /// Rotation angle in degrees.
+ /// default 0
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Axis of rotation.
+ /// default [0, 0, 1]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Scale.
+ /// default [1, 1, 1]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ ///
+ /// Translation.
+ /// default [0, 0, 0]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ public MeshTransform(
+ double? rotationAngle = null,
+ IReadOnlyList? rotationAxis = null,
+ IReadOnlyList? scale = null,
+ IReadOnlyList? translation = null)
+ {
+ AllowRender = false;
+#pragma warning disable BL0005
+ RotationAngle = rotationAngle;
+ RotationAxis = rotationAxis;
+ Scale = scale;
+ Translation = translation;
+#pragma warning restore BL0005
+ }
+
+
+#region Public Properties / Blazor Parameters
+
+ ///
+ /// GeoBlazor Docs
+ /// Rotation angle in degrees.
+ /// default 0
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public double? RotationAngle { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Axis of rotation.
+ /// default [0, 0, 1]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public IReadOnlyList? RotationAxis { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Scale.
+ /// default [1, 1, 1]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public IReadOnlyList? Scale { get; set; }
+
+ ///
+ /// GeoBlazor Docs
+ /// Translation.
+ /// default [0, 0, 0]
+ /// ArcGIS Maps SDK for JavaScript
+ ///
+ [ArcGISProperty]
+ [Parameter]
+ [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
+ public IReadOnlyList? Translation { get; set; }
+
+#endregion
+
+#region Property Getters
+
+ ///
+ /// Asynchronously retrieve the current value of the RotationAngle property.
+ ///
+ public async Task GetRotationAngle()
+ {
+ if (CoreJsModule is null)
+ {
+ return RotationAngle;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return RotationAngle;
+ }
+
+ // get the property value
+ JsNullableDoubleWrapper? result = await CoreJsModule!.InvokeAsync("getNullableValueTypedProperty",
+ CancellationTokenSource.Token, JsComponentReference, "rotationAngle");
+ if (result is { Value: not null })
+ {
+#pragma warning disable BL0005
+ RotationAngle = result.Value.Value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(RotationAngle)] = RotationAngle;
+ }
+
+ return RotationAngle;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the RotationAxis property.
+ ///
+ public async Task?> GetRotationAxis()
+ {
+ if (CoreJsModule is null)
+ {
+ return RotationAxis;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return RotationAxis;
+ }
+
+ // get the property value
+ IReadOnlyList? result = await JsComponentReference!.InvokeAsync?>("getProperty",
+ CancellationTokenSource.Token, "rotationAxis");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ RotationAxis = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(RotationAxis)] = RotationAxis;
+ }
+
+ return RotationAxis;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Scale property.
+ ///
+ public async Task?> GetScale()
+ {
+ if (CoreJsModule is null)
+ {
+ return Scale;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Scale;
+ }
+
+ // get the property value
+ IReadOnlyList? result = await JsComponentReference!.InvokeAsync?>("getProperty",
+ CancellationTokenSource.Token, "scale");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Scale = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Scale)] = Scale;
+ }
+
+ return Scale;
+ }
+
+ ///
+ /// Asynchronously retrieve the current value of the Translation property.
+ ///
+ public async Task?> GetTranslation()
+ {
+ if (CoreJsModule is null)
+ {
+ return Translation;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return Translation;
+ }
+
+ // get the property value
+ IReadOnlyList? result = await JsComponentReference!.InvokeAsync?>("getProperty",
+ CancellationTokenSource.Token, "translation");
+ if (result is not null)
+ {
+#pragma warning disable BL0005
+ Translation = result;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Translation)] = Translation;
+ }
+
+ return Translation;
+ }
+
+#endregion
+
+#region Property Setters
+
+ ///
+ /// Asynchronously set the value of the RotationAngle property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetRotationAngle(double? value)
+ {
+#pragma warning disable BL0005
+ RotationAngle = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(RotationAngle)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "rotationAngle", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the RotationAxis property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetRotationAxis(IReadOnlyList? value)
+ {
+#pragma warning disable BL0005
+ RotationAxis = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(RotationAxis)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "rotationAxis", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Scale property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetScale(IReadOnlyList? value)
+ {
+#pragma warning disable BL0005
+ Scale = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Scale)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "scale", value);
+ }
+
+ ///
+ /// Asynchronously set the value of the Translation property after render.
+ ///
+ ///
+ /// The value to set.
+ ///
+ public async Task SetTranslation(IReadOnlyList? value)
+ {
+#pragma warning disable BL0005
+ Translation = value;
+#pragma warning restore BL0005
+ ModifiedParameters[nameof(Translation)] = value;
+
+ if (CoreJsModule is null)
+ {
+ return;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync(
+ "getJsComponent", CancellationTokenSource.Token, Id);
+ }
+ catch (JSException)
+ {
+ // this is expected if the component is not yet built
+ }
+
+ if (JsComponentReference is null)
+ {
+ return;
+ }
+
+ await CoreJsModule.InvokeVoidAsync("setProperty", CancellationTokenSource.Token,
+ JsComponentReference, "translation", value);
+ }
+
+#endregion
+
+#region Add to Collection Methods
+
+ ///
+ /// Asynchronously adds elements to the RotationAxis property.
+ ///
+ ///
+ /// The elements to add.
+ ///
+ public async Task AddToRotationAxis(params double[] values)
+ {
+ double[] join = RotationAxis is null
+ ? values
+ : [..RotationAxis, ..values];
+ await SetRotationAxis(join);
+ }
+
+ ///
+ /// Asynchronously adds elements to the Scale property.
+ ///
+ ///
+ /// The elements to add.
+ ///
+ public async Task AddToScale(params double[] values)
+ {
+ double[] join = Scale is null
+ ? values
+ : [..Scale, ..values];
+ await SetScale(join);
+ }
+
+ ///
+ /// Asynchronously adds elements to the Translation property.
+ ///
+ ///
+ /// The elements to add.
+ ///
+ public async Task AddToTranslation(params double[] values)
+ {
+ double[] join = Translation is null
+ ? values
+ : [..Translation, ..values];
+ await SetTranslation(join);
+ }
+
+#endregion
+
+#region Remove From Collection Methods
+
+
+ ///
+ /// Asynchronously remove an element from the RotationAxis property.
+ ///
+ ///
+ /// The elements to remove.
+ ///
+ public async Task RemoveFromRotationAxis(params double[] values)
+ {
+ if (RotationAxis is null)
+ {
+ return;
+ }
+ await SetRotationAxis(RotationAxis.Except(values).ToArray());
+ }
+
+
+ ///
+ /// Asynchronously remove an element from the Scale property.
+ ///
+ ///
+ /// The elements to remove.
+ ///
+ public async Task RemoveFromScale(params double[] values)
+ {
+ if (Scale is null)
+ {
+ return;
+ }
+ await SetScale(Scale.Except(values).ToArray());
+ }
+
+
+ ///
+ /// Asynchronously remove an element from the Translation property.
+ ///
+ ///
+ /// The elements to remove.
+ ///
+ public async Task RemoveFromTranslation(params double[] values)
+ {
+ if (Translation is null)
+ {
+ return;
+ }
+ await SetTranslation(Translation.Except(values).ToArray());
+ }
+
+#endregion
+
+}
diff --git a/src/dymaptic.GeoBlazor.Core/Components/MeshVertexAttributes.cs b/src/dymaptic.GeoBlazor.Core/Components/MeshVertexAttributes.cs
new file mode 100644
index 000000000..bb9efa7f8
--- /dev/null
+++ b/src/dymaptic.GeoBlazor.Core/Components/MeshVertexAttributes.cs
@@ -0,0 +1,60 @@
+namespace dymaptic.GeoBlazor.Core.Components;
+
+[ProtobufSerializable]
+public partial class MeshVertexAttributes: IProtobufSerializable
+{
+ // Add custom code to this file to override generated code
+
+ ///
+ /// Asynchronously retrieve the current value of the Color property.
+ ///
+ [CodeGenerationIgnore]
+ public async Task GetColor()
+ {
+ if (CoreJsModule is null)
+ {
+ return Color;
+ }
+
+ try
+ {
+ JsComponentReference ??= await CoreJsModule.InvokeAsync