| /* | 
 | * Licensed to the Apache Software Foundation (ASF) under one | 
 | * or more contributor license agreements.  See the NOTICE file | 
 | * distributed with this work for additional information | 
 | * regarding copyright ownership.  The ASF licenses this file | 
 | * to you under the Apache License, Version 2.0 (the | 
 | * "License"); you may not use this file except in compliance | 
 | * with the License.  You may obtain a copy of the License at | 
 | * | 
 | *   http://www.apache.org/licenses/LICENSE-2.0 | 
 | * | 
 | * Unless required by applicable law or agreed to in writing, | 
 | * software distributed under the License is distributed on an | 
 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
 | * KIND, either express or implied.  See the License for the | 
 | * specific language governing permissions and limitations | 
 | * under the License. | 
 | */ | 
 |  | 
 | /** | 
 |  * Parse and decode geo json | 
 |  */ | 
 |  | 
 | import * as zrUtil from 'zrender/src/core/util'; | 
 | import { GeoJSONLineStringGeometry, GeoJSONPolygonGeometry, GeoJSONRegion } from './Region'; | 
 | import { GeoJSONCompressed, GeoJSON } from './geoTypes'; | 
 |  | 
 |  | 
 | function decode(json: GeoJSONCompressed | GeoJSON): GeoJSON { | 
 |     if (!(json as GeoJSONCompressed).UTF8Encoding) { | 
 |         return json as GeoJSON; | 
 |     } | 
 |     const jsonCompressed = json as GeoJSONCompressed; | 
 |     let encodeScale = jsonCompressed.UTF8Scale; | 
 |     if (encodeScale == null) { | 
 |         encodeScale = 1024; | 
 |     } | 
 |  | 
 |     const features = jsonCompressed.features; | 
 |     zrUtil.each(features, feature => { | 
 |         const geometry = feature.geometry; | 
 |         const encodeOffsets = geometry.encodeOffsets; | 
 |         const coordinates = geometry.coordinates; | 
 |  | 
 |         // Geometry may be appeded manually in the script after json loaded. | 
 |         // In this case this geometry is usually not encoded. | 
 |         if (!encodeOffsets) { | 
 |             return; | 
 |         } | 
 |  | 
 |         switch (geometry.type) { | 
 |             case 'LineString': | 
 |                 (geometry as any).coordinates = | 
 |                     decodeRing(coordinates as string, encodeOffsets as number[], encodeScale); | 
 |                 break; | 
 |             case 'Polygon': | 
 |                 decodeRings(coordinates as string[], encodeOffsets as number[][], encodeScale); | 
 |                 break; | 
 |             case 'MultiLineString': | 
 |                 decodeRings(coordinates as string[], encodeOffsets as number[][], encodeScale); | 
 |                 break; | 
 |             case 'MultiPolygon': | 
 |                 zrUtil.each( | 
 |                     coordinates as string[][], | 
 |                     (rings, idx) => decodeRings(rings, (encodeOffsets as number[][][])[idx], encodeScale) | 
 |                 ); | 
 |         } | 
 |     }); | 
 |     // Has been decoded | 
 |     jsonCompressed.UTF8Encoding = false; | 
 |  | 
 |     return jsonCompressed as unknown as GeoJSON; | 
 | } | 
 |  | 
 | function decodeRings( | 
 |     rings: string[], | 
 |     encodeOffsets: number[][], | 
 |     encodeScale: number | 
 | ) { | 
 |     for (let c = 0; c < rings.length; c++) { | 
 |         rings[c] = decodeRing( | 
 |             rings[c], | 
 |             encodeOffsets[c], | 
 |             encodeScale | 
 |         ) as any; | 
 |     } | 
 | } | 
 |  | 
 | function decodeRing( | 
 |     coordinate: string, | 
 |     encodeOffsets: number[], | 
 |     encodeScale: number | 
 | ): number[][] { | 
 |     const result = []; | 
 |     let prevX = encodeOffsets[0]; | 
 |     let prevY = encodeOffsets[1]; | 
 |  | 
 |     for (let i = 0; i < coordinate.length; i += 2) { | 
 |         let x = coordinate.charCodeAt(i) - 64; | 
 |         let y = coordinate.charCodeAt(i + 1) - 64; | 
 |         // ZigZag decoding | 
 |         x = (x >> 1) ^ (-(x & 1)); | 
 |         y = (y >> 1) ^ (-(y & 1)); | 
 |         // Delta deocding | 
 |         x += prevX; | 
 |         y += prevY; | 
 |  | 
 |         prevX = x; | 
 |         prevY = y; | 
 |         // Dequantize | 
 |         result.push([x / encodeScale, y / encodeScale]); | 
 |     } | 
 |  | 
 |     return result; | 
 | } | 
 |  | 
 | export default function parseGeoJSON(geoJson: GeoJSON | GeoJSONCompressed, nameProperty: string): GeoJSONRegion[] { | 
 |  | 
 |     geoJson = decode(geoJson); | 
 |  | 
 |     return zrUtil.map(zrUtil.filter(geoJson.features, function (featureObj) { | 
 |         // Output of mapshaper may have geometry null | 
 |         return featureObj.geometry | 
 |             && featureObj.properties | 
 |             && featureObj.geometry.coordinates.length > 0; | 
 |     }), function (featureObj) { | 
 |         const properties = featureObj.properties; | 
 |         const geo = featureObj.geometry; | 
 |  | 
 |         const geometries = [] as GeoJSONRegion['geometries']; | 
 |         switch (geo.type) { | 
 |             case 'Polygon': | 
 |                 const coordinates = geo.coordinates; | 
 |                 // According to the GeoJSON specification. | 
 |                 // First must be exterior, and the rest are all interior(holes). | 
 |                 geometries.push(new GeoJSONPolygonGeometry(coordinates[0], coordinates.slice(1))); | 
 |                 break; | 
 |             case 'MultiPolygon': | 
 |                 zrUtil.each(geo.coordinates, function (item) { | 
 |                     if (item[0]) { | 
 |                         geometries.push(new GeoJSONPolygonGeometry(item[0], item.slice(1))); | 
 |                     } | 
 |                 }); | 
 |                 break; | 
 |             case 'LineString': | 
 |                 geometries.push(new GeoJSONLineStringGeometry([geo.coordinates])); | 
 |                 break; | 
 |             case 'MultiLineString': | 
 |                 geometries.push(new GeoJSONLineStringGeometry(geo.coordinates)); | 
 |  | 
 |         } | 
 |  | 
 |         const region = new GeoJSONRegion( | 
 |             properties[nameProperty || 'name'], | 
 |             geometries, | 
 |             properties.cp | 
 |         ); | 
 |         region.properties = properties; | 
 |         return region; | 
 |     }); | 
 | } |