From 8186b6495de22f16fa27aec18be8341ffac63091 Mon Sep 17 00:00:00 2001 From: markpet49 Date: Thu, 11 Aug 2022 12:48:58 -0500 Subject: [PATCH 1/3] Fixes for default altitude mode and incorrect parameters to style.generate --- src/formats/kml/geom/KmlLineString.js | 42 +++++++++++++-------------- src/formats/kml/geom/KmlPolygon.js | 27 +++++++++-------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/formats/kml/geom/KmlLineString.js b/src/formats/kml/geom/KmlLineString.js index 4a2fddb39..9c46d2ede 100644 --- a/src/formats/kml/geom/KmlLineString.js +++ b/src/formats/kml/geom/KmlLineString.js @@ -38,16 +38,16 @@ define([ '../../../shapes/SurfacePolyline', '../../../util/WWUtil' ], function (Color, - KmlElements, - KmlGeometry, - KmlStyle, - Location, - NodeTransformers, - Path, - Position, - ShapeAttributes, - SurfacePolyline, - WWUtil) { + KmlElements, + KmlGeometry, + KmlStyle, + Location, + NodeTransformers, + Path, + Position, + ShapeAttributes, + SurfacePolyline, + WWUtil) { "use strict"; /** @@ -78,7 +78,7 @@ define([ */ kmlExtrude: { get: function () { - return this._factory.specific(this, {name: 'extrude', transformer: NodeTransformers.boolean}) || false; + return this._factory.specific(this, { name: 'extrude', transformer: NodeTransformers.boolean }) || false; } }, @@ -90,7 +90,7 @@ define([ */ kmlTessellate: { get: function () { - return this._factory.specific(this, {name: 'tessellate', transformer: NodeTransformers.boolean}) || false; + return this._factory.specific(this, { name: 'tessellate', transformer: NodeTransformers.boolean }) || false; } }, @@ -103,7 +103,7 @@ define([ */ kmlAltitudeMode: { get: function () { - return this._factory.specific(this, {name: 'altitudeMode', transformer: NodeTransformers.string}) || WorldWind.ABSOLUTE; + return this._factory.specific(this, { name: 'altitudeMode', transformer: NodeTransformers.string }) || WorldWind.CLAMP_TO_GROUND; } }, @@ -115,7 +115,7 @@ define([ */ kmlPositions: { get: function () { - return this._factory.specific(this, {name: 'coordinates', transformer: NodeTransformers.positions}); + return this._factory.specific(this, { name: 'coordinates', transformer: NodeTransformers.positions }); } }, @@ -153,26 +153,26 @@ define([ * @param styles.highlight {KmlStyle} Style applied when item is highlighted */ KmlLineString.prototype.createPath = function (styles, fileCache) { - if(this.kmlAltitudeMode == WorldWind.CLAMP_TO_GROUND) { + if (this.kmlAltitudeMode == WorldWind.CLAMP_TO_GROUND) { this._renderable = new SurfacePolyline(this.prepareLocations(), this.prepareAttributes(styles.normal, fileCache)); } else { this._renderable = new Path(this.prepareLocations(), this.prepareAttributes(styles.normal, fileCache)); } - if(styles.highlight) { + if (styles.highlight) { this._renderable.highlightAttributes = this.prepareAttributes(styles.highlight, fileCache); } this.moveValidProperties(); }; - KmlLineString.prototype.render = function(dc, kmlOptions) { + KmlLineString.prototype.render = function (dc, kmlOptions) { KmlGeometry.prototype.render.call(this, dc, kmlOptions); - if(kmlOptions.lastStyle && !this._renderable) { + if (kmlOptions.lastStyle && !this._renderable) { this.createPath(kmlOptions.lastStyle, kmlOptions.fileCache); dc.redrawRequested = true; } - if(this._renderable) { + if (this._renderable) { this._renderable.enabled = this.enabled; this._renderable.render(dc); } @@ -182,7 +182,7 @@ define([ * @inheritDoc */ KmlLineString.prototype.prepareAttributes = function (style, fileCache) { - var shapeOptions = style && style.generate(fileCache) || {}; + var shapeOptions = style && style.generate({}, fileCache) || {}; shapeOptions._applyLighting = true; shapeOptions._drawOutline = true; @@ -208,7 +208,7 @@ define([ */ KmlLineString.prototype.moveValidProperties = function () { this._renderable.extrude = this.kmlExtrude || false; - this._renderable.altitudeMode = this.kmlAltitudeMode || WorldWind.ABSOLUTE; + this._renderable.altitudeMode = this.kmlAltitudeMode || WorldWind.CLAMP_TO_GROUND; //noinspection JSUnusedGlobalSymbols this._renderable.tesselate = this.kmlTesselate || false; }; diff --git a/src/formats/kml/geom/KmlPolygon.js b/src/formats/kml/geom/KmlPolygon.js index 2f154af80..1ee908cd8 100644 --- a/src/formats/kml/geom/KmlPolygon.js +++ b/src/formats/kml/geom/KmlPolygon.js @@ -37,15 +37,15 @@ define([ '../../../shapes/ShapeAttributes', '../../../shapes/SurfacePolygon' ], function (Color, - KmlElements, - KmlGeometry, - KmlLinearRing, - KmlStyle, - Location, - NodeTransformers, - Polygon, - ShapeAttributes, - SurfacePolygon) { + KmlElements, + KmlGeometry, + KmlLinearRing, + KmlStyle, + Location, + NodeTransformers, + Polygon, + ShapeAttributes, + SurfacePolygon) { "use strict"; /** * Constructs an KmlPolygon. Application usually don't call this constructor. It is called by {@link KmlFile} as @@ -78,7 +78,7 @@ define([ */ kmlExtrude: { get: function () { - return this._factory.specific(this, {name: 'extrude', transformer: NodeTransformers.boolean}); + return this._factory.specific(this, { name: 'extrude', transformer: NodeTransformers.boolean }); } }, @@ -90,7 +90,7 @@ define([ */ kmlTessellate: { get: function () { - return this._factory.specific(this, {name: 'tessellate', transformer: NodeTransformers.boolean}); + return this._factory.specific(this, { name: 'tessellate', transformer: NodeTransformers.boolean }); } }, @@ -103,7 +103,7 @@ define([ */ kmlAltitudeMode: { get: function () { - return this._factory.specific(this, {name: 'altitudeMode', transformer: NodeTransformers.string}); + return this._factory.specific(this, { name: 'altitudeMode', transformer: NodeTransformers.string }); } }, @@ -157,7 +157,6 @@ define([ * @param styles.highlight {KmlStyle} Style to apply when item is highlighted. Currently ignored. */ KmlPolygon.prototype.createPolygon = function (styles, fileCache) { - console.log(this.kmlInnerBoundary && this.kmlInnerBoundary.kmlAltitudeMode === WorldWind.CLAMP_TO_GROUND); // TODO: KML boundaries are displaying graphic glitches when the camera is zoomed out if ( !this.isValidAltitudeMode(this.kmlAltitudeMode) || @@ -202,7 +201,7 @@ define([ * @inheritDoc */ KmlPolygon.prototype.prepareAttributes = function (style, fileCache) { - var shapeOptions = style && style.generate(fileCache) || {}; + var shapeOptions = style && style.generate({}, fileCache) || {}; shapeOptions._drawVerticals = this.kmlExtrude || false; shapeOptions._applyLighting = true; From 185aee65d6ce2a679455087ccf23dacf5064b141 Mon Sep 17 00:00:00 2001 From: markpet49 Date: Thu, 11 Aug 2022 14:42:01 -0500 Subject: [PATCH 2/3] Fix unit test. Bump minor version number. --- package.json | 4 ++-- test/formats/kml/geom/KmlLineString.test.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 8be0900e8..c43c1c537 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nasaworldwind/worldwind", - "version": "0.11.0", + "version": "0.11.1", "description": "Web WorldWind", "main": "build/dist/worldwind.min.js", "homepage": "https://worldwind.arc.nasa.gov", @@ -71,4 +71,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file diff --git a/test/formats/kml/geom/KmlLineString.test.js b/test/formats/kml/geom/KmlLineString.test.js index 58a6ad171..9c3ba02d4 100644 --- a/test/formats/kml/geom/KmlLineString.test.js +++ b/test/formats/kml/geom/KmlLineString.test.js @@ -71,7 +71,7 @@ define([ kmlPositions: [ new Position(37.824787, -122.364167, 0), new Position(37.824423, -122.363917, 0)], - kmlAltitudeMode: 'absolute', + kmlAltitudeMode: 'clampToGround', kmlExtrude: false, kmlTessellate: false })).toBeTruthy(); From 91904ea6f80d25fb84114219bf5413fc642cb547 Mon Sep 17 00:00:00 2001 From: markpet49 Date: Thu, 5 Oct 2023 14:58:44 -0500 Subject: [PATCH 3/3] Fixes some KML attribute handling bugs and improves handling of KML folder that have the same name --- .vscode/launch.json | 80 +++++++++---------- src/formats/kml/features/KmlPlacemark.js | 46 +++++------ src/formats/kml/styles/KmlLabelStyle.js | 13 ++- src/formats/kml/styles/KmlStyle.js | 50 ++++++------ .../kml/util/KmlElementsFactoryCached.js | 62 +++++++++----- src/formats/kml/util/KmlTreeKeyValueCache.js | 32 ++++---- 6 files changed, 151 insertions(+), 132 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 0f104dd4b..c52699c22 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,7 @@ { "name": "Annotations Example", "request": "launch", - "type": "pwa-chrome", + "type": "chrome", "url": "http://localhost:5500/examples/Annotations.html", "runtimeArgs": [ "--window-size=1200,768" @@ -17,7 +17,7 @@ { "name": "Basic Example", "request": "launch", - "type": "pwa-chrome", + "type": "chrome", "url": "http://localhost:5500/examples/BasicExample.html", "runtimeArgs": [ "--window-size=1200,768" @@ -27,7 +27,7 @@ { "name": "Blue Marble Time Series Example", "request": "launch", - "type": "pwa-chrome", + "type": "chrome", "url": "http://localhost:5500/examples/BlueMarbleTimeSeries.html", "runtimeArgs": [ "--window-size=1200,768" @@ -37,7 +37,7 @@ { "name": "Collada Example", "request": "launch", - "type": "pwa-chrome", + "type": "chrome", "url": "http://localhost:5500/examples/Collada.html", "runtimeArgs": [ "--window-size=1200,768" @@ -45,7 +45,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Configuration Example", "url": "http://localhost:5500/examples/Configuration.html", @@ -55,7 +55,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Custom Placemark Example", "url": "http://localhost:5500/examples/CustomPlacemark.html", @@ -65,7 +65,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Deep Picking Example", "url": "http://localhost:5500/examples/DeepPicking.html", @@ -75,7 +75,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Geographic Meshes Example", "url": "http://localhost:5500/examples/GeographicMeshes.html", @@ -85,7 +85,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Geographic Text Example", "url": "http://localhost:5500/examples/GeographicText.html", @@ -95,7 +95,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "GeoJSON Example", "url": "http://localhost:5500/examples/GeoJSON.html", @@ -105,7 +105,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "GeoJSON Exporter Example", "url": "http://localhost:5500/examples/GeoJSONExporter.html", @@ -115,7 +115,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "GeoTIFF Example", "url": "http://localhost:5500/examples/GeoTiff.html", @@ -125,7 +125,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Go to Location Example", "url": "http://localhost:5500/examples/GoToLocation.html", @@ -135,7 +135,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "HeatMap Example", "url": "http://localhost:5500/examples/HeatMap.html", @@ -145,17 +145,17 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "KML Example", "url": "http://localhost:5500/examples/KML.html", "runtimeArgs": [ - "--window-size=1200,768" + "--window-size=1200,1152" ], "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Measurements Example", "url": "http://localhost:5500/examples/Measurements.html", @@ -165,7 +165,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "MultiWindow Example", "url": "http://localhost:5500/examples/MultiWindow.html", @@ -175,7 +175,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Night Sky Animation Example", "url": "http://localhost:5500/examples/NightSkyAnimation.html", @@ -185,7 +185,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Parse URL Arguments Example", "url": "http://localhost:5500/examples/ParseUrlArguments.html?pos=38.8831,-77.0163,500", @@ -195,7 +195,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Paths Example", "url": "http://localhost:5500/examples/Paths.html", @@ -205,7 +205,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Pick All Shapes in Region Example", "url": "http://localhost:5500/examples/PickAllShapesInRegion.html", @@ -215,7 +215,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Placemarks And Picking Example", "url": "http://localhost:5500/examples/PlacemarksAndPicking.html", @@ -225,7 +225,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Polygons Example", "url": "http://localhost:5500/examples/Polygons.html", @@ -235,7 +235,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Pyramid Example", "url": "http://localhost:5500/examples/Pyramid.html", @@ -245,7 +245,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Refresh Imagery Example", "url": "http://localhost:5500/examples/RefreshImagery.html", @@ -255,7 +255,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Screen Image Example", "url": "http://localhost:5500/examples/ScreenImage.html", @@ -265,7 +265,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Screen Text Example", "url": "http://localhost:5500/examples/ScreenText.html", @@ -275,7 +275,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Shapefiles Example", "url": "http://localhost:5500/examples/Shapefiles.html", @@ -285,7 +285,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Surface Image Example", "url": "http://localhost:5500/examples/SurfaceImage.html", @@ -295,7 +295,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Surface Shapes Example", "url": "http://localhost:5500/examples/SurfaceShapes.html", @@ -305,7 +305,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Test Moving Surface Shapes Example", "url": "http://localhost:5500/examples/TestMovingSurfaceShapes.html", @@ -315,7 +315,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Triangle Meshes Example", "url": "http://localhost:5500/examples/TriangleMeshes.html", @@ -325,7 +325,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "WKT Example", "url": "http://localhost:5500/examples/WKT.html", @@ -335,7 +335,7 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "WKT Exporter Example", "url": "http://localhost:5500/examples/WKTExporter.html", @@ -345,17 +345,17 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "WMS Example", "url": "http://localhost:5500/examples/WMS.html", "runtimeArgs": [ - "--window-size=1200,768" + "--window-size=1400,1152" ], "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "WMTS Example", "url": "http://localhost:5500/examples/WMTS.html", @@ -365,10 +365,10 @@ "webRoot": "${workspaceFolder}", }, { - "type": "pwa-chrome", + "type": "chrome", "request": "launch", "name": "Collada App", - "url": "http://localhost:5500/build/app/Collada.html", + "url": "http://localhost:5500/apps/Collada.html", "runtimeArgs": [ "--window-size=1200,768" ], diff --git a/src/formats/kml/features/KmlPlacemark.js b/src/formats/kml/features/KmlPlacemark.js index f5b3e7b63..8fc8a9380 100644 --- a/src/formats/kml/features/KmlPlacemark.js +++ b/src/formats/kml/features/KmlPlacemark.js @@ -43,18 +43,18 @@ define([ '../../../util/Offset', '../../../util/WWUtil' ], function (KmlElements, - KmlFeature, - KmlGeometry, - KmlStyle, - KmlTimeSpan, - KmlTimeStamp, - PlacemarkAttributes, - Placemark, - Color, - ShapeAttributes, - TextAttributes, - Offset, - WWUtil) { + KmlFeature, + KmlGeometry, + KmlStyle, + KmlTimeSpan, + KmlTimeStamp, + PlacemarkAttributes, + Placemark, + Color, + ShapeAttributes, + TextAttributes, + Offset, + WWUtil) { "use strict"; /** * Constructs an KmlPlacemark. Applications usually don't call this constructor. It is called by {@link KmlFile} as @@ -90,12 +90,12 @@ define([ } }); - KmlPlacemark.prototype.render = function(dc, kmlOptions) { + KmlPlacemark.prototype.render = function (dc, kmlOptions) { KmlFeature.prototype.render.call(this, dc, kmlOptions); kmlOptions = WWUtil.clone(kmlOptions); - if(kmlOptions.lastStyle && !this._renderable) { + if (kmlOptions.lastStyle && !this._renderable) { // TODO: render placemarks without geometry. if (this.kmlGeometry) { this._renderable = new Placemark( @@ -103,15 +103,15 @@ define([ false, this.prepareAttributes(kmlOptions.lastStyle.normal, kmlOptions.fileCache) ); - if(kmlOptions.lastStyle.highlight) { + if (kmlOptions.lastStyle.highlight) { this._renderable.highlightAttributes = this.prepareAttributes(kmlOptions.lastStyle.highlight, kmlOptions.fileCache); } this.moveValidProperties(); dc.redrawRequested = true; } } - - if(this._renderable) { + + if (this._renderable) { if (this.kmlGeometry) { this.kmlGeometry.render(dc, kmlOptions); this._renderable.render(dc); @@ -125,19 +125,9 @@ define([ * @returns {PlacemarkAttributes} Attributes representing the current Placemark. */ KmlPlacemark.prototype.prepareAttributes = function (style, fileCache) { - var options = style && style.generate({}, fileCache) || {normal: {}, highlight:{}}; + var options = style && style.generate({}, fileCache) || { normal: {}, highlight: {} }; var placemarkAttributes = new PlacemarkAttributes(KmlStyle.placemarkAttributes(options)); - placemarkAttributes.imageOffset = new Offset( - WorldWind.OFFSET_FRACTION, 0.3, - WorldWind.OFFSET_FRACTION, 0.0); - placemarkAttributes.imageColor = Color.WHITE; - placemarkAttributes.labelAttributes = new TextAttributes(KmlStyle.textAttributes({ - _offset: new Offset( - WorldWind.OFFSET_FRACTION, 0.5, - WorldWind.OFFSET_FRACTION, 1.0), - _color: Color.YELLOW - })); placemarkAttributes.drawLeaderLine = true; placemarkAttributes.leaderLineAttributes = new ShapeAttributes(KmlStyle.shapeAttributes({ _outlineColor: Color.RED diff --git a/src/formats/kml/styles/KmlLabelStyle.js b/src/formats/kml/styles/KmlLabelStyle.js index c06f7c7a0..ed21ac9bf 100644 --- a/src/formats/kml/styles/KmlLabelStyle.js +++ b/src/formats/kml/styles/KmlLabelStyle.js @@ -26,10 +26,12 @@ * PDF found in code directory. */ define([ + '../../../util/Color', './KmlColorStyle', '../KmlElements', '../util/KmlNodeTransformers' ], function ( + Color, KmlColorStyle, KmlElements, NodeTransformers @@ -61,15 +63,18 @@ define([ * @type {Number} */ kmlScale: { - get: function() { - return this._factory.specific(this, {name: 'scale', transformer: NodeTransformers.number}); + get: function () { + return this._factory.specific(this, { name: 'scale', transformer: NodeTransformers.number }); } } }); - KmlLabelStyle.update = function () { - + KmlLabelStyle.update = function (style, options) { + var shapeOptions = options || {}; + style = style || {}; + shapeOptions._labelColor = style.kmlColor && Color.colorFromKmlHex(style.kmlColor) || Color.YELLOW; + return shapeOptions; }; /** diff --git a/src/formats/kml/styles/KmlStyle.js b/src/formats/kml/styles/KmlStyle.js index 756f5e284..ecb77144b 100644 --- a/src/formats/kml/styles/KmlStyle.js +++ b/src/formats/kml/styles/KmlStyle.js @@ -86,7 +86,7 @@ define([ * @type {KmlIconStyle|null} */ kmlIconStyle: { - get: function() { + get: function () { return this._factory.any(this, { name: KmlIconStyle.prototype.getTagNames() }); @@ -100,7 +100,7 @@ define([ * @type {KmlLabelStyle|null} */ kmlLabelStyle: { - get: function() { + get: function () { return this._factory.any(this, { name: KmlLabelStyle.prototype.getTagNames() }); @@ -114,7 +114,7 @@ define([ * @type {KmlLineStyle|null} */ kmlLineStyle: { - get: function() { + get: function () { return this._factory.any(this, { name: KmlLineStyle.prototype.getTagNames() }); @@ -128,7 +128,7 @@ define([ * @type {KmlPolyStyle|null} */ kmlPolyStyle: { - get: function() { + get: function () { return this._factory.any(this, { name: KmlPolyStyle.prototype.getTagNames() }); @@ -142,7 +142,7 @@ define([ * @type {KmlBalloonStyle|null} */ kmlBalloonStyle: { - get: function() { + get: function () { return this._factory.any(this, { name: KmlBalloonStyle.prototype.getTagNames() }); @@ -156,7 +156,7 @@ define([ * @type {KmlListStyle|null} */ kmlListStyle: { - get: function() { + get: function () { return this._factory.any(this, { name: KmlListStyle.prototype.getTagNames() }); @@ -164,26 +164,26 @@ define([ } }); - KmlStyle.prototype.generate = function(options, fileCache) { + KmlStyle.prototype.generate = function (options, fileCache) { options = options || {}; var style = this || {}; - if(style.kmlIconStyle) { + if (style.kmlIconStyle) { KmlIconStyle.update(style.kmlIconStyle, options, fileCache); } - if(style.kmlListStyle) { + if (style.kmlListStyle) { KmlListStyle.update(style.kmlListStyle, options); } - if(style.kmlBalloonStyle) { + if (style.kmlBalloonStyle) { KmlBalloonStyle.update(style.kmlBalloonStyle, options); } - if(style.kmlLabelStyle) { + if (style.kmlLabelStyle) { KmlLabelStyle.update(style.kmlLabelStyle, options); } - if(style.kmlPolyStyle) { + if (style.kmlPolyStyle) { KmlPolyStyle.update(style.kmlPolyStyle, options); } - if(style.kmlLineStyle) { + if (style.kmlLineStyle) { KmlLineStyle.update(style.kmlLineStyle, options); } @@ -193,10 +193,10 @@ define([ /** * @inheritDoc */ - KmlStyle.prototype.getStyle = function() { + KmlStyle.prototype.getStyle = function () { var self = this; - return new Promise(function(resolve){ - window.setTimeout(function(){ + return new Promise(function (resolve) { + window.setTimeout(function () { resolve(self); }, 0); }); @@ -216,16 +216,16 @@ define([ * @param attributes * @returns {Object} */ - KmlStyle.placemarkAttributes = function(attributes) { + KmlStyle.placemarkAttributes = function (attributes) { attributes = attributes || {}; // These are all documented with their property accessors below. attributes._imageColor = attributes._imageColor || new Color(1, 1, 1, 1); - attributes._imageOffset = attributes._imageOffset|| + attributes._imageOffset = attributes._imageOffset || new Offset(WorldWind.OFFSET_FRACTION, 0.5, WorldWind.OFFSET_FRACTION, 0.5); attributes._imageScale = attributes._imageScale || 1; attributes._imageSource = attributes._imageSource || null; attributes._depthTest = attributes._depthTest || true; - attributes._labelAttributes = attributes._labelAttributes || new TextAttributes(KmlStyle.textAttributes()); + attributes._labelAttributes = attributes._labelAttributes || new TextAttributes(KmlStyle.textAttributes(attributes)); attributes._drawLeaderLine = attributes._drawLeaderLine || false; attributes._leaderLineAttributes = attributes._leaderLineAttributes || new ShapeAttributes(KmlStyle.shapeAttributes()); @@ -237,14 +237,16 @@ define([ * @param attributes * @returns {Object} */ - KmlStyle.textAttributes = function(attributes) { + KmlStyle.textAttributes = function (attributes) { attributes = attributes || {}; - attributes._color = attributes._color || new Color(1, 1, 1, 1); + attributes._color = attributes._labelColor || new Color(1, 1, 1, 1); attributes._font = attributes._font || new Font(14); attributes._offset = attributes._offset || new Offset(WorldWind.OFFSET_FRACTION, 0.5, WorldWind.OFFSET_FRACTION, 0.0); attributes._scale = attributes._scale || 1; attributes._depthTest = attributes._depthTest || false; - attributes._outlineColor = attributes._outlineColor || Color.RED; + attributes._outlineWidth = 1; + attributes._outlineColor = Color.BLACK; + attributes._enableOutline = true; return attributes; }; @@ -254,7 +256,7 @@ define([ * @param attributes * @returns {*|{}} */ - KmlStyle.shapeAttributes = function(attributes) { + KmlStyle.shapeAttributes = function (attributes) { attributes = attributes || {}; // All these are documented with their property accessors below. attributes._drawInterior = attributes._drawInterior || true; @@ -277,7 +279,7 @@ define([ * It returns default KmlStyle, which doesn't contain any custom information. * @returns {KmlStyle} */ - KmlStyle.default = function() { + KmlStyle.default = function () { return new KmlStyle({ objectNode: document.createElement('Style') }); diff --git a/src/formats/kml/util/KmlElementsFactoryCached.js b/src/formats/kml/util/KmlElementsFactoryCached.js index 12269c67e..d4a562097 100644 --- a/src/formats/kml/util/KmlElementsFactoryCached.js +++ b/src/formats/kml/util/KmlElementsFactoryCached.js @@ -44,7 +44,7 @@ define([ * @constructor * @alias KmlElementsFactoryCached */ - var KmlElementsFactoryCached = function(options) { + var KmlElementsFactoryCached = function (options) { this.internalFactory = new KmlElementsFactory(options); this.cache = TreeKeyValueCache.applicationLevelCache(); }; @@ -55,13 +55,13 @@ define([ * @returns {KmlObject[]} All objects among the elements children * @see KmlElementsFactory.prototype.all */ - KmlElementsFactoryCached.prototype.all = function(element){ + KmlElementsFactoryCached.prototype.all = function (element) { var parentNode = element.node; var children = this.cache.level(this.cacheKey(element.node, "All")); if (children) { var results = []; - for(var key in children) { - if(children.hasOwnProperty(key)) { + for (var key in children) { + if (children.hasOwnProperty(key)) { results.push(children[key]); } } @@ -70,7 +70,7 @@ define([ var elements = this.internalFactory.all(element); - if(elements && elements.length) { + if (elements && elements.length) { var self = this; elements.forEach(function (pElement) { self.cache.add(self.cacheKey(parentNode, "All"), self.cacheKey(pElement.node), pElement); @@ -89,10 +89,10 @@ define([ * @returns Relevant value. * @see KmlElementsFactory.prototype.specific */ - KmlElementsFactoryCached.prototype.specific = function(element, options){ + KmlElementsFactoryCached.prototype.specific = function (element, options) { var parentNode = element.node; var name = options.name; - if(options.attribute) { + if (options.attribute) { name = options.attribute + name; } var child = this.cache.value(this.cacheKey(parentNode), name); @@ -101,9 +101,9 @@ define([ } var result = this.internalFactory.specific(element, options); - if(result && result.node) { + if (result && result.node) { this.cache.add(this.cacheKey(parentNode), this.cacheKey(result.node), result); - } else if(result) { + } else if (result) { this.cache.add(this.cacheKey(parentNode), name, result); } return result; @@ -117,15 +117,15 @@ define([ * @returns {KmlObject|null} KmlObject if there is one with the passed in name. * @see KmlElementsFactory.prototype.any */ - KmlElementsFactoryCached.prototype.any = function(element, options){ + KmlElementsFactoryCached.prototype.any = function (element, options) { var parentNode = element.node; var self = this; var child = null; var potentialChild; - options.name.forEach(function(name){ + options.name.forEach(function (name) { potentialChild = self.cache.value(self.cacheKey(parentNode), name); - if(potentialChild) { + if (potentialChild) { child = potentialChild; } }); @@ -135,12 +135,20 @@ define([ var result = this.internalFactory.any(element, options); - if(result) { + if (result) { this.cache.add(self.cacheKey(parentNode), self.cacheKey(result.node), result); } return result; }; + KmlElementsFactoryCached.prototype.getOrCreateId = function (node) { + var idAttribute = new Attribute(node, "id"); + if (!idAttribute.exists()) { + idAttribute.save(WWUtil.guid()); + } + return idAttribute; + }; + /** * It creates cache key based on the node. In case the node doesn't have any id, it also creates id for this * element. This id is used for storing the value in the cache. @@ -148,13 +156,27 @@ define([ * @param prefix {String|undefined} Prefix for the level * @returns {String} Value representing the key. */ - KmlElementsFactoryCached.prototype.cacheKey = function(node, prefix) { - var idAttribute = new Attribute(node, "id"); - if (!idAttribute.exists()) { - idAttribute.save(WWUtil.guid()); + KmlElementsFactoryCached.prototype.cacheKey = function (node, prefix) { + var idAttribute = this.getOrCreateId(node); + + // KML ids can be duplicated across folders, add any parent folder names to the key to make them unique. + let parent = node.parentNode; + let parentPrefix = ""; + while (parent) { + if (parent.nodeName === "Folder") { + if (parentPrefix !== "") { + parentPrefix += "#"; + } + parentPrefix += this.getOrCreateId(parent).value(); + } + parent = parent.parentNode; + } + let result = parentPrefix; + if (result !== "") { + result += "#"; } - var result = node.nodeName + "#" + idAttribute.value(); - if(prefix) { + result += node.nodeName + "#" + idAttribute.value(); + if (prefix) { result = prefix + result; } return result; @@ -165,7 +187,7 @@ define([ * It returns application wide instance of the factory. * @returns {KmlElementsFactoryCached} Singleton instance of factory for Application. */ - KmlElementsFactoryCached.applicationWide = function(){ + KmlElementsFactoryCached.applicationWide = function () { return applicationWide; }; diff --git a/src/formats/kml/util/KmlTreeKeyValueCache.js b/src/formats/kml/util/KmlTreeKeyValueCache.js index 31abd3922..2d1c75a8c 100644 --- a/src/formats/kml/util/KmlTreeKeyValueCache.js +++ b/src/formats/kml/util/KmlTreeKeyValueCache.js @@ -37,41 +37,41 @@ define([ * @constructor * @classdesc Represents internally used cache which stores data in a tree like structure. */ - var KmlTreeKeyValueCache = function() { + var KmlTreeKeyValueCache = function () { this.map = {}; }; - /** + /** * Adds new element to the cache. It accepts level, key and value in order * @param level {Object} Anything that can be used as a key in JavaScript object * @param key {Object} Anything that can be used as a key in JavaScript object * @param value {Object} The value to be stored in the cache on given level and value. Value must started with # */ - KmlTreeKeyValueCache.prototype.add = function(level, key, value){ - if(!this.map[level]) { + KmlTreeKeyValueCache.prototype.add = function (level, key, value) { + if (!this.map[level]) { this.map[level] = {}; } this.map[level][key] = value; }; - /** + /** * It returns value for key stored at certain level. If there is no such level, it returns null. If there is such leave then the key starting with # gets treated a bit differently. * @param level {Object} Anything that can be used as a key in JavaScript object * @param key {Object} Anything that can be used as a key in JavaScript object * @returns {Object|null} */ - KmlTreeKeyValueCache.prototype.value = function(level, key) { - if(!this.map[level]){ + KmlTreeKeyValueCache.prototype.value = function (level, key) { + if (!this.map[level]) { return null; } - if(key.indexOf("#") == -1) { + if (key.indexOf("#") == -1) { var currentLevel = this.level(level); - for(var keyFromLevel in currentLevel) { - if(!currentLevel.hasOwnProperty(keyFromLevel)){ + for (var keyFromLevel in currentLevel) { + if (!currentLevel.hasOwnProperty(keyFromLevel)) { continue; } - if(WWUtil.startsWith(keyFromLevel, key)){ + if (WWUtil.startsWith(keyFromLevel, key)) { return currentLevel[keyFromLevel]; } } @@ -79,26 +79,26 @@ define([ return this.map[level][key] || null; }; - /** + /** * It returns the whole level of the data. If there is none then undefined is returned. * @param level {Object} Anything that can be used as a key in JavaScript object * @returns {Object|null} */ - KmlTreeKeyValueCache.prototype.level = function(level) { + KmlTreeKeyValueCache.prototype.level = function (level) { return this.map[level]; }; - /** + /** * It removes the data from the map if such data exists. * @param level {Object} Anything that can be used as a key in JavaScript object * @param key {Object} Anything that can be used as a key in JavaScript object */ - KmlTreeKeyValueCache.prototype.remove = function(level, key) { + KmlTreeKeyValueCache.prototype.remove = function (level, key) { delete this.map[level][key]; }; var applicationLevelCache = new KmlTreeKeyValueCache(); - KmlTreeKeyValueCache.applicationLevelCache = function() { + KmlTreeKeyValueCache.applicationLevelCache = function () { return applicationLevelCache; };