|  | <!DOCTYPE html> | 
|  | <!-- | 
|  | 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. | 
|  | --> | 
|  |  | 
|  |  | 
|  | <html> | 
|  | <head> | 
|  | <meta charset="utf-8"> | 
|  | <meta name="viewport" content="width=device-width, initial-scale=1" /> | 
|  | <script src="https://unpkg.com/d3-array@3"></script> | 
|  | <script src="https://unpkg.com/d3-geo@3/dist/d3-geo.js"></script> | 
|  |  | 
|  | <script src="lib/simpleRequire.js"></script> | 
|  | <script src="lib/config.js"></script> | 
|  | <script src="lib/jquery.min.js"></script> | 
|  | <script src="lib/facePrint.js"></script> | 
|  | <script src="lib/testHelper.js"></script> | 
|  | <script src="lib/dat.gui.min.js"></script> | 
|  |  | 
|  | <!-- <script src="ut/lib/canteen.js"></script> --> | 
|  | <link rel="stylesheet" href="lib/reset.css" /> | 
|  | </head> | 
|  | <body> | 
|  | <style> | 
|  | body { | 
|  | margin: 0; | 
|  | } | 
|  | #main { | 
|  | position: absolute; | 
|  | left: 0; | 
|  | top: 0; | 
|  | bottom: 0; | 
|  | right: 0; | 
|  | } | 
|  | </style> | 
|  |  | 
|  |  | 
|  |  | 
|  | <div id="main"></div> | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | <script> | 
|  | require([ | 
|  | 'echarts', | 
|  | './data/map/json/world.json', | 
|  | './data/usa.json' | 
|  | ], function (echarts, worldJson, usaJson) { | 
|  |  | 
|  | var d3Projections =  [ | 
|  | ['default'], | 
|  | // Azimuthal Projections | 
|  | ['geoAzimuthalEqualArea'], | 
|  | ['geoAzimuthalEquidistant'], | 
|  | // 'geoGnomonic', | 
|  | ['geoOrthographic'], | 
|  | ['geoStereographic', d3.geoStereographic().rotate([-27, 0])], | 
|  |  | 
|  |  | 
|  | // Conic Projections | 
|  | ['geoConicConformal'], | 
|  | ['geoConicEqualArea'], | 
|  | ['geoConicEquidistant'], | 
|  |  | 
|  | // Cylindrical Projections | 
|  | ['geoEquirectangular'], | 
|  | ['geoMercator'], | 
|  | ['geoTransverseMercator', d3.geoStereographic()], | 
|  | // Equal-Earth | 
|  | ['geoEqualEarth'], | 
|  | ['geoNaturalEarth1'] | 
|  | ]; | 
|  |  | 
|  | function createLineString(start, end) { | 
|  | var dx = end[0] - start[0]; | 
|  | var dy = end[1] - start[1]; | 
|  | var segs = 100; | 
|  | var stepX = dx / segs; | 
|  | var stepY = dy / segs; | 
|  | var points = []; | 
|  | // TODO needs adaptive sampling on the -180 / 180 of azimuthal projections. | 
|  | for (let i = 0; i <= segs; i++) { | 
|  | points.push([ | 
|  | start[0] + i * stepX, | 
|  | start[1] + i * stepY | 
|  | ]); | 
|  | } | 
|  | return points; | 
|  | } | 
|  | function normalizePoint(pt) { | 
|  | if (pt[0] === -180) { | 
|  | pt[0] += 1e-2; | 
|  | } | 
|  | if (pt[0] === 180) { | 
|  | pt[0] -= 1e-2; | 
|  | } | 
|  | if (pt[1] === -80) { | 
|  | pt[1] += 1e-2; | 
|  | } | 
|  | if (pt[1] === 80) { | 
|  | pt[1] -= 1e-2; | 
|  | } | 
|  | return pt; | 
|  | } | 
|  | // Add graticule | 
|  | var graticuleLineStrings = []; | 
|  | for (var lat = -80; lat <= 80; lat += 10) { | 
|  | graticuleLineStrings.push( | 
|  | createLineString(normalizePoint([-180, lat]), normalizePoint([180, lat])) | 
|  | ); | 
|  | } | 
|  | for (var lng = -180; lng <= 180; lng += 10) { | 
|  | graticuleLineStrings.push( | 
|  | createLineString(normalizePoint([lng, -80]), normalizePoint([lng, 80])) | 
|  | ); | 
|  | } | 
|  |  | 
|  | worldJson.features.unshift({ | 
|  | geometry: { | 
|  | type: 'MultiLineString', | 
|  | coordinates: graticuleLineStrings | 
|  | }, | 
|  | properties: { | 
|  | name: 'graticule' | 
|  | } | 
|  | }); | 
|  |  | 
|  |  | 
|  | echarts.registerMap('world', worldJson); | 
|  |  | 
|  | function createWorldOption(name, projection) { | 
|  | return { | 
|  | series : [ | 
|  | { | 
|  | type: 'map', | 
|  | map: 'world', | 
|  | roam: false, | 
|  | itemStyle: { | 
|  | borderColor: '#fff', | 
|  | areaColor: '#000' | 
|  | }, | 
|  | projection, | 
|  | universalTransition: true, | 
|  | animationDurationUpdate: 2000, | 
|  | data:[ | 
|  | { | 
|  | name: 'graticule', | 
|  | itemStyle: { | 
|  | borderColor: '#ddd' | 
|  | }, | 
|  | emphasis: { | 
|  | itemStyle: { | 
|  | borderColor: '#ddd' | 
|  | } | 
|  | } | 
|  | } | 
|  | ] | 
|  | } | 
|  | ] | 
|  | }; | 
|  | } | 
|  |  | 
|  | var chart = echarts.init(document.querySelector('#main')); | 
|  |  | 
|  | var config = { | 
|  | projection: 'default' | 
|  | }; | 
|  |  | 
|  | function updateProjection(projectionName) { | 
|  | var projection = d3Projections.find(item => item[0] === projectionName)[1] | 
|  | || d3[projectionName] && d3[projectionName](); | 
|  | var projectionOpt = projection && { | 
|  | project: (pt) => { | 
|  | return projection(pt) | 
|  | }, | 
|  | unproject: (pt) => projection.invert(pt), | 
|  | stream: projection.stream | 
|  | }; | 
|  | var option = createWorldOption(projectionName, projectionOpt); | 
|  | if (projectionName === 'geoStereographic') { | 
|  | // TODO | 
|  | option.series[0].center = projection([0, 0]); | 
|  | option.series[0].zoom = 30; | 
|  | } | 
|  | else if (projectionName === 'geoTransverseMercator') { | 
|  | option.series[0].center = projection([0, 0]); | 
|  | option.series[0].zoom = 4000; | 
|  | } | 
|  | else { | 
|  | option.series[0].center = null, | 
|  | option.series[0].zoom = 1; | 
|  | } | 
|  | option.title = { | 
|  | text: projectionName, | 
|  | left: 'center', | 
|  | top: 0, | 
|  | textStyle: { | 
|  | fontSize: 14 | 
|  | } | 
|  | }; | 
|  | chart.setOption(option); | 
|  | } | 
|  |  | 
|  | updateProjection(config.projection); | 
|  |  | 
|  | var gui = new dat.GUI(); | 
|  | gui.add(config, 'projection',  d3Projections.map(item => item[0])).onChange(function () { | 
|  | updateProjection(config.projection); | 
|  | }) | 
|  | }); | 
|  | </script> | 
|  |  | 
|  |  | 
|  | </body> | 
|  | </html> |