| <!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> |