diff --git a/data/lyrx/kai_blattpk100_01.lyrx b/data/lyrx/kai_blattpk100_01.lyrx new file mode 100644 index 0000000..c49fc38 --- /dev/null +++ b/data/lyrx/kai_blattpk100_01.lyrx @@ -0,0 +1,693 @@ +{ + "type" : "CIMLayerDocument", + "version" : "2.6.0", + "build" : 24783, + "layers" : [ + "CIMPATH=map/kai_blattpk100_20190101.xml" + ], + "layerDefinitions" : [ + { + "type" : "CIMFeatureLayer", + "name" : "PK100 Blatteinteilung und Stand", + "uRI" : "CIMPATH=map/kai_blattpk100_20190101.xml", + "sourceModifiedTime" : { + "type" : "TimeInstant" + }, + "useSourceMetadata" : true, + "description" : "kai_blattpk100_20190101", + "layerElevation" : { + "type" : "CIMLayerElevationSurface", + "mapElevationID" : "{2FE8A72A-C1A6-43B6-9128-2893BEBC5590}" + }, + "expanded" : true, + "layerType" : "Operational", + "showLegends" : true, + "transparency" : 50, + "visibility" : true, + "displayCacheType" : "Permanent", + "maxDisplayCacheAge" : 5, + "showPopups" : true, + "serviceLayerID" : -1, + "refreshRate" : -1, + "refreshRateUnit" : "esriTimeUnitsSeconds", + "autoGenerateFeatureTemplates" : true, + "featureElevationExpression" : "0", + "featureTable" : { + "type" : "CIMFeatureTable", + "displayField" : "NAME", + "editable" : true, + "timeFields" : { + "type" : "CIMTimeTableDefinition" + }, + "timeDefinition" : { + "type" : "CIMTimeDataDefinition", + "hasLiveData" : true + }, + "timeDisplayDefinition" : { + "type" : "CIMTimeDisplayDefinition", + "timeInterval" : 0, + "timeIntervalUnits" : "esriTimeUnitsHours", + "timeOffsetUnits" : "esriTimeUnitsYears" + }, + "dataConnection" : { + "type" : "CIMStandardDataConnection", + "workspaceConnectionString" : "", + "workspaceFactory" : "FileGDB", + "dataset" : "kai_blattpk100_20190101", + "datasetType" : "esriDTFeatureClass" + }, + "studyAreaSpatialRel" : "esriSpatialRelUndefined", + "searchOrder" : "esriSearchOrderSpatial" + }, + "htmlPopupEnabled" : true, + "htmlPopupFormat" : { + "type" : "CIMHtmlPopupFormat", + "htmlUseCodedDomainValues" : true, + "htmlPresentationStyle" : "TwoColumnTable" + }, + "isFlattened" : true, + "selectable" : true, + "featureCacheType" : "Session", + "displayFiltersType" : "ByScale", + "labelClasses" : [ + { + "type" : "CIMLabelClass", + "expression" : "[NUMMER]", + "expressionEngine" : "VBScript", + "featuresToLabel" : "AllVisibleFeatures", + "maplexLabelPlacementProperties" : { + "type" : "CIMMaplexLabelPlacementProperties", + "featureType" : "Polygon", + "avoidPolygonHoles" : true, + "canOverrunFeature" : true, + "canPlaceLabelOutsidePolygon" : false, + "canRemoveOverlappingLabel" : true, + "canStackLabel" : true, + "connectionType" : "Unambiguous", + "constrainOffset" : "NoConstraint", + "contourAlignmentType" : "Page", + "contourLadderType" : "Straight", + "contourMaximumAngle" : 90, + "enableConnection" : true, + "featureWeight" : 0, + "fontHeightReductionLimit" : 4, + "fontHeightReductionStep" : 0.5, + "fontWidthReductionLimit" : 90, + "fontWidthReductionStep" : 5, + "graticuleAlignmentType" : "Straight", + "keyNumberGroupName" : "Default", + "labelBuffer" : 15, + "labelLargestPolygon" : false, + "labelPriority" : -1, + "labelStackingProperties" : { + "type" : "CIMMaplexLabelStackingProperties", + "stackAlignment" : "ChooseBest", + "maximumNumberOfLines" : 3, + "minimumNumberOfCharsPerLine" : 3, + "maximumNumberOfCharsPerLine" : 24, + "separators" : [ + { + "type" : "CIMMaplexStackingSeparator", + "separator" : " ", + "splitAfter" : true + }, + { + "type" : "CIMMaplexStackingSeparator", + "separator" : ",", + "visible" : true, + "splitAfter" : true + } + ] + }, + "lineFeatureType" : "General", + "linePlacementMethod" : "OffsetCurvedFromLine", + "maximumLabelOverrun" : 100, + "maximumLabelOverrunUnit" : "Point", + "minimumFeatureSizeUnit" : "Map", + "multiPartOption" : "OneLabelPerPart", + "offsetAlongLineProperties" : { + "type" : "CIMMaplexOffsetAlongLineProperties", + "placementMethod" : "BestPositionAlongLine", + "labelAnchorPoint" : "CenterOfLabel", + "distanceUnit" : "Percentage", + "useLineDirection" : true + }, + "pointExternalZonePriorities" : { + "type" : "CIMMaplexExternalZonePriorities", + "aboveLeft" : 4, + "aboveCenter" : 2, + "aboveRight" : 1, + "centerRight" : 3, + "belowRight" : 5, + "belowCenter" : 7, + "belowLeft" : 8, + "centerLeft" : 6 + }, + "pointPlacementMethod" : "AroundPoint", + "polygonAnchorPointType" : "GeometricCenter", + "polygonBoundaryWeight" : 0, + "polygonExternalZones" : { + "type" : "CIMMaplexExternalZonePriorities", + "aboveLeft" : 4, + "aboveCenter" : 2, + "aboveRight" : 1, + "centerRight" : 3, + "belowRight" : 5, + "belowCenter" : 7, + "belowLeft" : 8, + "centerLeft" : 6 + }, + "polygonFeatureType" : "General", + "polygonInternalZones" : { + "type" : "CIMMaplexInternalZonePriorities", + "center" : 1 + }, + "polygonPlacementMethod" : "HorizontalInPolygon", + "primaryOffset" : 1, + "primaryOffsetUnit" : "Point", + "removeExtraWhiteSpace" : true, + "repetitionIntervalUnit" : "Map", + "rotationProperties" : { + "type" : "CIMMaplexRotationProperties", + "rotationType" : "Arithmetic", + "alignmentType" : "Straight" + }, + "secondaryOffset" : 100, + "strategyPriorities" : { + "type" : "CIMMaplexStrategyPriorities", + "stacking" : 1, + "overrun" : 2, + "fontCompression" : 3, + "fontReduction" : 4, + "abbreviation" : 5 + }, + "thinningDistanceUnit" : "Point", + "truncationMarkerCharacter" : ".", + "truncationMinimumLength" : 1, + "truncationPreferredCharacters" : "aeiou" + }, + "name" : "Default", + "priority" : 1, + "standardLabelPlacementProperties" : { + "type" : "CIMStandardLabelPlacementProperties", + "featureType" : "Line", + "featureWeight" : "Low", + "labelWeight" : "High", + "numLabelsOption" : "OneLabelPerName", + "lineLabelPosition" : { + "type" : "CIMStandardLineLabelPosition", + "above" : true, + "inLine" : true, + "parallel" : true + }, + "lineLabelPriorities" : { + "type" : "CIMStandardLineLabelPriorities", + "aboveStart" : 3, + "aboveAlong" : 3, + "aboveEnd" : 3, + "centerStart" : 3, + "centerAlong" : 3, + "centerEnd" : 3, + "belowStart" : 3, + "belowAlong" : 3, + "belowEnd" : 3 + }, + "pointPlacementMethod" : "AroundPoint", + "pointPlacementPriorities" : { + "type" : "CIMStandardPointPlacementPriorities", + "aboveLeft" : 2, + "aboveCenter" : 2, + "aboveRight" : 1, + "centerLeft" : 3, + "centerRight" : 2, + "belowLeft" : 3, + "belowCenter" : 3, + "belowRight" : 2 + }, + "rotationType" : "Arithmetic", + "polygonPlacementMethod" : "AlwaysHorizontal" + }, + "textSymbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMTextSymbol", + "blockProgression" : "TTB", + "compatibilityMode" : true, + "depth3D" : 1, + "drawSoftHyphen" : true, + "extrapolateBaselines" : true, + "flipAngle" : 90, + "fontEffects" : "Normal", + "fontEncoding" : "Unicode", + "fontFamilyName" : "Arial", + "fontStyleName" : "Regular", + "fontType" : "Unspecified", + "haloSize" : 1, + "height" : 8, + "hinting" : "Default", + "horizontalAlignment" : "Center", + "kerning" : true, + "letterWidth" : 100, + "ligatures" : true, + "lineGapType" : "ExtraLeading", + "shadowColor" : { + "type" : "CIMRGBColor", + "values" : [ + 0, + 0, + 0, + 100 + ] + }, + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 0, + 0, + 0, + 100 + ] + } + } + ] + }, + "textCase" : "Normal", + "textDirection" : "LTR", + "verticalAlignment" : "Bottom", + "verticalGlyphOrientation" : "Right", + "wordSpacing" : 100, + "billboardMode3D" : "FaceNearPlane" + } + }, + "useCodedValue" : true, + "whereClause" : "STAND >0", + "visibility" : true, + "iD" : -1 + } + ], + "labelVisibility" : true, + "renderer" : { + "type" : "CIMUniqueValueRenderer", + "colorRamp" : { + "type" : "CIMRandomHSVColorRamp", + "colorSpace" : { + "type" : "CIMICCColorSpace", + "url" : "Default RGB" + }, + "maxH" : 360, + "minS" : 15, + "maxS" : 30, + "minV" : 99, + "maxV" : 100, + "minAlpha" : 100, + "maxAlpha" : 100 + }, + "defaultLabel" : "", + "defaultSymbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidStroke", + "enable" : true, + "capStyle" : "Round", + "joinStyle" : "Round", + "lineStyle3D" : "Strip", + "miterLimit" : 10, + "width" : 0.40000000000000002, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 110, + 110, + 110, + 100 + ] + } + }, + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 203, + 247, + 220, + 100 + ] + } + } + ] + } + }, + "defaultSymbolPatch" : "Default", + "fields" : [ + "STAND" + ], + "groups" : [ + { + "type" : "CIMUniqueValueGroup", + "classes" : [ + { + "type" : "CIMUniqueValueClass", + "label" : "2012", + "patch" : "Default", + "symbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidStroke", + "enable" : true, + "capStyle" : "Round", + "joinStyle" : "Round", + "lineStyle3D" : "Strip", + "miterLimit" : 10, + "width" : 0.69999999999999996, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 110, + 110, + 110, + 100 + ] + } + }, + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMHSVColor", + "values" : [ + 202.30000000000001, + 56.780000000000001, + 78.040000000000006, + 100 + ] + } + } + ] + } + }, + "values" : [ + { + "type" : "CIMUniqueValue", + "fieldValues" : [ + "2012" + ] + } + ], + "visible" : true + }, + { + "type" : "CIMUniqueValueClass", + "editable" : true, + "label" : "2013", + "patch" : "Default", + "symbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidStroke", + "enable" : true, + "capStyle" : "Round", + "joinStyle" : "Round", + "lineStyle3D" : "Strip", + "miterLimit" : 10, + "width" : 0.69999999999999996, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 110, + 110, + 110, + 100 + ] + } + }, + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMHSVColor", + "values" : [ + 58.82, + 65.109999999999999, + 92.159999999999997, + 100 + ] + } + } + ] + } + }, + "values" : [ + { + "type" : "CIMUniqueValue", + "fieldValues" : [ + "2013" + ] + } + ], + "visible" : true + }, + { + "type" : "CIMUniqueValueClass", + "editable" : true, + "label" : "2014", + "patch" : "Default", + "symbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidStroke", + "enable" : true, + "capStyle" : "Round", + "joinStyle" : "Round", + "lineStyle3D" : "Strip", + "miterLimit" : 10, + "width" : 0.69999999999999996, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 110, + 110, + 110, + 100 + ] + } + }, + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMHSVColor", + "values" : [ + 297.01999999999998, + 64.980000000000004, + 85.099999999999994, + 100 + ] + } + } + ] + } + }, + "values" : [ + { + "type" : "CIMUniqueValue", + "fieldValues" : [ + "2014" + ] + } + ], + "visible" : true + }, + { + "type" : "CIMUniqueValueClass", + "editable" : true, + "label" : "2017", + "patch" : "Default", + "symbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidStroke", + "enable" : true, + "capStyle" : "Round", + "joinStyle" : "Round", + "lineStyle3D" : "Strip", + "miterLimit" : 10, + "width" : 0.69999999999999996, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 110, + 110, + 110, + 100 + ] + } + }, + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 215, + 194, + 158, + 100 + ] + } + } + ] + } + }, + "values" : [ + { + "type" : "CIMUniqueValue", + "fieldValues" : [ + "2017" + ] + } + ], + "visible" : true + }, + { + "type" : "CIMUniqueValueClass", + "editable" : true, + "label" : "2018", + "patch" : "Default", + "symbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidStroke", + "enable" : true, + "capStyle" : "Round", + "joinStyle" : "Round", + "lineStyle3D" : "Strip", + "miterLimit" : 10, + "width" : 0.69999999999999996, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 110, + 110, + 110, + 100 + ] + } + }, + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMHSVColor", + "values" : [ + 4, + 57.969999999999999, + 81.180000000000007, + 100 + ] + } + } + ] + } + }, + "values" : [ + { + "type" : "CIMUniqueValue", + "fieldValues" : [ + "2018" + ] + } + ], + "visible" : true + }, + { + "type" : "CIMUniqueValueClass", + "editable" : true, + "label" : "2019", + "patch" : "Default", + "symbol" : { + "type" : "CIMSymbolReference", + "symbol" : { + "type" : "CIMPolygonSymbol", + "symbolLayers" : [ + { + "type" : "CIMSolidStroke", + "enable" : true, + "capStyle" : "Round", + "joinStyle" : "Round", + "lineStyle3D" : "Strip", + "miterLimit" : 10, + "width" : 0.69999999999999996, + "color" : { + "type" : "CIMRGBColor", + "values" : [ + 110, + 110, + 110, + 100 + ] + } + }, + { + "type" : "CIMSolidFill", + "enable" : true, + "color" : { + "type" : "CIMHSVColor", + "values" : [ + 143.00999999999999, + 62.149999999999999, + 83.920000000000002, + 100 + ] + } + } + ] + } + }, + "values" : [ + { + "type" : "CIMUniqueValue", + "fieldValues" : [ + "2019" + ] + } + ], + "visible" : true + } + ] + } + ], + "polygonSymbolColorTarget" : "Fill" + }, + "scaleSymbols" : true, + "snappable" : true + } + ], + "rGBColorProfile" : "sRGB IEC61966-2-1 noBPC", + "cMYKColorProfile" : "U.S. Web Coated (SWOP) v2" +} diff --git a/src/LyrxParser.spec.ts b/src/LyrxParser.spec.ts index 45bc0dd..8b72e95 100644 --- a/src/LyrxParser.spec.ts +++ b/src/LyrxParser.spec.ts @@ -154,4 +154,24 @@ describe('LyrxParser should parse afu_gwn_02.lyrx', () => { expect(textSymbolizer.kind).toEqual('Text'); expect(textSymbolizer.label).toEqual('{{bew_nr}} / {{bew_foerde}} l/s'); }); -}); \ No newline at end of file +}); + +describe('LyrxParser should parse kai_blattpk100_01.lyrx', () => { + let lyrx: any; + let lyrxParser: LyrxParser; + let geostylerStyle: ReadStyleResult; + + beforeAll(async () => { + lyrxParser = new LyrxParser(); + lyrx = JSON.parse( + fs.readFileSync('./data/lyrx/kai_blattpk100_01.lyrx', 'utf8') + ); + geostylerStyle = await lyrxParser.readStyle(lyrx); + }); + + it('should have parse whereClause expression', () => { + const rules = geostylerStyle.output!.rules; + expect(rules.length).toEqual(7); + expect(rules[6].filter).toEqual(['>', 'stand', '0']); + }); +}); diff --git a/src/customProperties.ts b/src/customProperties.ts deleted file mode 100644 index 2ad228c..0000000 --- a/src/customProperties.ts +++ /dev/null @@ -1,3 +0,0 @@ -export enum WellKnownText { - NewLine = '[newline]' -} diff --git a/src/expressions.ts b/src/expressions.ts index 57dbcd7..f22e8fe 100644 --- a/src/expressions.ts +++ b/src/expressions.ts @@ -1,5 +1,12 @@ -import {WellKnownText} from './customProperties'; import { LabelExpressionEngine } from './esri/types'; +import {ComparisonOperator, Filter} from 'geostyler-style'; + +export const getSimpleFilter = ( + operator: ComparisonOperator, + value1: string, value2: string, + toLowerCase=true): Filter => { + return [operator, stringToParameter(value1, toLowerCase), stringToParameter(value2, toLowerCase)]; +}; export const convertExpression = ( rawExpression: string, engine: LabelExpressionEngine, @@ -40,27 +47,15 @@ export const convertWhereClause = (clause: string, toLowerCase: boolean): any => } if (clause.includes('=')) { let tokens = clause.split('=').map(t => t.trim()); - expression.push( - 'PropertyIsEqualTo', - stringToParameter(tokens[0], toLowerCase), stringToParameter(tokens[1], toLowerCase) - ); - return expression; + return getSimpleFilter('==', tokens[0], tokens[1], toLowerCase); } if (clause.includes('<>')) { let tokens = clause.split('<>').map(t => t.trim()); - expression.push( - 'PropertyIsNotEqualTo', - stringToParameter(tokens[0], toLowerCase), stringToParameter(tokens[1], toLowerCase) - ); - return expression; + return getSimpleFilter('!=', tokens[0], tokens[1], toLowerCase); } if (clause.includes('>')) { let tokens = clause.split('>').map(t => t.trim()); - expression.push( - 'PropertyIsGreaterThan', - stringToParameter(tokens[0], toLowerCase), stringToParameter(tokens[1], toLowerCase) - ); - return expression; + return getSimpleFilter('>', tokens[0], tokens[1], toLowerCase); } if (clause.toLowerCase().includes(' in ')) { clause = clause.replace(' IN ', ' in '); @@ -106,7 +101,7 @@ export const processRotationExpression = ( const replaceSpecialLiteral = (literal: string): string => { if (literal === 'vbnewline') { - return WellKnownText.NewLine; + return '/n'; } return literal; }; @@ -119,18 +114,18 @@ const convertArcadeExpression = (expression: string): string => { return expression.replace('$feature.', ''); }; -const stringToParameter = (s: string, toLowerCase: boolean): string | string[] => { +const stringToParameter = (s: string, toLowerCase: boolean): string|null => { s = s.trim(); if ((s.startsWith('\'') && s.endsWith('\'')) || (s.startsWith('"') && s.endsWith('"'))) { // Removes quote around and returns. return s.substring(1).substring(0, s.length -2); } - // Returns if it's alphabetical only. - if (s.match(/^[A-Z]*$/i)) { - if (toLowerCase) { - s = s.toLowerCase(); - } - return ['PropertyName', s]; + // Lowercase if it's wanted and alphabetical only. + if (toLowerCase && s.match(/^[A-Z]*$/i)) { + s = s.toLowerCase(); + } + if (s === '') { + return null; } // Returns as is. return s; diff --git a/src/toGeostyler.ts b/src/toGeostyler.ts index e8f0522..f9ea341 100644 --- a/src/toGeostyler.ts +++ b/src/toGeostyler.ts @@ -1,5 +1,5 @@ import {Rule as FIXMERULE, Style} from 'geostyler-style'; -import {convertExpression, convertWhereClause, processRotationExpression,} from './expressions'; +import {convertExpression, convertWhereClause, getSimpleFilter, processRotationExpression,} from './expressions'; import {Options, Rule, Symbolizer} from './badTypes'; import {extractFillColor, extractFontWeight, ptToPxProp, WARNINGS,} from './toGeostylerUtils'; import {processSymbolReference} from './processSymbolReference'; @@ -313,12 +313,8 @@ const processUniqueValueGroup = ( return orConditions; }; - const equal = (name: string, val: any): any[] => { - return [ - '==', - toLowerCase ? name.toLowerCase() : name, - val === '' ? null : val, - ]; + const equal = (name: string, val: any): any => { + return getSimpleFilter('==', name, val, toLowerCase); }; const rules: Rule[] = [];