├── export.js ├── .npmrc ├── .babelrc.json ├── .eslintignore ├── index.d.ts ├── index.js ├── .editorconfig ├── .prettierignore ├── .prettierrc ├── .gitignore ├── lib ├── helper.js ├── AzureMapModel.js ├── index.js ├── AzureMapView.js └── AzureMapCoordSys.js ├── LICENSE ├── .eslintrc.js ├── package.json ├── rollup.config.js ├── examples ├── heatmap.html ├── pie-echart@4.html ├── pie-echart@5.html ├── line.html ├── fly.html └── scatter.html └── README.md /export.js: -------------------------------------------------------------------------------- 1 | export * from './lib/index'; 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org 2 | -------------------------------------------------------------------------------- /.babelrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/env"] 3 | } 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | build/ 4 | .eslintrc.js 5 | examples/ 6 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare const name = 'echarts-extension-azure-map'; 2 | declare const version = '1.0.0'; 3 | 4 | export { name, version }; 5 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import * as echarts from 'echarts'; 2 | import { isNewEC } from './lib/helper'; 3 | import { install } from './lib/index'; 4 | 5 | isNewEC ? echarts.use(install) : install(echarts); 6 | 7 | export { name, version } from './lib/index'; 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.svg 2 | /dist 3 | .dockerignore 4 | node_modules 5 | .DS_Store 6 | .eslintignore 7 | *.png 8 | *.toml 9 | docker 10 | .editorconfig 11 | .gitignore 12 | .prettierignore 13 | LICENSE 14 | .eslintcache 15 | *.lock 16 | yarn-error.log 17 | .history 18 | CNAME 19 | package-lock.json 20 | /.vscode 21 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "proseWrap": "never", 6 | "endOfLine": "lf", 7 | "overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }], 8 | "plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"] 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist-ssr 12 | *.local 13 | 14 | # Editor directories and files 15 | .vscode/* 16 | !.vscode/extensions.json 17 | .idea 18 | .DS_Store 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /lib/helper.js: -------------------------------------------------------------------------------- 1 | import { version } from 'echarts'; 2 | 3 | export const ecVer = version.split('.'); 4 | 5 | export const isNewEC = ecVer[0] > 4; 6 | 7 | export const COMPONENT_TYPE = 'azuremap'; 8 | 9 | export const ACTION_TYPE = `${COMPONENT_TYPE}Roam`; 10 | 11 | export function v2Equal(a, b) { 12 | return a && b && a[0] === b[0] && a[1] === b[1]; 13 | } 14 | -------------------------------------------------------------------------------- /lib/AzureMapModel.js: -------------------------------------------------------------------------------- 1 | import { ComponentModel } from 'echarts'; 2 | import { COMPONENT_TYPE, isNewEC, v2Equal } from './helper'; 3 | 4 | const AzureMapModel = { 5 | type: COMPONENT_TYPE, 6 | setAzureMap: function (azuremap) { 7 | this.__azuremap = azuremap; 8 | }, 9 | getAzureMap: function () { 10 | // __azuremap is injected when creating AzureMapCoordSys 11 | return this.__azuremap; 12 | }, 13 | setEChartsLayer: function (layer) { 14 | this.__echartsLayer = layer; 15 | }, 16 | getEChartsLayer: function () { 17 | return this.__echartsLayer; 18 | }, 19 | setCenterAndZoom: function (center, zoom) { 20 | this.option.center = center; 21 | this.option.zoom = zoom; 22 | }, 23 | centerOrZoomChanged: function (center, zoom) { 24 | const option = this.option; 25 | return !(v2Equal(center, option.center) && zoom === option.zoom); 26 | }, 27 | defaultOption: { 28 | view: 'Auto', 29 | center: [104.1064453125, 37.54457732085582], 30 | zoom: 5, 31 | }, 32 | }; 33 | 34 | export default isNewEC ? ComponentModel.extend(AzureMapModel) : AzureMapModel; 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 andybuibui 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { browser: true, es6: true, node: true, es2020: true }, 3 | extends: 'eslint:recommended', 4 | parserOptions: { 5 | ecmaVersion: 2020, 6 | sourceType: 'module', 7 | }, 8 | rules: { 9 | strict: 0, 10 | 'no-param-reassign': 2, 11 | 'no-undef': 2, 12 | 'accessor-pairs': 2, 13 | 'comma-dangle': [2, 'always-multiline'], 14 | 'consistent-return': 2, 15 | 'dot-notation': 2, 16 | eqeqeq: 2, 17 | indent: [2, 2, { SwitchCase: 1 }], 18 | 'no-cond-assign': 2, 19 | 'no-constant-condition': 2, 20 | 'no-eval': 2, 21 | 'no-inner-declarations': [0], 22 | 'no-unneeded-ternary': 2, 23 | radix: 2, 24 | semi: [2, 'always'], 25 | 'comma-spacing': 2, 26 | 'comma-style': 2, 27 | 'eol-last': 2, 28 | 'linebreak-style': [2, 'unix'], 29 | 'new-parens': 2, 30 | 'no-lonely-if': 2, 31 | 'no-multiple-empty-lines': 2, 32 | 'no-nested-ternary': 2, 33 | 'no-spaced-func': 2, 34 | 'no-trailing-spaces': 2, 35 | 'operator-linebreak': 2, 36 | quotes: [2, 'single'], 37 | 'semi-spacing': 2, 38 | 'space-unary-ops': 2, 39 | 'arrow-parens': 2, 40 | 'arrow-spacing': 2, 41 | 'no-class-assign': 2, 42 | 'no-dupe-class-members': 2, 43 | 'no-var': 2, 44 | 'object-shorthand': 0, 45 | 'prefer-const': 2, 46 | 'prefer-spread': 2, 47 | 'prefer-template': 2, 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "echarts-extension-azure-map", 3 | "version": "2.0.0", 4 | "private": false, 5 | "description": "Azure Map for Apache ECharts (https://github.com/apache/echarts)", 6 | "keywords": [ 7 | "echarts", 8 | "azure-map", 9 | "echarts-extension", 10 | "map", 11 | "azuremap", 12 | "echarts-azure-map", 13 | "echarts4", 14 | "echarts5", 15 | "azure", 16 | "echarts-extension-azure-map" 17 | ], 18 | "homepage": "https://github.com/andybuibui/echarts-extension-azure-map#readme", 19 | "bugs": { 20 | "url": "https://github.com/andybuibui/echarts-extension-azure-map/issues" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/andybuibui/echarts-extension-azure-map" 25 | }, 26 | "license": "MIT", 27 | "author": "andybuibui", 28 | "main": "dist/echarts-extension-azure-map.min.js", 29 | "module": "dist/echarts-extension-azure-map.esm.js", 30 | "types": "index.d.ts", 31 | "files": [ 32 | "dist", 33 | "index.d.ts" 34 | ], 35 | "scripts": { 36 | "build": "rollup -c --bundleConfigAsCjs", 37 | "format": "prettier --cache --write ." 38 | }, 39 | "devDependencies": { 40 | "@babel/core": "^7.24.5", 41 | "@babel/preset-env": "^7.24.5", 42 | "@rollup/plugin-babel": "^6.0.4", 43 | "@rollup/plugin-commonjs": "^25.0.7", 44 | "@rollup/plugin-json": "^6.1.0", 45 | "@rollup/plugin-node-resolve": "^15.2.3", 46 | "@rollup/plugin-terser": "^0.4.4", 47 | "@types/echarts": "^4.9.22", 48 | "azure-maps-control": "^3.1.2", 49 | "chalk": "^4.1.2", 50 | "echarts": "^5.5.0", 51 | "eslint": "^8.57.0", 52 | "globals": "^15.8.0", 53 | "prettier": "^3.2.5", 54 | "prettier-plugin-organize-imports": "^3.2.2", 55 | "prettier-plugin-packagejson": "^2.4.3", 56 | "rollup": "^4.17.2" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | import AzureMapCoordSys from './AzureMapCoordSys'; 2 | import AzureMapModel from './AzureMapModel'; 3 | import AzureMapView from './AzureMapView'; 4 | import { ACTION_TYPE, COMPONENT_TYPE, ecVer, isNewEC } from './helper'; 5 | 6 | export { name, version } from '../package.json'; 7 | 8 | export function install(registers) { 9 | // add coordinate system support for pie series for ECharts < 5.4.0 10 | if (!isNewEC || (ecVer[0] === 5 && ecVer[1] < 4)) { 11 | registers.registerLayout(function (ecModel) { 12 | ecModel.eachSeriesByType('pie', function (seriesModel) { 13 | const coordSys = seriesModel.coordinateSystem; 14 | const data = seriesModel.getData(); 15 | const valueDim = data.mapDimension('value'); 16 | if (coordSys && coordSys.type === COMPONENT_TYPE) { 17 | const center = seriesModel.get('center'); 18 | const point = coordSys.dataToPoint(center); 19 | const cx = point[0]; 20 | const cy = point[1]; 21 | data.each(valueDim, function (_value, idx) { 22 | const layout = data.getItemLayout(idx); 23 | layout.cx = cx; 24 | layout.cy = cy; 25 | }); 26 | } 27 | }); 28 | }); 29 | } 30 | // Model 31 | isNewEC 32 | ? registers.registerComponentModel(AzureMapModel) 33 | : registers.extendComponentModel(AzureMapModel); 34 | // View 35 | isNewEC 36 | ? registers.registerComponentView(AzureMapView) 37 | : registers.extendComponentView(AzureMapView); 38 | // Coordinate System 39 | registers.registerCoordinateSystem(COMPONENT_TYPE, AzureMapCoordSys); 40 | // Action 41 | registers.registerAction( 42 | { 43 | type: ACTION_TYPE, 44 | event: ACTION_TYPE, 45 | update: 'updateLayout', 46 | }, 47 | function (_payload, ecModel) { 48 | ecModel.eachComponent(COMPONENT_TYPE, function (azMapModel) { 49 | const azmap = azMapModel.getAzureMap(); 50 | const center = azmap.getCamera().center; 51 | const zoom = azmap.getCamera().zoom; 52 | azMapModel.setCenterAndZoom(center, zoom); 53 | }); 54 | }, 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import { babel } from '@rollup/plugin-babel'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import json from '@rollup/plugin-json'; 4 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 5 | import terser from '@rollup/plugin-terser'; 6 | import chalk from 'chalk'; 7 | import fs from 'node:fs'; 8 | import path from 'node:path'; 9 | import { author, name, version } from './package.json'; 10 | 11 | const resolve = (p) => path.resolve(__dirname, p); 12 | function getLicense() { 13 | const license = fs.readFileSync(path.resolve(__dirname, './LICENSE'), { encoding: 'utf-8' }); 14 | const content = `${name} \n@version ${version}\n@author ${author}\n\n${license}`; 15 | return `/*!\n * ${content.replace(/\*\//g, '* /').split('\n').join('\n * ')}\n */`; 16 | } 17 | 18 | const outputConfigs = { 19 | esm: { 20 | file: resolve(`dist/${name}.esm.js`), 21 | format: 'es', 22 | }, 23 | cjs: { 24 | file: resolve(`dist/${name}.cjs.js`), 25 | format: 'cjs', 26 | }, 27 | umd: { 28 | file: resolve(`dist/${name}.js`), 29 | format: 'umd', 30 | }, 31 | mumd: { 32 | file: resolve(`dist/${name}.min.js`), 33 | format: 'umd', 34 | }, 35 | }; 36 | 37 | console.log(chalk.bgCyan(`🚩 Building ${version} ... `)); 38 | 39 | const packageConfigs = Object.keys(outputConfigs).reduce((prev, format) => { 40 | const output = { 41 | ...outputConfigs[format], 42 | externalLiveBindings: false, 43 | interop: 'esModule', 44 | globals: { 45 | echarts: 'echarts', 46 | atlas: 'atlas', 47 | }, 48 | validate: true, 49 | banner: getLicense(), 50 | }; 51 | const plugins = [ 52 | json(), 53 | nodeResolve(), 54 | commonjs(), 55 | babel({ 56 | babelHelpers: 'bundled', 57 | compact: false, 58 | }), 59 | ]; 60 | if (output.format === 'umd') { 61 | output.name = 'echarts.azuremap'; 62 | output.sourcemap = true; 63 | } 64 | if (format === 'mumd') { 65 | plugins.push( 66 | terser({ 67 | module: /^esm/.test(format), 68 | compress: { 69 | ecma: 2015, 70 | pure_getters: true, 71 | pure_funcs: ['console.log'], 72 | }, 73 | safari10: true, 74 | ie8: false, 75 | }), 76 | ); 77 | } 78 | 79 | return prev.concat({ 80 | input: resolve('index.js'), 81 | external: ['echarts', 'atlas'], 82 | plugins: [...plugins], 83 | output, 84 | treeshake: { 85 | moduleSideEffects: false, 86 | }, 87 | }); 88 | }, []); 89 | export default packageConfigs; 90 | -------------------------------------------------------------------------------- /lib/AzureMapView.js: -------------------------------------------------------------------------------- 1 | import { ComponentView } from 'echarts'; 2 | import { ACTION_TYPE, COMPONENT_TYPE, isNewEC } from './helper'; 3 | 4 | const AzureMapView = { 5 | type: COMPONENT_TYPE, 6 | render: function (azMapModel, ecModel, api) { 7 | let rendering = true; 8 | 9 | const azmap = azMapModel.getAzureMap(); 10 | const viewportRoot = api.getZr().painter.getViewportRoot(); 11 | const coordSys = azMapModel.coordinateSystem; 12 | const moveHandler = function () { 13 | if (rendering) { 14 | return; 15 | } 16 | const offsetEl = azmap.getMapContainer(); 17 | const mapOffset = [ 18 | -parseInt(offsetEl.style.left, 10) || 0, 19 | -parseInt(offsetEl.style.top, 10) || 0, 20 | ]; 21 | const viewportRootStyle = viewportRoot.style; 22 | const offsetLeft = `${mapOffset[0]}px`; 23 | const offsetTop = `${mapOffset[1]}px`; 24 | if (viewportRootStyle.left !== offsetLeft) { 25 | viewportRootStyle.left = offsetLeft; 26 | } 27 | if (viewportRootStyle.top !== offsetTop) { 28 | viewportRootStyle.top = offsetTop; 29 | } 30 | coordSys.setMapOffset(mapOffset); 31 | azMapModel.__mapOffset = mapOffset; 32 | api.dispatchAction({ 33 | type: ACTION_TYPE, 34 | animation: { 35 | duration: 0, 36 | }, 37 | }); 38 | }; 39 | 40 | function zoomEndHandler() { 41 | if (rendering) { 42 | return; 43 | } 44 | api.dispatchAction({ 45 | type: ACTION_TYPE, 46 | animation: { 47 | duration: 0, 48 | }, 49 | }); 50 | } 51 | 52 | azmap.events.remove('move', this._oldMoveHandler); 53 | azmap.events.remove('moveend', this._oldMoveHandler); 54 | azmap.events.remove('zoomend', this._oldZoomEndHandler); 55 | 56 | azmap.events.add('move', moveHandler); 57 | azmap.events.add('moveend', moveHandler); 58 | azmap.events.add('zoomend', zoomEndHandler); 59 | 60 | this._oldMoveHandler = moveHandler; 61 | this._oldZoomEndHandler = zoomEndHandler; 62 | rendering = false; 63 | }, 64 | dispose: function () { 65 | const component = this.__model; 66 | delete this._oldMoveHandler; 67 | delete this._oldZoomEndHandler; 68 | if (component) { 69 | component.getAzureMap().dispose(); 70 | component.setAzureMap(null); 71 | component.getEChartsLayer(null); 72 | if (component.coordinateSystem) { 73 | component.coordinateSystem.setAzureMap(null); 74 | component.coordinateSystem = null; 75 | } 76 | } 77 | }, 78 | }; 79 | 80 | export default isNewEC ? ComponentView.extend(AzureMapView) : AzureMapView; 81 | -------------------------------------------------------------------------------- /examples/heatmap.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 ||
215 | andybuibui 222 | |
223 |