|  | /* | 
|  | * 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; | 
|  | }); | 
|  | } |