├── .babelrc ├── .eslintrc ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── LICENSE ├── README.md ├── package.json ├── src ├── components │ ├── AutoComplete │ │ └── index.js │ ├── Base │ │ ├── Bounds.js │ │ ├── Common.js │ │ ├── Events.js │ │ ├── Path.js │ │ ├── Point.js │ │ ├── Size.js │ │ └── index.js │ ├── ContextMenu │ │ ├── Item.js │ │ └── index.js │ ├── Control │ │ ├── BaseControl.js │ │ ├── CityList.js │ │ ├── CopyrightControl.js │ │ ├── Custom.js │ │ ├── Geolocation.js │ │ ├── MapType.js │ │ ├── Navigation.js │ │ ├── OverviewMap.js │ │ ├── Panorama.js │ │ └── Scale.js │ ├── Copyright │ │ └── index.js │ ├── Layer │ │ ├── TileLayer.js │ │ └── TrafficLayer.js │ ├── Library │ │ ├── CurveLine │ │ │ └── index.js │ │ ├── DistanceTool │ │ │ ├── Icon.js │ │ │ └── index.js │ │ └── HeatMap │ │ │ └── index.js │ ├── Map │ │ ├── PlaceHolder.js │ │ └── index.js │ └── Overlay │ │ ├── BaseOverlay.js │ │ ├── Boundary.js │ │ ├── Circle.js │ │ ├── Custom.js │ │ ├── Ground.js │ │ ├── HTMLComponent.js │ │ ├── HTMLStringComponent.js │ │ ├── InfoWindow │ │ ├── Content.js │ │ ├── MaxContent.js │ │ ├── Title.js │ │ └── index.js │ │ ├── Label │ │ ├── Content.js │ │ └── index.js │ │ ├── Marker │ │ ├── Icon.js │ │ └── index.js │ │ ├── PointCollection.js │ │ ├── Polygon.js │ │ ├── Polyline │ │ ├── IconSequence.js │ │ └── index.js │ │ └── Symbol.js ├── core │ ├── AutoComplete │ │ └── index.js │ ├── Control │ │ ├── BaseControl.js │ │ ├── CityList.js │ │ ├── Copyright.js │ │ ├── Custom.js │ │ ├── Geolocation.js │ │ ├── MapType.js │ │ ├── Navigation.js │ │ ├── OverviewMap.js │ │ ├── Panorama.js │ │ └── Scale.js │ ├── Layer │ │ ├── TileLayer.js │ │ └── TrafficLayer.js │ ├── Library │ │ ├── CurveLine.js │ │ ├── DistanceTool.js │ │ └── HeatMap.js │ ├── Map │ │ └── index.js │ ├── Overlay │ │ ├── BaseOverlay.js │ │ ├── Circle.js │ │ ├── Custom.js │ │ ├── GroundOverlay.js │ │ ├── Icon.js │ │ ├── IconSequence.js │ │ ├── InfoWindow.js │ │ ├── Label.js │ │ ├── Marker.js │ │ ├── PointCollection.js │ │ ├── Polygon.js │ │ ├── Polyline.js │ │ └── Symbol.js │ ├── constants │ │ └── index.js │ ├── index.js │ ├── options │ │ ├── autoComplete.js │ │ ├── circle.js │ │ ├── ground.js │ │ ├── infoWindow.js │ │ ├── label.js │ │ ├── map.js │ │ ├── marker.js │ │ ├── polygon.js │ │ ├── polyline.js │ │ └── symbol.js │ └── utils │ │ ├── index.js │ │ └── map.js └── index.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | "stage-0" 6 | ], 7 | "plugins": [ 8 | "transform-runtime", 9 | "transform-decorators-legacy", 10 | "babel-plugin-transform-regenerator" 11 | ] 12 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "parser": "babel-eslint", 4 | "env": { 5 | "browser": true 6 | }, 7 | "rules": { 8 | "import/no-extraneous-dependencies": "off", 9 | "no-param-reassign": "off", 10 | "react/prop-types": "off", 11 | "no-underscore-dangle": "warn", 12 | "linebreak-style": "off", 13 | "global-require": "warn", 14 | "react/jsx-filename-extension": "off", 15 | "react/require-default-props": "off", 16 | "react/forbid-prop-types": "off", 17 | "react/destructuring-assignment": "off", 18 | "react/no-array-index-key": "off" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Do you want to request a *feature* or report a *bug*?** 2 | 3 | **What is the current behavior?** 4 | 5 | **If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run. Paste the link to your CodeSandbox (https://codesandbox.io/s/jnnxrwq5y3) example below:** 6 | 7 | **What is the expected behavior?** 8 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | First of all, thank you for your contribution! :-) 2 | 3 | Please makes sure that these checkboxes are checked before submitting your PR, thank you! 4 | 5 | * [ ] Make sure that you propose PR to right branch: bugfix for `master`, feature for latest active branch `vx.x.x`. 6 | * [ ] Rebase before creating a PR to keep commit history clear. 7 | * [ ] Add some descriptions and refer relative issues for you PR. 8 | 9 | Extra checklist: 10 | if** *isNewFeature* **:** 11 | 12 | * [ ] Update API docs for the component. 13 | * [ ] Update/Add demo to demonstrate new feature. 14 | * [ ] Update TypeScript definition for the component. 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | .DS_Store 5 | .env.local 6 | .env.development.local 7 | .env.test.local 8 | .env.production.local 9 | 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | /docs/.vuepress/dist 14 | .vscode 15 | 16 | lib 17 | dist 18 | package-lock.json 19 | /.idea 20 | /lib/ 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 JserClub 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React BaiduMap 2 | 3 |

4 | 5 |

6 |

基于 React 的百度地图组件

7 | 8 | [![npm](https://img.shields.io/npm/v/rc-bmap.svg)]() 9 | [![license](https://img.shields.io/github/license/jserwang/rc-bmap.svg)]() 10 | 11 | ## 文档 12 | 13 | 1.x文档地址: 14 | 15 | [http://jser.wang/bmap/](http://jser.wang/bmap/) 16 | 17 | 0.2.4文档地址: 18 | 19 | [https://bmap.jser-club.com](https://bmap.jser-club.com) 20 | 21 | ## 安装 22 | 23 | ``` 24 | npm install rc-bmap 25 | ``` 26 | 27 | 当前通过npm 或 yarn 直接安装为最新版,若想指定安装0.2.4版本时可通过: 28 | ``` 29 | npm install rc-bmap@0.2.4 30 | ``` 31 | 32 | ## 协议 33 | 34 | [MIT 许可证](https://opensource.org/licenses/MIT) 35 | 36 | ## 本地开发 37 | 38 | 与`demo`结合的最佳实践: 39 | 40 | 1. 将`demo`工程`clone`至本地。 41 | ``` bash 42 | git clone https://github.com/jser-club/rc-bmap-demo.git 43 | ``` 44 | 2. 安装`demo`工程所需依赖。 45 | ``` bash 46 | cd 你刚clone的工程目录 47 | yarn install 48 | ``` 49 | 3. 进入`rc-bmap`工程的目录,执行 50 | ``` bash 51 | yarn link 52 | ``` 53 | 4. 进入`rc-bmap-dmeo`工程目录执行 54 | ``` bash 55 | yarn link rc-bmap 56 | ``` 57 | 5. 修改完`rc-bmap`的源码后,在`rc-bmap`工程执行 58 | ``` bash 59 | yarn run build 60 | ``` 61 | 如果在windows系统下 62 | ```bash 63 | yarn run build_win 64 | ``` 65 | 6. 在`demo`重新点击按钮运行,即可看到最新修改后的效果 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rc-bmap", 3 | "version": "1.0.5", 4 | "main": "lib/index.js", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/JserWang/rc-bmap.git" 8 | }, 9 | "keywords": [ 10 | "react", 11 | "baidu-map", 12 | "bmap", 13 | "rc-bmap", 14 | "baidu", 15 | "map" 16 | ], 17 | "files": [ 18 | "src", 19 | "lib", 20 | "types" 21 | ], 22 | "license": "MIT", 23 | "homepage": "http://jser.wang/bmap", 24 | "dependencies": { 25 | "babel-plugin-transform-regenerator": "^6.26.0", 26 | "babel-plugin-transform-runtime": "^6.23.0", 27 | "lodash.isequal": "^4.5.0", 28 | "prop-types": "^15.6.2" 29 | }, 30 | "scripts": { 31 | "build": "rm -rf lib && babel src -d lib", 32 | "build_win": "rimraf lib && babel src -d lib", 33 | "prepublish": "npm run build", 34 | "pub": "npm run prepublish && npm publish" 35 | }, 36 | "devDependencies": { 37 | "@types/react": "^16.4.9", 38 | "babel-cli": "^6.26.0", 39 | "babel-core": "^6.26.3", 40 | "babel-eslint": "^8.2.6", 41 | "babel-loader": "^7.1.5", 42 | "babel-plugin-transform-decorators-legacy": "^1.3.5", 43 | "babel-preset-es2015": "^6.24.1", 44 | "babel-preset-react": "^6.24.1", 45 | "babel-preset-stage-0": "^6.24.1", 46 | "eslint": "^5.3.0", 47 | "eslint-config-airbnb": "^17.1.0", 48 | "eslint-plugin-import": "^2.14.0", 49 | "eslint-plugin-jsx-a11y": "^6.1.1", 50 | "eslint-plugin-react": "^7.11.0", 51 | "react": "^16.4.1", 52 | "react-dom": "^16.4.1" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/AutoComplete/index.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Util, AutoComplete as BAutoComplete } from '../../core'; 4 | 5 | class AutoComplete extends PureComponent { 6 | instance = null; 7 | 8 | config = {} 9 | 10 | static childContextTypes = { 11 | centralizedUpdates: PropTypes.func, 12 | } 13 | 14 | getChildContext() { 15 | return { 16 | centralizedUpdates: this.centralizedUpdates, 17 | }; 18 | } 19 | 20 | componentDidMount() { 21 | const { children, ...resetProps } = this.props; 22 | this.config = { ...this.config, ...resetProps }; 23 | this.control = new BAutoComplete(this.config); 24 | this.instance = this.control.instance; 25 | } 26 | 27 | componentDidUpdate() { 28 | const { children, ...resetProps } = this.props; 29 | this.config = { ...this.config, ...resetProps }; 30 | this.control.repaint(this.config); 31 | } 32 | 33 | componentWillUnmount() { 34 | this.control.destroy(); 35 | } 36 | 37 | centralizedUpdates = ({ name, data }) => { 38 | const configName = Util.firstLowerCase(name); 39 | this.config[configName] = data; 40 | } 41 | 42 | render() { 43 | const { children } = this.props; 44 | return children || null; 45 | } 46 | } 47 | 48 | export default AutoComplete; 49 | -------------------------------------------------------------------------------- /src/components/Base/Bounds.js: -------------------------------------------------------------------------------- 1 | import Common from './Common'; 2 | 3 | export default class Bounds extends Common { 4 | static displayName = 'Bounds' 5 | 6 | getData = () => ({ 7 | name: this.props.name || 'bounds', 8 | data: { 9 | sw: this.config.sw || this.props.sw, 10 | ne: this.config.ne || this.props.ne, 11 | }, 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Base/Common.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Util } from '../../core'; 4 | 5 | class Common extends PureComponent { 6 | static contextTypes = { 7 | centralizedUpdates: PropTypes.func, 8 | } 9 | 10 | config = {} 11 | 12 | static displayName = 'CommonBaseComponent'; 13 | 14 | static childContextTypes = { 15 | centralizedUpdates: PropTypes.func, 16 | } 17 | 18 | getChildContext() { 19 | return { 20 | centralizedUpdates: this.centralizedUpdates, 21 | }; 22 | } 23 | 24 | componentDidMount() { 25 | const { context, getData } = this; 26 | const data = (getData && getData()) || {}; 27 | context.centralizedUpdates(data); 28 | } 29 | 30 | componentDidUpdate() { 31 | const { context, getData } = this; 32 | const data = (getData && getData()) || {}; 33 | context.centralizedUpdates(data); 34 | } 35 | 36 | componentWillUnmount() { 37 | const { context, getData } = this; 38 | const data = (getData && getData()) || {}; 39 | data.data = null; 40 | context.centralizedUpdates(data); 41 | } 42 | 43 | centralizedUpdates = ({ name, data }) => { 44 | const configName = Util.firstLowerCase(name); 45 | this.config[configName] = data; 46 | } 47 | 48 | render() { 49 | const { children } = this.props; 50 | if (children) { 51 | return
{children}
; 52 | } 53 | return null; 54 | } 55 | } 56 | 57 | export default Common; 58 | -------------------------------------------------------------------------------- /src/components/Base/Events.js: -------------------------------------------------------------------------------- 1 | import Common from './Common'; 2 | 3 | export default class Events extends Common { 4 | static displayName = 'Events' 5 | 6 | getData = () => ({ 7 | name: 'events', 8 | data: this.props, 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /src/components/Base/Path.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | export default class Path extends PureComponent { 5 | static displayName = 'Path' 6 | 7 | static contextTypes = { 8 | centralizedUpdates: PropTypes.func, 9 | } 10 | 11 | items = [] 12 | 13 | static childContextTypes = { 14 | addPoint: PropTypes.func, 15 | updatePoint: PropTypes.func, 16 | removePoint: PropTypes.func, 17 | } 18 | 19 | getChildContext() { 20 | return { 21 | addPoint: this.addPoint, 22 | updatePoint: this.updatePoint, 23 | removePoint: this.removePoint, 24 | }; 25 | } 26 | 27 | componentDidMount() { 28 | const { context } = this; 29 | context.centralizedUpdates({ 30 | name: this.props.name || 'path', 31 | data: [...this.items], 32 | }); 33 | } 34 | 35 | componentDidUpdate() { 36 | const { context } = this; 37 | // filter undefined item 38 | context.centralizedUpdates({ 39 | name: this.props.name || 'path', 40 | data: [...this.items.filter(i => i)], 41 | }); 42 | } 43 | 44 | componentWillUnmount() { 45 | const { context } = this; 46 | context.centralizedUpdates({ 47 | name: this.props.name || 'path', 48 | data: null, 49 | }); 50 | } 51 | 52 | addPoint = (index, item) => { 53 | if (this.items[index]) { 54 | this.items.splice(index, 0, item); 55 | } else { 56 | this.items[index] = item; 57 | } 58 | } 59 | 60 | updatePoint = (index, item) => { 61 | this.items[index] = item; 62 | } 63 | 64 | removePoint = (index) => { 65 | // Fix sync call removePoint cause index confusion 66 | // https://github.com/jser-club/rc-bmap/issues/92 67 | this.items.splice(index, 1, undefined); 68 | } 69 | 70 | renderChildren = () => React.Children.map(this.props.children, (child, index) => { 71 | if (child) { 72 | return React.cloneElement(child, { 73 | index, 74 | }); 75 | } 76 | return null; 77 | }) 78 | 79 | render() { 80 | return ( 81 |
82 | {this.renderChildren()} 83 |
84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/components/Base/Point.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import Common from './Common'; 3 | 4 | export default class Point extends Common { 5 | static displayName = 'Point' 6 | 7 | static contextTypes = { 8 | centralizedUpdates: PropTypes.func, 9 | addPoint: PropTypes.func, 10 | updatePoint: PropTypes.func, 11 | removePoint: PropTypes.func, 12 | } 13 | 14 | componentDidMount() { 15 | const { context } = this; 16 | const { 17 | index, name = 'point', ...resetProps 18 | } = this.props; 19 | // 若存在addPoint,则证明在Path下,不进行统一数据变更逻辑 20 | if (context.addPoint) { 21 | context.addPoint(index, { ...resetProps }); 22 | } else { 23 | this.centralizedUpdates(name, { ...resetProps }); 24 | } 25 | } 26 | 27 | componentDidUpdate() { 28 | const { context } = this; 29 | const { 30 | index, name = 'point', ...resetProps 31 | } = this.props; 32 | if (context.updatePoint) { 33 | context.updatePoint(index, { ...resetProps }); 34 | } else { 35 | this.centralizedUpdates(name, { ...resetProps }); 36 | } 37 | } 38 | 39 | componentWillUnmount() { 40 | const { context } = this; 41 | const { index } = this.props; 42 | if (context.removePoint) { 43 | context.removePoint(index); 44 | } 45 | } 46 | 47 | centralizedUpdates = (name, item) => { 48 | this.context.centralizedUpdates({ 49 | name, 50 | data: item, 51 | }); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/components/Base/Size.js: -------------------------------------------------------------------------------- 1 | import Common from './Common'; 2 | 3 | export default class Size extends Common { 4 | static displayName = 'Size' 5 | 6 | getData = () => { 7 | const { width, height, name = 'size' } = this.props; 8 | 9 | const data = { width, height }; 10 | return { name, data }; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/components/Base/index.js: -------------------------------------------------------------------------------- 1 | import Point from './Point'; 2 | import Size from './Size'; 3 | import Events from './Events'; 4 | import Bounds from './Bounds'; 5 | import Path from './Path'; 6 | 7 | export default class Base { 8 | static Point = Point; 9 | 10 | static Size = Size; 11 | 12 | static Events = Events; 13 | 14 | static Bounds = Bounds; 15 | 16 | static Path = Path; 17 | } 18 | -------------------------------------------------------------------------------- /src/components/ContextMenu/Item.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Util, BMapUtil, Constants } from '../../core'; 4 | 5 | const { CONTEXT_MENU_ICON } = Constants; 6 | // 内置ContextMenuIcon集合 7 | const builtInArray = [CONTEXT_MENU_ICON.ZOOM_IN, CONTEXT_MENU_ICON.ZOOM_OUT]; 8 | 9 | /** 10 | * 处理icon 11 | * @param {*} iconUrl icon链接 12 | */ 13 | const getIconUrl = (iconUrl) => { 14 | let icon = iconUrl; 15 | if (iconUrl && builtInArray.indexOf(iconUrl) > -1) { 16 | icon = global[iconUrl]; 17 | } 18 | return icon; 19 | }; 20 | 21 | export default class ContextMenuItem extends PureComponent { 22 | displayName = 'ContextMenuItem' 23 | 24 | instance = null 25 | 26 | static contextTypes = { 27 | addMenuItem: PropTypes.func, 28 | updateMenuItem: PropTypes.func, 29 | removeMenuItem: PropTypes.func, 30 | } 31 | 32 | componentDidMount() { 33 | const { context } = this; 34 | const { index } = this.props; 35 | 36 | this.instance = this.getInstance(); 37 | context.addMenuItem(index, this.instance); 38 | } 39 | 40 | componentDidUpdate() { 41 | const { context } = this; 42 | const { index } = this.props; 43 | this.instance = this.getInstance(); 44 | context.updateMenuItem(index, this.instance); 45 | } 46 | 47 | componentWillUnmount() { 48 | const { context } = this; 49 | const { index } = this.props; 50 | context.removeMenuItem(index); 51 | } 52 | 53 | /** 54 | * 根据 props 初始化MenuItem 55 | */ 56 | getInstance = () => { 57 | const { 58 | disabled, separator, iconUrl, 59 | text, width, id, onClick, 60 | } = this.props; 61 | const menuItem = BMapUtil.BMenuItem(text, onClick, { 62 | id, 63 | width, 64 | iconUrl: getIconUrl(iconUrl), 65 | }); 66 | menuItem.separator = separator; 67 | if (!Util.isNil(disabled) && disabled) { 68 | menuItem.disable(); 69 | } else { 70 | menuItem.enable(); 71 | } 72 | return menuItem; 73 | } 74 | 75 | render() { 76 | return null; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/components/ContextMenu/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Item from './Item'; 4 | import { BMapUtil } from '../../core'; 5 | 6 | export default class ContextMenu extends PureComponent { 7 | static Item = Item 8 | 9 | displayName = 'ContextMenu' 10 | 11 | static contextTypes = { 12 | centralizedUpdates: PropTypes.func, 13 | } 14 | 15 | // 子元素集合 16 | menuItems = []; 17 | 18 | // BContextMenu实例 19 | instance = null 20 | 21 | static childContextTypes = { 22 | addMenuItem: PropTypes.func, 23 | updateMenuItem: PropTypes.func, 24 | removeMenuItem: PropTypes.func, 25 | } 26 | 27 | getChildContext() { 28 | return { 29 | addMenuItem: this.addMenuItem, 30 | updateMenuItem: this.updateMenuItem, 31 | removeMenuItem: this.removeMenuItem, 32 | }; 33 | } 34 | 35 | componentDidMount() { 36 | const { context } = this; 37 | this.repaint(); 38 | context.centralizedUpdates({ 39 | name: 'contextMenu', 40 | data: this.instance, 41 | }); 42 | } 43 | 44 | componentDidUpdate() { 45 | const { context } = this; 46 | this.repaint(); 47 | context.centralizedUpdates({ 48 | name: 'contextMenu', 49 | data: this.instance, 50 | }); 51 | } 52 | 53 | addMenuItem = (index, item) => { 54 | if (this.menuItems[index]) { 55 | this.menuItems.splice(index, 0, item); 56 | } else { 57 | this.menuItems[index] = item; 58 | } 59 | } 60 | 61 | updateMenuItem = (index, item) => { 62 | this.menuItems[index] = item; 63 | } 64 | 65 | removeMenuItem = (index) => { 66 | this.menuItems.splice(index, 1, undefined); 67 | } 68 | 69 | repaint = () => { 70 | this.instance = BMapUtil.BContextMenu([...this.menuItems.filter(i => i)]); 71 | } 72 | 73 | renderChildren = () => React.Children.map(this.props.children, (child, index) => { 74 | if (child) { 75 | // 这里将 index 传递给MenuItem,保证子元素的显示顺序 76 | return React.cloneElement(child, { 77 | index, 78 | }); 79 | } 80 | return null; 81 | }) 82 | 83 | render() { 84 | return ( 85 |
86 | {this.renderChildren()} 87 |
88 | ); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/components/Control/BaseControl.js: -------------------------------------------------------------------------------- 1 | 2 | import { PureComponent } from 'react'; 3 | import PropTypes from 'prop-types'; 4 | import { Util } from '../../core'; 5 | 6 | class BaseControl extends PureComponent { 7 | static contextTypes = { 8 | getMapInstance: PropTypes.func, 9 | } 10 | 11 | static childContextTypes = { 12 | centralizedUpdates: PropTypes.func, 13 | } 14 | 15 | control = null 16 | 17 | mapInstance = null 18 | 19 | config = {} 20 | 21 | getChildContext() { 22 | return { 23 | centralizedUpdates: this.centralizedUpdates, 24 | }; 25 | } 26 | 27 | componentDidMount() { 28 | const { context, props } = this; 29 | const { children, ...resetProps } = props; 30 | this.config = { ...this.config, ...resetProps }; 31 | this.mapInstance = context.getMapInstance(); 32 | const control = this.getRealControl(); 33 | this.control = control; 34 | this.instance = control.instance; 35 | } 36 | 37 | componentDidUpdate() { 38 | const { children, ...resetProps } = this.props; 39 | this.config = { ...this.config, ...resetProps }; 40 | this.control.repaint(this.config); 41 | } 42 | 43 | componentWillUnmount() { 44 | this.control.destroy(); 45 | } 46 | 47 | centralizedUpdates = ({ name, data }) => { 48 | const configName = Util.firstLowerCase(name); 49 | this.config[configName] = data; 50 | } 51 | 52 | render() { 53 | const { children } = this.props; 54 | return children || null; 55 | } 56 | } 57 | 58 | export default BaseControl; 59 | -------------------------------------------------------------------------------- /src/components/Control/CityList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { CityList as BCityList } from '../../core'; 3 | import BaseControl from './BaseControl'; 4 | 5 | class CityList extends BaseControl { 6 | getRealControl = () => new BCityList(this.config, this.mapInstance) 7 | 8 | render() { 9 | const { children } = this.props; 10 | if (children) { 11 | return
{children}
; 12 | } 13 | return null; 14 | } 15 | } 16 | 17 | export default CityList; 18 | -------------------------------------------------------------------------------- /src/components/Control/CopyrightControl.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Copyright as BCopyright } from '../../core'; 4 | import BaseControl from './BaseControl'; 5 | 6 | import Copyright from '../Copyright'; 7 | 8 | class CopyrightControl extends BaseControl { 9 | static Copyright = Copyright; 10 | 11 | static childContextTypes = { 12 | addCopyright: PropTypes.func, 13 | updateCopyright: PropTypes.func, 14 | removeCopyright: PropTypes.func, 15 | } 16 | 17 | config = { 18 | copyrights: [], 19 | } 20 | 21 | getChildContext() { 22 | return { 23 | addCopyright: this.addCopyright, 24 | updateCopyright: this.updateCopyright, 25 | removeCopyright: this.removeCopyright, 26 | }; 27 | } 28 | 29 | addCopyright = (index, item) => { 30 | if (this.config.copyrights[index]) { 31 | this.config.copyrights.splice(index, 0, item); 32 | } else { 33 | this.config.copyrights[index] = item; 34 | } 35 | } 36 | 37 | updateCopyright = (index, item) => { 38 | this.config.copyrights.splice(index, 1, item); 39 | } 40 | 41 | removeCopyright = (index) => { 42 | this.config.copyrights.splice(index, 1, undefined); 43 | } 44 | 45 | getRealControl = () => { 46 | this.config.copyrights = this.config.copyrights.filter(item => item); 47 | return new BCopyright(this.config, this.mapInstance) 48 | } 49 | 50 | renderChildren = () => React.Children.map(this.props.children, (child, index) => { 51 | if (child) { 52 | return React.cloneElement(child, { 53 | index, 54 | }); 55 | } 56 | return null; 57 | }) 58 | 59 | render() { 60 | return ( 61 |
62 | {this.renderChildren()} 63 |
64 | ); 65 | } 66 | } 67 | 68 | export default CopyrightControl; 69 | -------------------------------------------------------------------------------- /src/components/Control/Custom.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { initCustomControl } from '../../core'; 3 | import BaseControl from './BaseControl'; 4 | 5 | const CustomHOC = WrappedComponent => class extends BaseControl { 6 | config = {} 7 | 8 | control = null 9 | 10 | componentDidMount() { 11 | const { context } = this; 12 | const { children, ...resetProps } = this.props; 13 | this.config = { ...this.config, ...resetProps }; 14 | this.mapInstance = context.getMapInstance(); 15 | this.control = initCustomControl(this.config, this.initialize, this.mapInstance); 16 | } 17 | 18 | getContainer = (ref) => { 19 | this.container = ref; 20 | } 21 | 22 | initialize = () => { 23 | const { container, mapInstance } = this; 24 | mapInstance.getContainer().appendChild(container); 25 | return container; 26 | } 27 | 28 | render() { 29 | const { context } = this; 30 | const { children } = this.props; 31 | return ( 32 |
33 | 37 | { children } 38 |
39 | ); 40 | } 41 | }; 42 | 43 | export default CustomHOC; 44 | -------------------------------------------------------------------------------- /src/components/Control/Geolocation.js: -------------------------------------------------------------------------------- 1 | import { Geolocation as BGeolocation } from '../../core'; 2 | import BaseControl from './BaseControl'; 3 | 4 | class Geolocation extends BaseControl { 5 | getRealControl = () => new BGeolocation(this.config, this.mapInstance) 6 | } 7 | 8 | export default Geolocation; 9 | -------------------------------------------------------------------------------- /src/components/Control/MapType.js: -------------------------------------------------------------------------------- 1 | import { MapType as BMapType } from '../../core'; 2 | import BaseControl from './BaseControl'; 3 | 4 | class MapType extends BaseControl { 5 | getRealControl = () => new BMapType(this.config, this.mapInstance) 6 | } 7 | 8 | export default MapType; 9 | -------------------------------------------------------------------------------- /src/components/Control/Navigation.js: -------------------------------------------------------------------------------- 1 | import { Navigation as BNavigation } from '../../core'; 2 | import BaseControl from './BaseControl'; 3 | 4 | class Navigation extends BaseControl { 5 | getRealControl = () => new BNavigation(this.config, this.mapInstance) 6 | } 7 | 8 | export default Navigation; 9 | -------------------------------------------------------------------------------- /src/components/Control/OverviewMap.js: -------------------------------------------------------------------------------- 1 | import BaseControl from './BaseControl'; 2 | import { OverviewMap as BOverviewMap } from '../../core'; 3 | 4 | class OverviewMap extends BaseControl { 5 | getRealControl = () => new BOverviewMap(this.config, this.mapInstance) 6 | } 7 | 8 | export default OverviewMap; 9 | -------------------------------------------------------------------------------- /src/components/Control/Panorama.js: -------------------------------------------------------------------------------- 1 | import { Panorama as BPanorama } from '../../core'; 2 | import BaseControl from './BaseControl'; 3 | 4 | class Panorama extends BaseControl { 5 | getRealControl = () => new BPanorama(this.config, this.mapInstance) 6 | } 7 | 8 | export default Panorama; 9 | -------------------------------------------------------------------------------- /src/components/Control/Scale.js: -------------------------------------------------------------------------------- 1 | import BaseControl from './BaseControl'; 2 | import { Scale as BScale } from '../../core'; 3 | 4 | class Scale extends BaseControl { 5 | getRealControl = () => new BScale(this.config, this.mapInstance) 6 | } 7 | 8 | export default Scale; 9 | -------------------------------------------------------------------------------- /src/components/Copyright/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const containerStyle = { 5 | position: 'absolute', 6 | top: -10000, 7 | }; 8 | 9 | export default class Copyright extends PureComponent { 10 | static contextTypes = { 11 | getMapInstance: PropTypes.func, 12 | addCopyright: PropTypes.func, 13 | updateCopyright: PropTypes.func, 14 | removeCopyright: PropTypes.func, 15 | } 16 | 17 | componentDidMount() { 18 | const { context } = this; 19 | const { index } = this.props; 20 | context.addCopyright(index, this.getCopyright()); 21 | } 22 | 23 | componentDidUpdate() { 24 | const { context } = this; 25 | const { index } = this.props; 26 | context.updateCopyright(index, this.getCopyright()); 27 | } 28 | 29 | componentWillUnmount() { 30 | const { context } = this; 31 | const { index } = this.props; 32 | context.removeCopyright(index); 33 | } 34 | 35 | getCopyright = () => { 36 | const { context } = this; 37 | const { index, bounds } = this.props; 38 | return { 39 | id: index, 40 | bounds: bounds || context.getMapInstance().getBounds(), 41 | content: this.container.innerHTML, 42 | }; 43 | } 44 | 45 | getContainer = (ref) => { 46 | this.container = ref; 47 | } 48 | 49 | render() { 50 | const { children } = this.props; 51 | return ( 52 |
53 | {children} 54 |
55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/components/Layer/TileLayer.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { TileLayer as BTileLayer } from '../../core'; 4 | 5 | class TileLayer extends PureComponent { 6 | static contextTypes = { 7 | getMapInstance: PropTypes.func, 8 | } 9 | 10 | componentDidMount() { 11 | const { context, props } = this; 12 | const { children, ...resetProps } = props; 13 | this.config = { ...this.config, ...resetProps }; 14 | this.mapInstance = context.getMapInstance(); 15 | const layer = new BTileLayer(this.config, this.mapInstance); 16 | this.layer = layer; 17 | this.instance = layer.instance; 18 | } 19 | 20 | componentDidUpdate() { 21 | const { children, ...resetProps } = this.props; 22 | this.config = { ...this.config, ...resetProps }; 23 | this.layer.repaint({ ...this.config }); 24 | } 25 | 26 | componentWillUnmount() { 27 | this.layer.destroy(); 28 | } 29 | 30 | render() { 31 | const { children } = this.props; 32 | return children || null; 33 | } 34 | } 35 | 36 | export default TileLayer; 37 | -------------------------------------------------------------------------------- /src/components/Layer/TrafficLayer.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { TrafficLayer as BTrafficLayer } from '../../core'; 4 | 5 | class TrafficLayer extends PureComponent { 6 | static contextTypes = { 7 | getMapInstance: PropTypes.func, 8 | } 9 | 10 | componentDidMount() { 11 | const { context, props } = this; 12 | const { children, ...resetProps } = props; 13 | this.config = { ...this.config, ...resetProps }; 14 | this.mapInstance = context.getMapInstance(); 15 | const layer = new BTrafficLayer(this.config, this.mapInstance); 16 | this.layer = layer; 17 | this.instance = layer.instance; 18 | } 19 | 20 | componentDidUpdate() { 21 | const { children, ...resetProps } = this.props; 22 | this.config = { ...this.config, ...resetProps }; 23 | this.layer.repaint({ ...this.config }); 24 | } 25 | 26 | componentWillUnmount() { 27 | this.layer.destroy(); 28 | } 29 | 30 | render() { 31 | const { children } = this.props; 32 | return children || null; 33 | } 34 | } 35 | 36 | export default TrafficLayer; 37 | -------------------------------------------------------------------------------- /src/components/Library/CurveLine/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { CurveLine as BCurveLine, Util } from '../../../core'; 4 | 5 | class CurveLine extends PureComponent { 6 | static contextTypes = { 7 | getMapInstance: PropTypes.func, 8 | } 9 | 10 | static childContextTypes = { 11 | centralizedUpdates: PropTypes.func, 12 | } 13 | 14 | config = {} 15 | 16 | getChildContext() { 17 | return { 18 | centralizedUpdates: this.centralizedUpdates, 19 | }; 20 | } 21 | 22 | componentDidMount() { 23 | const map = this.context.getMapInstance(); 24 | 25 | const { children, ...resetProps } = this.props; 26 | this.config = { ...this.config, ...resetProps }; 27 | 28 | Util.syncScript('https://api.map.baidu.com/library/CurveLine/1.5/src/CurveLine.min.js') 29 | .then(() => { 30 | this.tool = new BCurveLine({ ...this.config }, map); 31 | if (this.props.getInstance) { 32 | this.props.getInstance(this.tool.instance); 33 | } 34 | }); 35 | } 36 | 37 | componentDidUpdate() { 38 | if (this.tool) { 39 | const { children, ...resetProps } = this.props; 40 | this.config = { ...this.config, ...resetProps }; 41 | this.tool.repaint(this.config); 42 | } 43 | } 44 | 45 | 46 | componentWillUnmount() { 47 | if (this.tool) { 48 | this.tool.destroy(); 49 | } 50 | } 51 | 52 | centralizedUpdates = ({ name, data }) => { 53 | const configName = Util.firstLowerCase(name); 54 | this.config[configName] = data; 55 | } 56 | 57 | render() { 58 | const { children } = this.props; 59 | return ( 60 |
61 | {children} 62 |
63 | ); 64 | } 65 | } 66 | 67 | export default CurveLine; 68 | -------------------------------------------------------------------------------- /src/components/Library/DistanceTool/Icon.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Icon as BIcon, Util } from '../../../core'; 4 | 5 | export default class Icon extends PureComponent { 6 | config = {} 7 | 8 | static contextTypes = { 9 | centralizedUpdates: PropTypes.func, 10 | } 11 | 12 | static childContextTypes = { 13 | centralizedUpdates: PropTypes.func, 14 | } 15 | 16 | getChildContext() { 17 | return { 18 | centralizedUpdates: this.centralizedUpdates, 19 | }; 20 | } 21 | 22 | componentDidMount() { 23 | const { context, props } = this; 24 | context.centralizedUpdates({ 25 | name: props.name || 'secIcon', 26 | data: this.getIcon(), 27 | }); 28 | } 29 | 30 | componentDidUpdate() { 31 | const { context, props } = this; 32 | context.centralizedUpdates({ 33 | name: props.name || 'secIcon', 34 | data: this.getIcon(), 35 | }); 36 | } 37 | 38 | centralizedUpdates = ({ name, data }) => { 39 | const configName = Util.firstLowerCase(name); 40 | this.config[configName] = data; 41 | } 42 | 43 | getIcon = () => { 44 | const { children, ...resetProps } = this.props; 45 | this.config = { ...this.config, ...resetProps }; 46 | 47 | return new BIcon({ ...this.config }); 48 | } 49 | 50 | render() { 51 | const { children } = this.props; 52 | return children || null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/Library/DistanceTool/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Icon from './Icon'; 4 | import { DistanceTool as BDistanceTool, Util } from '../../../core'; 5 | 6 | class DistanceTool extends PureComponent { 7 | static Icon = Icon 8 | 9 | static contextTypes = { 10 | getMapInstance: PropTypes.func, 11 | } 12 | 13 | static childContextTypes = { 14 | centralizedUpdates: PropTypes.func, 15 | } 16 | 17 | config = {} 18 | 19 | 20 | getChildContext() { 21 | return { 22 | centralizedUpdates: this.centralizedUpdates, 23 | }; 24 | } 25 | 26 | componentDidMount() { 27 | const map = this.context.getMapInstance(); 28 | 29 | const { children, ...resetProps } = this.props; 30 | this.config = { ...this.config, ...resetProps }; 31 | 32 | Util.syncScript('https://api.map.baidu.com/library/DistanceTool/1.2/src/DistanceTool_min.js') 33 | .then(() => { 34 | this.tool = new BDistanceTool({ ...this.config }, map); 35 | if (this.props.getInstance) { 36 | this.props.getInstance(this.tool.instance); 37 | } 38 | }); 39 | } 40 | 41 | componentDidUpdate() { 42 | if (this.tool) { 43 | const { children, ...resetProps } = this.props; 44 | this.config = { ...this.config, ...resetProps }; 45 | this.tool.init(this.config); 46 | } 47 | } 48 | 49 | 50 | componentWillUnmount() { 51 | if (this.tool) { 52 | this.tool.destroy(); 53 | } 54 | } 55 | 56 | centralizedUpdates = ({ name, data }) => { 57 | const configName = Util.firstLowerCase(name); 58 | this.config[configName] = data; 59 | } 60 | 61 | render() { 62 | const { children } = this.props; 63 | return ( 64 |
65 | {children} 66 |
67 | ); 68 | } 69 | } 70 | 71 | export default DistanceTool; 72 | -------------------------------------------------------------------------------- /src/components/Library/HeatMap/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { HeatMap as BHeatMap, Util } from '../../../core'; 4 | 5 | class HeatMap extends PureComponent { 6 | static contextTypes = { 7 | getMapInstance: PropTypes.func, 8 | } 9 | 10 | static childContextTypes = { 11 | centralizedUpdates: PropTypes.func, 12 | } 13 | 14 | config = {} 15 | 16 | getChildContext() { 17 | return { 18 | centralizedUpdates: this.centralizedUpdates, 19 | }; 20 | } 21 | 22 | componentDidMount() { 23 | const map = this.context.getMapInstance(); 24 | 25 | const { children, ...resetProps } = this.props; 26 | this.config = { ...this.config, ...resetProps }; 27 | 28 | Util.syncScript('https://api.map.baidu.com/library/Heatmap/2.0/src/Heatmap_min.js') 29 | .then(() => { 30 | this.tool = new BHeatMap({ ...this.config }, map); 31 | if (this.props.getInstance) { 32 | this.props.getInstance(this.tool.instance); 33 | } 34 | }); 35 | } 36 | 37 | componentDidUpdate() { 38 | if (this.tool) { 39 | const { children, ...resetProps } = this.props; 40 | this.config = { ...this.config, ...resetProps }; 41 | this.tool.repaint(this.config); 42 | } 43 | } 44 | 45 | 46 | componentWillUnmount() { 47 | if (this.tool) { 48 | this.tool.destroy(); 49 | } 50 | } 51 | 52 | centralizedUpdates = ({ name, data }) => { 53 | const configName = Util.firstLowerCase(name); 54 | this.config[configName] = data; 55 | } 56 | 57 | render() { 58 | const { children } = this.props; 59 | return ( 60 |
61 | {children} 62 |
63 | ); 64 | } 65 | } 66 | 67 | export default HeatMap; 68 | -------------------------------------------------------------------------------- /src/components/Map/PlaceHolder.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | 3 | const style = { 4 | height: '100%', 5 | width: '100%', 6 | display: 'flex', 7 | justifyContent: 'center', 8 | alignItems: 'center', 9 | }; 10 | 11 | export default class PlaceHolder extends PureComponent { 12 | static displayName= 'PlaceHolder' 13 | 14 | render() { 15 | const { children } = this.props; 16 | return children ||
地图加载中...
; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/components/Map/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import initMap, { Util } from '../../core'; 4 | import ContextMenu from '../ContextMenu'; 5 | import PlaceHolder from './PlaceHolder'; 6 | 7 | const fillStyle = { 8 | width: '100%', 9 | height: '100%', 10 | }; 11 | 12 | export default class Map extends PureComponent { 13 | static PlaceHolder = PlaceHolder; 14 | 15 | static ContextMenu = ContextMenu; 16 | 17 | static childContextTypes = { 18 | getMapInstance: PropTypes.func, 19 | centralizedUpdates: PropTypes.func, 20 | } 21 | 22 | config = {} 23 | 24 | // 仅用作config的组件 25 | configComponent = ['Point', 'PlaceHolder'] 26 | 27 | getChildContext() { 28 | return { 29 | getMapInstance: this.getMapInstance, 30 | centralizedUpdates: this.centralizedUpdates, 31 | }; 32 | } 33 | 34 | componentDidMount() { 35 | const { children, ...resetProps } = this.props; 36 | this.config = { ...this.config, ...resetProps }; 37 | this.createMapInstance(this.config); 38 | } 39 | 40 | componentDidUpdate() { 41 | const { children, ...resetProps } = this.props; 42 | this.config = { ...this.config, ...resetProps }; 43 | if (this.map) { 44 | this.map.repaint(this.config); 45 | } 46 | } 47 | 48 | /** 49 | * 内部子组件属性更新触发方法 50 | */ 51 | centralizedUpdates = ({ name, data }) => { 52 | const configName = Util.firstLowerCase(name); 53 | this.config[configName] = data; 54 | } 55 | 56 | /** 57 | * 初始化地图实例 58 | */ 59 | createMapInstance = async (config) => { 60 | const { mounted, name } = this.props; 61 | this.map = await initMap(this.mapContainer, config); 62 | const mapInstance = this.map.instance; 63 | if (name) { 64 | global[`${name}`] = mapInstance; 65 | } 66 | this.forceUpdate(() => { 67 | if (mounted) { 68 | mounted(mapInstance); 69 | } 70 | }); 71 | } 72 | 73 | /** 74 | * 获得地图容器ref 75 | */ 76 | getMapContainer = (ref) => { 77 | this.mapContainer = ref; 78 | } 79 | 80 | /** 81 | * 获得地图实例 82 | */ 83 | getMapInstance = () => this.map && this.map.instance 84 | 85 | renderChildren = () => { 86 | const { children } = this.props; 87 | return React.Children.map(children, (child) => { 88 | if (this.map || (child && this.configComponent.indexOf(child.type.displayName) > -1)) { 89 | return child; 90 | } 91 | return null; 92 | }); 93 | } 94 | 95 | render() { 96 | return ( 97 |
98 | { this.renderChildren() } 99 |
100 | ); 101 | } 102 | } 103 | 104 | 105 | Map.propTypes = { 106 | //  107 | ak: PropTypes.string, 108 | // 地图实例别名 109 | // 设置后可通过window[name]进行获取 110 | name: PropTypes.string, 111 | // 当前缩放等级 112 | zoom: PropTypes.number, 113 | // 当前百度地图版本, 2 or 3 114 | version: PropTypes.number, 115 | // 最小缩放等级 116 | minZoom: PropTypes.number, 117 | // 最大缩放等级 118 | maxZoom: PropTypes.number, 119 | // 设置地图默认的鼠标指针样式 120 | defaultCursor: PropTypes.string, 121 | // 设置拖拽地图时的鼠标指针样式 122 | draggingCursor: PropTypes.string, 123 | // 设置地图样式,样式包括地图底图颜色和地图要素是否展示两部分 124 | mapStyle: PropTypes.object, 125 | // 设置地图个性化样式V2版本,仅支持现代浏览器(支持Canvas) 126 | mapStyleV2: PropTypes.object, 127 | // 设置地图类型 128 | mapType: PropTypes.string, 129 | // 地图初始化完成回调函数 130 | mounted: PropTypes.func, 131 | // 是否启用使用高分辨率地图 132 | highResolution: PropTypes.bool, 133 | // 自动适应地图容器变化 134 | autoResize: PropTypes.bool, 135 | // 地图可点 136 | mapClick: PropTypes.bool, 137 | // 拖拽 138 | dragging: PropTypes.bool, 139 | // 滚轮缩放 140 | scrollWheelZoom: PropTypes.bool, 141 | // 双击放大 142 | doubleClickZoom: PropTypes.bool, 143 | // 键盘操作 144 | keyboard: PropTypes.bool, 145 | // 惯性拖拽 146 | inertialDragging: PropTypes.bool, 147 | // 连续缩放 148 | continuousZoom: PropTypes.bool, 149 | // 双指操作 150 | pinchToZoom: PropTypes.bool, 151 | }; 152 | -------------------------------------------------------------------------------- /src/components/Overlay/BaseOverlay.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Util } from '../../core'; 4 | 5 | class BaseOverlay extends PureComponent { 6 | static contextTypes = { 7 | getMapInstance: PropTypes.func, 8 | } 9 | 10 | static childContextTypes = { 11 | centralizedUpdates: PropTypes.func, 12 | } 13 | 14 | overlay = null 15 | 16 | mapInstance = null 17 | 18 | config = {} 19 | 20 | getChildContext() { 21 | return { 22 | centralizedUpdates: this.centralizedUpdates, 23 | }; 24 | } 25 | 26 | componentDidMount() { 27 | const { context, props } = this; 28 | const { children, ...resetProps } = props; 29 | this.config = { ...this.config, ...resetProps }; 30 | this.mapInstance = context.getMapInstance(); 31 | const overlay = this.getRealOverlay(); 32 | this.overlay = overlay; 33 | this.instance = overlay.instance; 34 | } 35 | 36 | componentDidUpdate() { 37 | const { children, ...resetProps } = this.props; 38 | this.config = { ...this.config, ...resetProps }; 39 | this.overlay.repaint({ ...this.config }); 40 | // fix: when the custom overlay change the point, overlay need redraw 41 | if (this.draw) { 42 | this.draw(); 43 | } 44 | } 45 | 46 | componentWillUnmount() { 47 | this.overlay.destroy(); 48 | } 49 | 50 | centralizedUpdates = ({ name, data }) => { 51 | const configName = Util.firstLowerCase(name); 52 | this.config[configName] = data; 53 | } 54 | 55 | render() { 56 | const { children } = this.props; 57 | if (children) { 58 | return
{children}
; 59 | } 60 | return null; 61 | } 62 | } 63 | 64 | export default BaseOverlay; 65 | -------------------------------------------------------------------------------- /src/components/Overlay/Boundary.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Polygon from './Polygon'; 4 | import Base from '../Base'; 5 | import { Util } from '../../core'; 6 | 7 | const { Point, Path } = Base; 8 | 9 | class Boundary extends PureComponent { 10 | static contextTypes = { 11 | getMapInstance: PropTypes.func, 12 | } 13 | 14 | state = { 15 | name: '', 16 | area: [], 17 | } 18 | 19 | componentDidMount() { 20 | const { name } = this.props; 21 | this.getPoints(name); 22 | } 23 | 24 | componentDidUpdate() { 25 | const { name } = this.props; 26 | if (name !== this.state.name) { 27 | this.getPoints(name); 28 | } 29 | } 30 | 31 | getPoints = (name) => { 32 | Util.getBoundary(name).then(({ points, area }) => { 33 | this.processAutoViewport(points); 34 | this.setState({ 35 | name, 36 | area, 37 | }); 38 | }); 39 | } 40 | 41 | processAutoViewport(points = []) { 42 | const { context, props } = this; 43 | const { autoViewport } = props; 44 | if (autoViewport) { 45 | context.getMapInstance().setViewport(points); 46 | } 47 | } 48 | 49 | render() { 50 | const { area, name } = this.state; 51 | const { children, ...resetProps } = this.props; 52 | return ( 53 | area.length > 0 ? ( 54 |
55 | { 56 | area.map((points, index) => ( 57 | 61 | 62 | { 63 | points.map((item, idx) => ( 64 | 65 | )) 66 | } 67 | 68 | { children } 69 | 70 | )) 71 | } 72 |
73 | ) : null 74 | ); 75 | } 76 | } 77 | 78 | export default Boundary; 79 | -------------------------------------------------------------------------------- /src/components/Overlay/Circle.js: -------------------------------------------------------------------------------- 1 | import BaseOverlay from './BaseOverlay'; 2 | import { Circle as BCircle } from '../../core'; 3 | 4 | class Circle extends BaseOverlay { 5 | getRealOverlay = () => new BCircle(this.config, this.mapInstance) 6 | } 7 | 8 | export default Circle; 9 | -------------------------------------------------------------------------------- /src/components/Overlay/Custom.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { initCustomOverlay, Util, Constants } from '../../core'; 3 | import BaseOverlay from './BaseOverlay'; 4 | 5 | const { MAP_PANES } = Constants; 6 | 7 | // fix: #106 the custom overlay's container position should be absolute 8 | const containerStyle = { 9 | position: 'absolute', 10 | }; 11 | 12 | const CustomHOC = WrappedComponent => class extends BaseOverlay { 13 | config = {} 14 | 15 | overlay = null 16 | 17 | componentDidMount() { 18 | const { context } = this; 19 | const { children, ...resetProps } = this.props; 20 | this.config = { ...this.config, ...resetProps }; 21 | this.mapInstance = context.getMapInstance(); 22 | this.overlay = initCustomOverlay(this.config, this.initialize, this.draw, this.mapInstance); 23 | } 24 | 25 | getContainer = (ref) => { 26 | this.container = ref; 27 | } 28 | 29 | initialize = () => { 30 | const { container, mapInstance } = this; 31 | mapInstance.getPanes()[MAP_PANES.MARKER].appendChild(container); 32 | return container; 33 | } 34 | 35 | draw = () => { 36 | const { container, mapInstance } = this; 37 | const { point, offset = { width: 0, height: 0 } } = this.config; 38 | const bdPoint = Util.convert2BPoint({ ...point }); 39 | // 当地图scroll时,container的高度为0 宽度为0,导致计算出现错误,所以存储上次有效宽高 40 | this.lastWidth = container.offsetWidth > 0 ? container.offsetWidth : this.lastWidth; 41 | this.lastHeight = container.offsetHeight > 0 ? container.offsetHeight : this.lastHeight; 42 | 43 | const position = mapInstance.pointToOverlayPixel(bdPoint); 44 | container.style.left = `${position.x - this.lastWidth / 2 + offset.width / 2}px`; 45 | container.style.top = `${position.y - this.lastHeight / 2 + offset.height / 2}px`; 46 | } 47 | 48 | render() { 49 | const { context } = this; 50 | const { children } = this.props; 51 | return ( 52 |
53 |
54 | 58 | { children } 59 |
60 |
61 | ); 62 | } 63 | }; 64 | 65 | export default CustomHOC; 66 | -------------------------------------------------------------------------------- /src/components/Overlay/Ground.js: -------------------------------------------------------------------------------- 1 | import { GroundOverlay as BGroundOverlay } from '../../core'; 2 | import BaseOverlay from './BaseOverlay'; 3 | 4 | class Ground extends BaseOverlay { 5 | getRealOverlay = () => new BGroundOverlay(this.config, this.mapInstance) 6 | } 7 | 8 | export default Ground; 9 | -------------------------------------------------------------------------------- /src/components/Overlay/HTMLComponent.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import PropTypes from 'prop-types'; 4 | 5 | class HTMLComponent extends PureComponent { 6 | static contextTypes = { 7 | centralizedUpdates: PropTypes.func, 8 | } 9 | 10 | static displayName = 'HTMLComponent'; 11 | 12 | constructor(props) { 13 | super(props); 14 | this.div = document.createElement('div'); 15 | } 16 | 17 | componentDidMount() { 18 | const { context } = this; 19 | ReactDOM.render(this.props.children, this.div); 20 | context.centralizedUpdates({ 21 | name: this.name, 22 | data: this.div, 23 | }); 24 | } 25 | 26 | componentDidUpdate() { 27 | const { context } = this; 28 | ReactDOM.render(this.props.children, this.div); 29 | context.centralizedUpdates({ 30 | name: this.name, 31 | data: this.div, 32 | }); 33 | } 34 | 35 | componentWillUnmount() { 36 | const { context } = this; 37 | context.centralizedUpdates({ 38 | name: this.name, 39 | data: null, 40 | }); 41 | } 42 | 43 | render() { 44 | return null; 45 | } 46 | } 47 | 48 | export default HTMLComponent; 49 | -------------------------------------------------------------------------------- /src/components/Overlay/HTMLStringComponent.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | 4 | const containerStyle = { 5 | position: 'absolute', 6 | top: -10000, 7 | }; 8 | 9 | class HTMLStringComponent extends PureComponent { 10 | static contextTypes = { 11 | centralizedUpdates: PropTypes.func, 12 | } 13 | 14 | static displayName = 'HTMLComponent'; 15 | 16 | componentDidMount() { 17 | const { context } = this; 18 | this.instance = this.content.innerHTML; 19 | context.centralizedUpdates({ 20 | name: this.name, 21 | data: this.content.innerHTML, 22 | }); 23 | } 24 | 25 | componentDidUpdate() { 26 | const { context } = this; 27 | context.centralizedUpdates({ 28 | name: this.name, 29 | data: this.content.innerHTML, 30 | }); 31 | } 32 | 33 | componentWillUnmount() { 34 | const { context } = this; 35 | context.centralizedUpdates({ 36 | name: this.name, 37 | data: null, 38 | }); 39 | } 40 | 41 | getContent = (ref) => { 42 | this.content = ref; 43 | } 44 | 45 | render() { 46 | const { children } = this.props; 47 | return ( 48 |
49 | { children || null } 50 |
51 | ); 52 | } 53 | } 54 | 55 | export default HTMLStringComponent; -------------------------------------------------------------------------------- /src/components/Overlay/InfoWindow/Content.js: -------------------------------------------------------------------------------- 1 | import HTMLComponent from '../HTMLComponent'; 2 | 3 | class Content extends HTMLComponent { 4 | name = 'content'; 5 | } 6 | 7 | export default Content; 8 | -------------------------------------------------------------------------------- /src/components/Overlay/InfoWindow/MaxContent.js: -------------------------------------------------------------------------------- 1 | import HTMLComponent from '../HTMLComponent'; 2 | 3 | class MaxContent extends HTMLComponent { 4 | name = 'maxContent'; 5 | } 6 | 7 | export default MaxContent; 8 | -------------------------------------------------------------------------------- /src/components/Overlay/InfoWindow/Title.js: -------------------------------------------------------------------------------- 1 | import HTMLComponent from '../HTMLComponent'; 2 | 3 | class Title extends HTMLComponent { 4 | name = 'title'; 5 | } 6 | 7 | export default Title; 8 | -------------------------------------------------------------------------------- /src/components/Overlay/InfoWindow/index.js: -------------------------------------------------------------------------------- 1 | import BaseOverlay from '../BaseOverlay'; 2 | import { InfoWindow as BInfoWindow } from '../../../core'; 3 | import Content from './Content'; 4 | import Title from './Title'; 5 | import MaxContent from './MaxContent'; 6 | 7 | class InfoWindow extends BaseOverlay { 8 | static Content = Content; 9 | 10 | static Title = Title; 11 | 12 | static MaxContent = MaxContent; 13 | 14 | getRealOverlay = () => new BInfoWindow(this.config, this.mapInstance); 15 | } 16 | 17 | export default InfoWindow; 18 | -------------------------------------------------------------------------------- /src/components/Overlay/Label/Content.js: -------------------------------------------------------------------------------- 1 | import HTMLStringComponent from '../HTMLStringComponent'; 2 | 3 | class Content extends HTMLStringComponent { 4 | name = 'content' 5 | } 6 | 7 | export default Content; 8 | -------------------------------------------------------------------------------- /src/components/Overlay/Label/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import BaseOverlay from '../BaseOverlay'; 3 | import { Label as BLabel } from '../../../core'; 4 | import Content from './Content'; 5 | 6 | class Label extends BaseOverlay { 7 | static Content = Content; 8 | 9 | static contextTypes = { 10 | getMapInstance: PropTypes.func, 11 | centralizedUpdates: PropTypes.func, 12 | } 13 | 14 | componentDidMount() { 15 | const { context, props } = this; 16 | const { children, ...resetProps } = props; 17 | this.config = { ...this.config, ...resetProps }; 18 | this.mapInstance = context.getMapInstance(); 19 | const overlay = this.getRealOverlay(); 20 | this.overlay = overlay; 21 | this.instance = overlay.instance; 22 | 23 | context.centralizedUpdates({ 24 | name: 'label', 25 | data: this.instance, 26 | }); 27 | } 28 | 29 | componentDidUpdate() { 30 | const { context } = this; 31 | const { children, ...resetProps } = this.props; 32 | this.config = { ...this.config, ...resetProps }; 33 | this.overlay.repaint({ ...this.config }); 34 | 35 | context.centralizedUpdates({ 36 | name: 'label', 37 | data: this.overlay.instance, 38 | }); 39 | } 40 | 41 | getRealOverlay = () => new BLabel(this.config, this.mapInstance) 42 | } 43 | 44 | export default Label; 45 | -------------------------------------------------------------------------------- /src/components/Overlay/Marker/Icon.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Icon as BIcon, Util } from '../../../core'; 4 | 5 | export default class Icon extends PureComponent { 6 | config = {} 7 | 8 | static contextTypes = { 9 | centralizedUpdates: PropTypes.func, 10 | } 11 | 12 | static childContextTypes = { 13 | centralizedUpdates: PropTypes.func, 14 | } 15 | 16 | getChildContext() { 17 | return { 18 | centralizedUpdates: this.centralizedUpdates, 19 | }; 20 | } 21 | 22 | componentDidMount() { 23 | const { context } = this; 24 | context.centralizedUpdates({ 25 | name: 'icon', 26 | data: this.getIcon(), 27 | }); 28 | } 29 | 30 | componentDidUpdate() { 31 | const { context } = this; 32 | context.centralizedUpdates({ 33 | name: 'icon', 34 | data: this.getIcon(), 35 | }); 36 | } 37 | 38 | centralizedUpdates = ({ name, data }) => { 39 | const configName = Util.firstLowerCase(name); 40 | this.config[configName] = data; 41 | } 42 | 43 | getIcon = () => { 44 | const { children, ...resetProps } = this.props; 45 | this.config = { ...this.config, ...resetProps }; 46 | 47 | return new BIcon({ ...this.config }); 48 | } 49 | 50 | render() { 51 | const { children } = this.props; 52 | return children || null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/components/Overlay/Marker/index.js: -------------------------------------------------------------------------------- 1 | import BaseOverlay from '../BaseOverlay'; 2 | import ContextMenu from '../../ContextMenu'; 3 | import Icon from './Icon'; 4 | import Symbol from '../Symbol'; 5 | import { Marker as BMarker } from '../../../core'; 6 | 7 | class Marker extends BaseOverlay { 8 | static ContextMenu = ContextMenu; 9 | 10 | static Icon = Icon; 11 | 12 | static Symbol = Symbol; 13 | 14 | getRealOverlay = () => { 15 | // symbol 覆盖 icon 属性 16 | if (this.config.symbol) { 17 | this.config.icon = this.config.symbol; 18 | } 19 | return new BMarker(this.config, this.mapInstance); 20 | } 21 | } 22 | 23 | export default Marker; 24 | -------------------------------------------------------------------------------- /src/components/Overlay/PointCollection.js: -------------------------------------------------------------------------------- 1 | import BaseOverlay from './BaseOverlay'; 2 | import { PointCollection as BPointCollection } from '../../core'; 3 | 4 | class PointCollection extends BaseOverlay { 5 | getRealOverlay = () => new BPointCollection(this.config, this.mapInstance) 6 | } 7 | 8 | export default PointCollection; 9 | -------------------------------------------------------------------------------- /src/components/Overlay/Polygon.js: -------------------------------------------------------------------------------- 1 | import BaseOverlay from './BaseOverlay'; 2 | import { Polygon as BPolygon } from '../../core'; 3 | 4 | class Polygon extends BaseOverlay { 5 | getRealOverlay = () => new BPolygon(this.config, this.mapInstance); 6 | } 7 | 8 | export default Polygon; 9 | -------------------------------------------------------------------------------- /src/components/Overlay/Polyline/IconSequence.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Symbol from '../Symbol'; 4 | import { IconSequence as BIconSequence, Util } from '../../../core'; 5 | 6 | export default class IconSequence extends PureComponent { 7 | static Symbol = Symbol; 8 | 9 | config = {}; 10 | 11 | static contextTypes = { 12 | centralizedUpdates: PropTypes.func, 13 | } 14 | 15 | static childContextTypes = { 16 | centralizedUpdates: PropTypes.func, 17 | } 18 | 19 | getChildContext() { 20 | return { 21 | centralizedUpdates: this.centralizedUpdates, 22 | }; 23 | } 24 | 25 | componentDidMount() { 26 | const { context } = this; 27 | context.centralizedUpdates({ 28 | name: 'icons', 29 | data: [this.iconSequence()], 30 | }); 31 | } 32 | 33 | componentDidUpdate() { 34 | const { context } = this; 35 | context.centralizedUpdates({ 36 | name: 'icons', 37 | data: [this.iconSequence()], 38 | }); 39 | } 40 | 41 | centralizedUpdates = ({ name, data }) => { 42 | const configName = Util.firstLowerCase(name); 43 | this.config[configName] = data; 44 | } 45 | 46 | iconSequence = () => { 47 | const { children, ...resetProps } = this.props; 48 | this.config = { ...this.config, ...resetProps }; 49 | return new BIconSequence({ ...this.config }); 50 | } 51 | 52 | render() { 53 | const { children } = this.props; 54 | return children || null; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/components/Overlay/Polyline/index.js: -------------------------------------------------------------------------------- 1 | import IconSequence from './IconSequence'; 2 | import BaseOverlay from '../BaseOverlay'; 3 | import { Polyline as BPolyline } from '../../../core'; 4 | 5 | class Polyline extends BaseOverlay { 6 | static IconSequence = IconSequence; 7 | 8 | getRealOverlay = () => new BPolyline(this.config, this.mapInstance); 9 | } 10 | 11 | export default Polyline; 12 | -------------------------------------------------------------------------------- /src/components/Overlay/Symbol.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Symbol as BSymbol, Util } from '../../core'; 4 | 5 | export default class Symbol extends PureComponent { 6 | config = {} 7 | 8 | static contextTypes = { 9 | centralizedUpdates: PropTypes.func, 10 | } 11 | 12 | static childContextTypes = { 13 | centralizedUpdates: PropTypes.func, 14 | } 15 | 16 | getChildContext() { 17 | return { 18 | centralizedUpdates: this.centralizedUpdates, 19 | }; 20 | } 21 | 22 | componentDidMount() { 23 | const { context } = this; 24 | context.centralizedUpdates({ 25 | name: 'symbol', 26 | data: this.getIcon(), 27 | }); 28 | } 29 | 30 | componentDidUpdate() { 31 | const { context } = this; 32 | context.centralizedUpdates({ 33 | name: 'symbol', 34 | data: this.getIcon(), 35 | }); 36 | } 37 | 38 | centralizedUpdates = ({ name, data }) => { 39 | const configName = Util.firstLowerCase(name); 40 | this.config[configName] = data; 41 | } 42 | 43 | getIcon = () => { 44 | const { children, ...resetProps } = this.props; 45 | this.config = { ...this.config, ...resetProps }; 46 | 47 | return new BSymbol({ ...this.config }); 48 | } 49 | 50 | render() { 51 | const { children } = this.props; 52 | return children || null; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/core/AutoComplete/index.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import OPTIONS from '../options/autoComplete'; 4 | 5 | const getAutocompleteOptions = (config, map) => ({ 6 | location: config.location || map, 7 | types: config.types, 8 | onSearchComplete: config.onSearchComplete, 9 | input: config.input, 10 | }); 11 | 12 | class AutoComplete { 13 | config = {} 14 | 15 | outOfRangeOpts = ['input', 'onSearchComplete'] 16 | 17 | hasOutOfRangeOpts = (opts = []) => opts.some(item => this.outOfRangeOpts.indexOf(item) > -1) 18 | 19 | constructor(config = {}, map) { 20 | this.config = { ...config }; 21 | this.init(config, map); 22 | } 23 | 24 | init = (config, map) => { 25 | this.checkInputExist(); 26 | const options = getAutocompleteOptions(config, map); 27 | this.instance = BMapUtil.BAutocomplete(options); 28 | this.processOptions(config); 29 | this.processEvents(config.events); 30 | } 31 | 32 | checkInputExist = () => { 33 | if (!document.querySelector(`#${this.config.input}`)) { 34 | throw Error(`[Input] ${this.config.input} is not exist when init autocomplete.`); 35 | } 36 | } 37 | 38 | repaint = (config) => { 39 | const diffConfig = Util.compareConfig(this.config, config) || {}; 40 | if (this.hasOutOfRangeOpts(Object.keys(diffConfig))) { 41 | this.destroy(); 42 | this.init({ ...this.config, ...diffConfig }); 43 | } else { 44 | this.processOptions(diffConfig); 45 | } 46 | this.config = { ...this.config, ...diffConfig }; 47 | this.processEvents(this.config.events); 48 | } 49 | 50 | destroy = () => { 51 | this.instance.dispose(); 52 | } 53 | 54 | processEvents = (events) => { 55 | Util.unbindEvents(this.instance); 56 | Util.bindEvents(this.instance, events); 57 | } 58 | 59 | processOptions(config) { 60 | if (config.value) { 61 | config.inputValue = config.value; 62 | } 63 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 64 | } 65 | } 66 | 67 | export default AutoComplete; 68 | -------------------------------------------------------------------------------- /src/core/Control/BaseControl.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 基础控件类 3 | * 用于统一处理重绘、销毁逻辑 4 | */ 5 | 6 | import Util from '../utils'; 7 | 8 | class BaseControl { 9 | instance = null; 10 | 11 | constructor(config, map) { 12 | this.map = map; 13 | this.repaint(config); 14 | } 15 | 16 | /** 17 | * 重绘 18 | */ 19 | repaint = (config) => { 20 | this.destroy(); 21 | config = { ...config, ...Util.convertControlOptions(config) }; 22 | this.init(config); 23 | Util.processControlVisible(this.instance, config.visible); 24 | } 25 | 26 | /** 27 | * 销毁 28 | */ 29 | destroy = () => { 30 | if (this.instance) { 31 | this.map.removeControl(this.instance); 32 | this.instance = null; 33 | } 34 | } 35 | } 36 | 37 | export default BaseControl; 38 | -------------------------------------------------------------------------------- /src/core/Control/CityList.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | import BaseControl from './BaseControl'; 3 | 4 | const processEvents = (config) => { 5 | const events = config.events || {}; 6 | const keys = Object.keys(events); 7 | 8 | keys.forEach((key) => { 9 | config[key] = events[key]; 10 | }); 11 | }; 12 | 13 | class CityList extends BaseControl { 14 | init(config = {}) { 15 | processEvents(config); 16 | this.instance = BMapUtil.BCityListControl(config); 17 | this.map.addControl(this.instance); 18 | } 19 | } 20 | 21 | export default CityList; 22 | -------------------------------------------------------------------------------- /src/core/Control/Copyright.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | import BaseControl from './BaseControl'; 3 | 4 | class Copyright extends BaseControl { 5 | init(config = {}) { 6 | const { copyrights = [] } = config; 7 | this.instance = BMapUtil.BCopyrightControl(config); 8 | copyrights.forEach((item) => { 9 | this.instance.addCopyright(item); 10 | }); 11 | this.map.addControl(this.instance); 12 | } 13 | } 14 | 15 | export default Copyright; 16 | -------------------------------------------------------------------------------- /src/core/Control/Custom.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | 4 | class CustomControl { 5 | constructor(config, map) { 6 | this.map = map; 7 | config = { ...config, ...Util.convertControlOptions(config) }; 8 | this.config = { ...config }; 9 | this.defaultAnchor = config.anchor; 10 | this.defaultOffset = config.offset; 11 | } 12 | 13 | config = {} 14 | 15 | processOptions = ({ anchor, offset, visible }) => { 16 | if (anchor) { 17 | this.setAnchor(anchor); 18 | } 19 | if (offset) { 20 | this.setOffset(offset); 21 | } 22 | if (!Util.isNil(visible)) { 23 | if (!visible) { 24 | this.hide(); 25 | } else { 26 | this.show(); 27 | } 28 | } 29 | } 30 | 31 | repaint = (config) => { 32 | config = { ...config, ...Util.convertControlOptions(config) }; 33 | const diffConfig = Util.compareConfig(this.config, config); 34 | this.processOptions(diffConfig); 35 | this.config = { ...this.config, ...diffConfig }; 36 | } 37 | 38 | destroy = () => { 39 | this.map.removeControl(this); 40 | } 41 | } 42 | 43 | // 异步加载时,BMap对象不存在,所以提供获得类方法,确保调用时BMap对象存在。 44 | const initCustomControl = (config, initialize, mapInstance) => { 45 | CustomControl.prototype = BMapUtil.BControl(); 46 | CustomControl.prototype.initialize = initialize; 47 | 48 | const control = new CustomControl(config, mapInstance); 49 | mapInstance.addControl(control); 50 | Util.processControlVisible(control, config.visible); 51 | return control; 52 | }; 53 | 54 | export default initCustomControl; 55 | -------------------------------------------------------------------------------- /src/core/Control/Geolocation.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import BaseControl from './BaseControl'; 4 | 5 | class Geolocation extends BaseControl { 6 | init(config = {}) { 7 | config.locationIcon = config.icon; 8 | delete config.icon; 9 | this.instance = BMapUtil.BGeolocationControl(config); 10 | this.map.addControl(this.instance); 11 | 12 | Util.bindEvents(this.instance, config.events); 13 | } 14 | } 15 | 16 | export default Geolocation; 17 | -------------------------------------------------------------------------------- /src/core/Control/MapType.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | import BaseControl from './BaseControl'; 3 | 4 | const getTypes = types => types && types.map(item => global[item] || item); 5 | 6 | const getMapTypeOptions = config => ({ 7 | anchor: config.anchor, 8 | offset: config.offset, 9 | type: global[config.type] || config.type, 10 | mapTypes: getTypes(config.mapTypes), 11 | }); 12 | 13 | class MapType extends BaseControl { 14 | init(config = {}) { 15 | const options = getMapTypeOptions(config); 16 | this.instance = BMapUtil.BMapTypeControl(options); 17 | this.map.addControl(this.instance); 18 | } 19 | } 20 | 21 | export default MapType; 22 | -------------------------------------------------------------------------------- /src/core/Control/Navigation.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | import BaseControl from './BaseControl'; 3 | 4 | const getNavigationControlOptions = config => ({ 5 | anchor: config.anchor, 6 | offset: config.offset, 7 | type: global[config.type] || config.type, 8 | showZoomInfo: config.showZoomInfo, 9 | }); 10 | 11 | class Navigation extends BaseControl { 12 | init(config = {}) { 13 | const options = getNavigationControlOptions(config); 14 | this.instance = BMapUtil.BNavigationControl(options); 15 | this.map.addControl(this.instance); 16 | } 17 | } 18 | 19 | export default Navigation; 20 | -------------------------------------------------------------------------------- /src/core/Control/OverviewMap.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import BaseControl from './BaseControl'; 4 | 5 | const getOverviewMapControlOptions = config => ({ 6 | anchor: config.anchor, 7 | offset: config.offset, 8 | size: config.size && BMapUtil.BSize({ ...config.size }), 9 | isOpen: config.isOpen, 10 | }); 11 | 12 | class OverviewMap extends BaseControl { 13 | init(config = {}) { 14 | const options = getOverviewMapControlOptions(config); 15 | this.instance = BMapUtil.BOverviewMapControl(options); 16 | this.map.addControl(this.instance); 17 | Util.bindEvents(this.instance, config.events); 18 | } 19 | } 20 | 21 | export default OverviewMap; 22 | -------------------------------------------------------------------------------- /src/core/Control/Panorama.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | import BaseControl from './BaseControl'; 3 | 4 | class Panorama extends BaseControl { 5 | init(config = {}) { 6 | this.instance = BMapUtil.BPanoramaControl(config); 7 | this.map.addControl(this.instance); 8 | } 9 | } 10 | 11 | export default Panorama; 12 | -------------------------------------------------------------------------------- /src/core/Control/Scale.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | import BaseControl from './BaseControl'; 3 | 4 | const processUnit = (unit, instance) => { 5 | if (unit) { 6 | unit = global[unit] || unit; 7 | instance.setUnit(unit); 8 | } 9 | }; 10 | 11 | class Scale extends BaseControl { 12 | init(config = {}) { 13 | this.instance = BMapUtil.BScaleControl(config); 14 | processUnit(config.unit, this.instance); 15 | this.map.addControl(this.instance); 16 | } 17 | } 18 | 19 | export default Scale; 20 | -------------------------------------------------------------------------------- /src/core/Layer/TileLayer.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | 3 | const getTileLayerOptions = config => ({ 4 | transparentPng: config.transparentPng, 5 | tileUrlTemplate: config.tileUrlTemplate, 6 | zIndex: config.zIndex, 7 | }); 8 | 9 | class TileLayer { 10 | constructor(config, map) { 11 | this.map = map; 12 | this.init(config); 13 | } 14 | 15 | init(config = {}) { 16 | const options = getTileLayerOptions(config); 17 | this.instance = BMapUtil.BTileLayer(options); 18 | if (config.getTilesUrl) { 19 | this.instance.getTilesUrl = config.getTilesUrl; 20 | } 21 | this.map.addTileLayer(this.instance); 22 | } 23 | 24 | repaint = (config = {}) => { 25 | this.destroy(); 26 | this.init(config); 27 | } 28 | 29 | destroy = () => { 30 | if (this.instance) { 31 | this.map.removeTileLayer(this.instance); 32 | } 33 | } 34 | } 35 | 36 | export default TileLayer; 37 | -------------------------------------------------------------------------------- /src/core/Layer/TrafficLayer.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | 3 | class TrafficLayer { 4 | constructor(config, map) { 5 | this.map = map; 6 | this.init(config); 7 | } 8 | 9 | init(config = {}) { 10 | const now = new Date(); 11 | if (!config.weekday) { 12 | config.weekday = now.getDay(); 13 | } 14 | 15 | if (!config.hour) { 16 | config.hour = now.getHours(); 17 | } 18 | 19 | this.instance = BMapUtil.BTrafficLayer({ 20 | predictDate: { 21 | weekday: config.weekday, 22 | hour: config.hour, 23 | }, 24 | }); 25 | 26 | this.map.addTileLayer(this.instance); 27 | } 28 | 29 | repaint = (config = {}) => { 30 | this.destroy(); 31 | this.init(config); 32 | } 33 | 34 | destroy = () => { 35 | if (this.instance) { 36 | this.map.removeTileLayer(this.instance); 37 | } 38 | } 39 | } 40 | 41 | export default TrafficLayer; 42 | -------------------------------------------------------------------------------- /src/core/Library/CurveLine.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | 3 | const getCurveLineOptions = config => ({ 4 | strokeColor: config.strokeColor, 5 | strokeWeight: config.strokeWeight, 6 | strokeOpacity: config.strokeOpacity, 7 | strokeStyle: config.strokeStyle, 8 | }); 9 | 10 | class CurveLine { 11 | constructor(config, map) { 12 | this.map = map; 13 | this.init(config); 14 | } 15 | 16 | init(config = {}) { 17 | const options = getCurveLineOptions(config); 18 | const points = this.processPoints(config.path); 19 | this.instance = new global.BMapLib.CurveLine(points, options); 20 | this.map.addOverlay(this.instance); 21 | this.processEditing(config.editing); 22 | } 23 | 24 | repaint = (config) => { 25 | if (this.instance) { 26 | this.instance.disableEditing(); 27 | this.destroy(); 28 | this.init(config); 29 | } 30 | } 31 | 32 | processPoints = points => points.map(point => Util.convert2BPoint(point)) 33 | 34 | processEditing = (editing) => { 35 | if (editing) { 36 | this.instance.enableEditing(); 37 | } else { 38 | this.instance.disableEditing(); 39 | } 40 | } 41 | 42 | destroy = () => { 43 | if (this.instance) { 44 | this.map.removeOverlay(this.instance); 45 | } 46 | } 47 | } 48 | 49 | export default CurveLine; 50 | -------------------------------------------------------------------------------- /src/core/Library/DistanceTool.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | 3 | const getDistanceToolOptions = config => ({ 4 | followText: config.followText || '单击确定地点,双击结束', 5 | unit: config.unit, 6 | lineColor: config.lineColor || 'red', 7 | lineStroke: config.lineStroke || 2, 8 | opacity: config.opacity, 9 | cursor: config.cursor, 10 | lineStyle: config.lineStyle, 11 | secIcon: config.secIcon, 12 | closeIcon: config.closeIcon, 13 | }); 14 | 15 | class DistanceTool { 16 | constructor(config, map) { 17 | this.map = map; 18 | this.init(config); 19 | } 20 | 21 | init(config = {}) { 22 | const options = getDistanceToolOptions(config); 23 | this.instance = new global.BMapLib.DistanceTool(this.map, options); 24 | this.processEvents(config.events); 25 | } 26 | 27 | processEvents = (events) => { 28 | Util.unbindEvents(this.instance); 29 | Util.bindEvents(this.instance, events); 30 | } 31 | 32 | destroy = () => { 33 | if (this.instance) { 34 | this.instance.close(); 35 | } 36 | } 37 | } 38 | 39 | export default DistanceTool; 40 | -------------------------------------------------------------------------------- /src/core/Library/HeatMap.js: -------------------------------------------------------------------------------- 1 | const getHeatMapOptions = config => ({ 2 | radius: config.radius, 3 | visible: config.visible, 4 | gradient: config.gradient, 5 | opacity: config.opacity, 6 | }); 7 | 8 | class HeatMap { 9 | constructor(config, map) { 10 | this.map = map; 11 | this.init(config); 12 | } 13 | 14 | init(config = {}) { 15 | const options = getHeatMapOptions(config); 16 | this.instance = new global.BMapLib.HeatmapOverlay(options); 17 | this.map.addOverlay(this.instance); 18 | this.setData(config); 19 | } 20 | 21 | repaint = (config) => { 22 | if (this.instance) { 23 | const options = getHeatMapOptions(config); 24 | this.instance.setOptions(options); 25 | this.setData(config); 26 | } 27 | } 28 | 29 | setData = (config) => { 30 | if (config.data) { 31 | this.instance.setDataSet({ 32 | max: config.max, 33 | data: config.data, 34 | }); 35 | } 36 | } 37 | 38 | destroy = () => { 39 | if (this.instance) { 40 | this.map.removeOverlay(this.instance); 41 | } 42 | } 43 | } 44 | 45 | export default HeatMap; 46 | -------------------------------------------------------------------------------- /src/core/Map/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 百度地图核心类 3 | * 4 | */ 5 | 6 | import Util from '../utils'; 7 | import BMapUtil from '../utils/map'; 8 | 9 | import OPTIONS from '../options/map'; 10 | 11 | /** 12 | * 地图初始化配置项所需属性 13 | */ 14 | const getMapOptions = config => ({ 15 | minZoom: config.minZoom, 16 | maxZoom: config.maxZoom, 17 | mapType: config.mapType && global[config.mapType], 18 | enableHighResolution: config.highResolution, 19 | enableAutoResize: config.autoResize, 20 | enableMapClick: config.mapClick, 21 | }); 22 | 23 | /** 24 | * 处理地图显示中心点 25 | */ 26 | const processCenter = (center) => { 27 | if (!Util.isNil(center) && !Util.isString(center)) { 28 | center = Util.convert2BPoint(center, 'center'); 29 | } 30 | 31 | return center; 32 | }; 33 | 34 | class Map { 35 | config = {} 36 | 37 | instance = null 38 | 39 | requiredProperty = ['zoom', 'center'] 40 | 41 | constructor(container, config) { 42 | const mapOptions = getMapOptions(config); 43 | this.instance = BMapUtil.BMap(container, mapOptions); 44 | this.config.center = processCenter(config.center); 45 | if (!config.zoom) { 46 | throw Error('Missing the required property `zoom`'); 47 | } 48 | this.instance.centerAndZoom(this.config.center, config.zoom); 49 | } 50 | 51 | /** 52 | * 设置右键菜单 53 | */ 54 | processContextMenu = (contextMenu) => { 55 | if (this.contextMenu) { 56 | this.instance.removeContextMenu(this.contextMenu); 57 | } 58 | this.contextMenu = contextMenu; 59 | if (contextMenu) { 60 | this.instance.addContextMenu(contextMenu); 61 | } 62 | } 63 | 64 | /** 65 | * 设置地图类型 66 | */ 67 | setMapType = (mapType) => { 68 | if (mapType && global[mapType]) { 69 | this.instance.setMapType(global[mapType]); 70 | } 71 | } 72 | 73 | /** 74 | * 处理地图相关事件 75 | * 绑定之前先统一解绑 76 | */ 77 | processEvents = (events) => { 78 | Util.unbindEvents(this.instance); 79 | Util.bindEvents(this.instance, events); 80 | } 81 | 82 | /** 83 | * 处理可以通过 setXXX 以及 enable、disableXXX 的方法 84 | */ 85 | processOptions = (config) => { 86 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 87 | Util.processBooleanOptions(this.instance, OPTIONS.BOOLEAN, config); 88 | } 89 | 90 | /** 91 | * 重绘 92 | */ 93 | repaint = (config) => { 94 | // 先进行一步转换,因为this.config.center为转换后的值,防止diff出现 bad case 95 | if (config.center) { 96 | config.center = processCenter(config.center); 97 | } 98 | const diffConfig = Util.compareConfig(this.config, config); 99 | 100 | this.processContextMenu(diffConfig.contextMenu); 101 | this.setMapType(diffConfig.mapType); 102 | this.processOptions(diffConfig); 103 | this.config = { 104 | ...this.config, 105 | ...diffConfig, 106 | }; 107 | this.processEvents(this.config.events); 108 | } 109 | } 110 | 111 | export default Map; 112 | -------------------------------------------------------------------------------- /src/core/Overlay/BaseOverlay.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | 3 | class BaseOverlay { 4 | config = {} 5 | 6 | outOfRangeOpts = [] 7 | 8 | constructor(config, map) { 9 | this.map = map; 10 | this.config = { ...config }; 11 | this.init(config); 12 | this.processEvents(config.events); 13 | } 14 | 15 | hasOutOfRangeOpts = (opts = []) => opts.some(item => this.outOfRangeOpts.indexOf(item) > -1) 16 | 17 | processEvents = (events) => { 18 | Util.unbindEvents(this.instance); 19 | Util.bindEvents(this.instance, events); 20 | } 21 | 22 | repaint = (config) => { 23 | const diffConfig = Util.compareConfig(this.config, config) || {}; 24 | 25 | if (this.hasOutOfRangeOpts(Object.keys(diffConfig))) { 26 | this.destroy(); 27 | this.init({ ...this.config, ...diffConfig }); 28 | } else { 29 | this.processOptions(diffConfig); 30 | } 31 | this.config = { ...this.config, ...diffConfig }; 32 | this.processEvents(this.config.events); 33 | } 34 | 35 | destroy = () => { 36 | this.map.removeOverlay(this.instance); 37 | } 38 | } 39 | 40 | export default BaseOverlay; 41 | -------------------------------------------------------------------------------- /src/core/Overlay/Circle.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import OPTIONS from '../options/circle'; 4 | import BaseOverlay from './BaseOverlay'; 5 | 6 | const getCircleOptions = config => ({ 7 | strokeColor: config.strokeColor, 8 | fillColor: config.fillColor, 9 | strokeWeight: config.strokeWeight, 10 | strokeOpacity: config.strokeOpacity, 11 | fillOpacity: config.fillOpacity, 12 | strokeStyle: config.strokeStyle, 13 | enableMassClear: config.massClear, 14 | enableClicking: config.clicking, 15 | }); 16 | 17 | class Circle extends BaseOverlay { 18 | outOfRangeOpts = ['clicking'] 19 | 20 | init(config = {}) { 21 | const options = getCircleOptions(config); 22 | const center = Util.convert2BPoint(config.center); 23 | this.instance = BMapUtil.BCircle(center, config.radius, options); 24 | this.map.addOverlay(this.instance); 25 | this.processOptions(config); 26 | } 27 | 28 | processOptions(config) { 29 | if (config.center) { 30 | config.center = Util.convert2BPoint(config.center); 31 | } 32 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 33 | Util.processBooleanOptions(this.instance, OPTIONS.BOOLEAN, config); 34 | } 35 | } 36 | 37 | export default Circle; 38 | -------------------------------------------------------------------------------- /src/core/Overlay/Custom.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | 4 | class CustomOverlay { 5 | constructor(config, map) { 6 | this.config = { ...config }; 7 | this.map = map; 8 | this.processOptions(config); 9 | } 10 | 11 | config = {} 12 | 13 | processOptions = ({ visible }) => { 14 | if (!Util.isNil(visible)) { 15 | if (!visible) { 16 | this.hide(); 17 | } else { 18 | this.show(); 19 | } 20 | } 21 | } 22 | 23 | repaint = (config) => { 24 | const diffConfig = Util.compareConfig(this.config, config); 25 | this.processOptions(diffConfig); 26 | this.config = { ...this.config, ...diffConfig }; 27 | } 28 | 29 | destroy = () => { 30 | this.map.removeOverlay(this); 31 | } 32 | } 33 | 34 | // 异步加载时,BMap对象不存在,所以提供获得类方法,确保调用时BMap对象存在。 35 | const initCustomOverlay = (config, initialize, draw, mapInstance) => { 36 | CustomOverlay.prototype = BMapUtil.BOverlay(); 37 | CustomOverlay.prototype.initialize = initialize; 38 | CustomOverlay.prototype.draw = draw; 39 | 40 | const overlay = new CustomOverlay(config, mapInstance); 41 | mapInstance.addOverlay(overlay); 42 | 43 | return overlay; 44 | }; 45 | 46 | export default initCustomOverlay; 47 | -------------------------------------------------------------------------------- /src/core/Overlay/GroundOverlay.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import OPTIONS from '../options/ground'; 4 | import BaseOverlay from './BaseOverlay'; 5 | 6 | const getGroundOverlayOptions = config => ({ 7 | opacity: config.opacity, 8 | imageURL: config.imageURL, 9 | displayOnMaxLevel: config.displayOnMaxLevel, 10 | displayOnMinLevel: config.displayOnMinLevel, 11 | }); 12 | 13 | class GroundOverlay extends BaseOverlay { 14 | init(config = {}) { 15 | const bounds = Util.convert2BBounds(config.bounds); 16 | const options = getGroundOverlayOptions(config); 17 | this.instance = BMapUtil.BGroundOverlay(bounds, options); 18 | this.map.addOverlay(this.instance); 19 | this.processOptions(config); 20 | } 21 | 22 | processOptions(config) { 23 | if (config.bounds) { 24 | config.bounds = Util.convert2BBounds(config.bounds); 25 | } 26 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 27 | } 28 | } 29 | 30 | export default GroundOverlay; 31 | -------------------------------------------------------------------------------- /src/core/Overlay/Icon.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | 4 | const getIconOptions = config => ({ 5 | anchor: config.anchor, 6 | imageOffset: config.imageOffset, 7 | imageSize: config.imageSize, 8 | infoWindowAnchor: config.infoWindowAnchor, 9 | printImageUrl: config.printImageUrl, 10 | }); 11 | 12 | const processConfig = (config) => { 13 | const { 14 | size, imageOffset, imageSize, infoWindowAnchor, 15 | } = config; 16 | const result = { ...config }; 17 | 18 | if (size) { 19 | result.size = Util.convert2BSize(size); 20 | } 21 | 22 | if (imageOffset) { 23 | result.imageOffset = Util.convert2BSize(imageOffset); 24 | } 25 | 26 | if (imageSize) { 27 | result.imageSize = Util.convert2BSize(imageSize); 28 | } 29 | 30 | if (infoWindowAnchor) { 31 | result.infoWindowAnchor = Util.convert2BSize(infoWindowAnchor); 32 | } 33 | return result; 34 | }; 35 | 36 | class Icon { 37 | constructor(config = {}) { 38 | const result = processConfig(config); 39 | const options = getIconOptions(result); 40 | const icon = BMapUtil.BIcon(result.imageUrl, result.size, options); 41 | return icon; 42 | } 43 | } 44 | 45 | export default Icon; 46 | -------------------------------------------------------------------------------- /src/core/Overlay/IconSequence.js: -------------------------------------------------------------------------------- 1 | import BMapUtil from '../utils/map'; 2 | 3 | class IconSequence { 4 | constructor(config = {}) { 5 | const { 6 | symbol, offset, repeat, fixedRotation, 7 | } = config; 8 | const icon = BMapUtil.BIconSequence(symbol, offset, repeat, fixedRotation); 9 | return icon; 10 | } 11 | } 12 | 13 | export default IconSequence; 14 | -------------------------------------------------------------------------------- /src/core/Overlay/InfoWindow.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | 4 | import OPTIONS from '../options/infoWindow'; 5 | import BaseOverlay from './BaseOverlay'; 6 | 7 | const getInfoWindowOptions = config => ({ 8 | width: config.width, 9 | height: config.height, 10 | maxWidth: config.maxWidth, 11 | offset: config.offset, 12 | title: config.title, 13 | enableAutoPan: config.autoPan, 14 | enableCloseOnClick: config.closeOnClick, 15 | enableMessage: config.displayMessage, 16 | message: config.message, 17 | }); 18 | 19 | class InfoWindow extends BaseOverlay { 20 | outOfRangeOpts = ['maxWidth', 'offset', 'displayMessage', 'message', 'point'] 21 | 22 | init(config = {}) { 23 | const options = getInfoWindowOptions(config); 24 | const point = Util.convert2BPoint(config.point); 25 | this.instance = BMapUtil.BInfoWindow(config.content, options); 26 | this.processVisible(config.visible, point); 27 | } 28 | 29 | processOptions(config) { 30 | const point = config.point || this.config.point; 31 | config.point = Util.convert2BPoint(point); 32 | 33 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 34 | Util.processBooleanOptions(this.instance, OPTIONS.BOOLEAN, config); 35 | this.processVisible(config.visible, config.point); 36 | } 37 | 38 | processVisible(visible = true, point) { 39 | if (this.instance.isOpen() && !visible) { 40 | this.map.closeInfoWindow(); 41 | } else if (!this.instance.isOpen() && visible) { 42 | this.map.openInfoWindow(this.instance, point); 43 | } 44 | } 45 | } 46 | 47 | export default InfoWindow; 48 | -------------------------------------------------------------------------------- /src/core/Overlay/Label.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import OPTIONS from '../options/label'; 4 | import BaseOverlay from './BaseOverlay'; 5 | 6 | const getLabelOptions = config => ({ 7 | offset: config.offset, 8 | position: config.position, 9 | enableMassClear: config.massClear, 10 | }); 11 | 12 | class Label extends BaseOverlay { 13 | outOfRangeOpts = [] 14 | 15 | init(config = {}) { 16 | if (config.position) { 17 | config.position = Util.convert2BPoint(config.position); 18 | } 19 | if (config.offset) { 20 | config.offset = Util.convert2BSize(config.offset); 21 | } 22 | const options = getLabelOptions(config); 23 | this.instance = BMapUtil.BLabel(config.content, options); 24 | this.map.addOverlay(this.instance); 25 | this.processOptions(config); 26 | } 27 | 28 | processOptions(config) { 29 | if (config.position) { 30 | config.position = Util.convert2BPoint(config.position); 31 | } 32 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 33 | Util.processBooleanOptions(this.instance, OPTIONS.BOOLEAN, config); 34 | } 35 | } 36 | 37 | export default Label; 38 | -------------------------------------------------------------------------------- /src/core/Overlay/Marker.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import OPTIONS from '../options/marker'; 4 | import BaseOverlay from './BaseOverlay'; 5 | 6 | const getMarkerOptions = config => ({ 7 | offset: config.offset, 8 | icon: config.icon, 9 | enableMassClear: config.massClear, 10 | enableClicking: config.clicking, 11 | raiseOnDrag: config.raiseOnDrag, 12 | draggingCursor: config.draggingCursor, 13 | rotation: config.rotation, 14 | shadow: config.shadow, 15 | title: config.title, 16 | }); 17 | 18 | class Marker extends BaseOverlay { 19 | outOfRangeOpts = ['clicking', 'raiseOnDrag', 'draggingCursor', 'shadow'] 20 | 21 | init(config = {}) { 22 | const options = getMarkerOptions(config); 23 | const point = Util.convert2BPoint(config.point); 24 | this.instance = BMapUtil.BMarker(point, options); 25 | this.map.addOverlay(this.instance); 26 | this.processOptions(config); 27 | this.setContextMenu(config.contextMenu); 28 | } 29 | 30 | processOptions(config) { 31 | const { animation } = config; 32 | if (animation) { 33 | config.animation = global[animation] || animation; 34 | } 35 | 36 | if (config.point) { 37 | config.position = Util.convert2BPoint(config.point); 38 | } else { 39 | delete config.position; 40 | } 41 | 42 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 43 | Util.processBooleanOptions(this.instance, OPTIONS.BOOLEAN, config); 44 | 45 | if (config.contextMenu) { 46 | this.setContextMenu(config.contextMenu); 47 | } 48 | } 49 | 50 | setContextMenu(contextMenu) { 51 | if (this.contextMenu) { 52 | this.instance.removeContextMenu(this.contextMenu); 53 | } 54 | this.contextMenu = contextMenu; 55 | if (contextMenu) { 56 | this.instance.addContextMenu(contextMenu); 57 | } 58 | } 59 | } 60 | 61 | export default Marker; 62 | -------------------------------------------------------------------------------- /src/core/Overlay/PointCollection.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | 4 | import BaseOverlay from './BaseOverlay'; 5 | 6 | const getPointCollectionOptions = config => ({ 7 | shape: config.shape ? global[config.shape] : null, 8 | size: config.size ? global[config.size] : null, 9 | color: config.color, 10 | }); 11 | 12 | const processPoints = (points = []) => points.map(item => Util.convert2BPoint(item)); 13 | 14 | class PointCollection extends BaseOverlay { 15 | init(config = {}) { 16 | const options = getPointCollectionOptions(config); 17 | const points = processPoints(config.path); 18 | this.instance = BMapUtil.BPointCollection(points, options); 19 | this.map.addOverlay(this.instance); 20 | } 21 | 22 | processOptions(config) { 23 | if (config.shape || config.size || config.color) { 24 | this.instance.setStyles({ 25 | shape: config.shape ? global[config.shape] : global[this.config.shape], 26 | size: config.shape ? global[config.size] : global[this.config.size], 27 | color: config.color || this.config.color, 28 | }); 29 | } 30 | 31 | if (config.path) { 32 | this.instance.setPoints(processPoints(config.path)); 33 | } 34 | } 35 | } 36 | 37 | export default PointCollection; 38 | -------------------------------------------------------------------------------- /src/core/Overlay/Polygon.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import OPTIONS from '../options/polygon'; 4 | import BaseOverlay from './BaseOverlay'; 5 | 6 | const getPolygonOptions = config => ({ 7 | strokeColor: config.strokeColor, 8 | fillColor: config.fillColor, 9 | strokeWeight: config.strokeWeight, 10 | strokeOpacity: config.strokeOpacity, 11 | fillOpacity: config.fillOpacity, 12 | strokeStyle: config.strokeStyle, 13 | enableMassClear: config.massClear, 14 | enableClicking: config.clicking, 15 | }); 16 | 17 | const processPoints = (points = []) => points.map(item => Util.convert2BPoint(item)); 18 | 19 | class Polygon extends BaseOverlay { 20 | outOfRangeOpts = ['clicking'] 21 | 22 | init(config = {}) { 23 | const options = getPolygonOptions(config); 24 | const points = processPoints(config.path); 25 | this.instance = BMapUtil.BPolygon(points, options); 26 | this.map.addOverlay(this.instance); 27 | this.processOptions(config); 28 | } 29 | 30 | processOptions(config) { 31 | if (config.path && Array.isArray(config.path)) { 32 | config.path = processPoints(config.path); 33 | } 34 | 35 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 36 | Util.processBooleanOptions(this.instance, OPTIONS.BOOLEAN, config); 37 | } 38 | } 39 | 40 | export default Polygon; 41 | -------------------------------------------------------------------------------- /src/core/Overlay/Polyline.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | import OPTIONS from '../options/polyline'; 4 | import BaseOverlay from './BaseOverlay'; 5 | 6 | const getPolylineOptions = config => ({ 7 | strokeColor: config.strokeColor, 8 | strokeWeight: config.strokeWeight, 9 | strokeOpacity: config.strokeOpacity, 10 | strokeStyle: config.strokeStyle, 11 | enableMassClear: config.massClear, 12 | enableClicking: config.clicking, 13 | icons: config.icons, 14 | }); 15 | 16 | const processPoints = (points = []) => points.map(item => Util.convert2BPoint(item)); 17 | 18 | class Polyline extends BaseOverlay { 19 | outOfRangeOpts = ['clicking'] 20 | 21 | init(config = {}) { 22 | const options = getPolylineOptions(config); 23 | const points = processPoints(config.path); 24 | this.instance = BMapUtil.BPolyline(points, options); 25 | this.map.addOverlay(this.instance); 26 | this.processOptions(config); 27 | } 28 | 29 | processOptions(config) { 30 | if (config.path && Array.isArray(config.path)) { 31 | config.path = processPoints(config.path); 32 | } 33 | 34 | Util.processSetOptions(this.instance, OPTIONS.SET, config); 35 | Util.processBooleanOptions(this.instance, OPTIONS.BOOLEAN, config); 36 | } 37 | } 38 | 39 | export default Polyline; 40 | -------------------------------------------------------------------------------- /src/core/Overlay/Symbol.js: -------------------------------------------------------------------------------- 1 | import Util from '../utils'; 2 | import BMapUtil from '../utils/map'; 3 | 4 | const getSymbolOptions = config => ({ 5 | anchor: config.anchor && Util.convert2BSize(config.anchor), 6 | fillColor: config.fillColor, 7 | fillOpacity: config.fillOpacity, 8 | scale: config.scale, 9 | rotation: config.rotation, 10 | strokeColor: config.strokeColor, 11 | strokeOpacity: config.strokeOpacity, 12 | strokeWeight: config.strokeWeight, 13 | }); 14 | 15 | const processPath = path => (global[path] ? global[path] : path); 16 | 17 | class Symbol { 18 | constructor(config = {}) { 19 | const options = getSymbolOptions(config); 20 | const path = processPath(config.path); 21 | return BMapUtil.BSymbol(path, options); 22 | } 23 | } 24 | 25 | export default Symbol; 26 | -------------------------------------------------------------------------------- /src/core/constants/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 标注的动画效果 3 | */ 4 | const ANIMATION = { 5 | DROP: 'BMAP_ANIMATION_DROP', 6 | BOUNCE: 'BMAP_ANIMATION_BOUNCE', 7 | }; 8 | 9 | /** 10 | * 内置的右键菜单图标 11 | */ 12 | const CONTEXT_MENU_ICON = { 13 | ZOOM_IN: 'BMAP_CONTEXT_MENU_ICON_ZOOMIN', 14 | ZOOM_OUT: 'BMAP_CONTEXT_MENU_ICON_ZOOMOUT', 15 | }; 16 | 17 | /** 18 | * 控件的定位 19 | */ 20 | const CONTROL_ANCHOR = { 21 | TOP_LEFT: 'BMAP_ANCHOR_TOP_LEFT', 22 | TOP_RIGHT: 'BMAP_ANCHOR_TOP_RIGHT', 23 | BOTTOM_LEFT: 'BMAP_ANCHOR_BOTTOM_LEFT', 24 | BOTTOM_RIGHT: 'BMAP_ANCHOR_BOTTOM_RIGHT', 25 | }; 26 | 27 | /** 28 | * 长度单位制 29 | */ 30 | const LENGTH_UNIT = { 31 | METRIC: 'BMAP_UNIT_METRIC', 32 | IMPERIAL: 'BMAP_UNIT_IMPERIAL', 33 | }; 34 | 35 | /** 36 | * 地图上所有覆盖物的容器集合 37 | */ 38 | const MAP_PANES = { 39 | FLOAT: 'floatPane', // 信息窗口所在容器 40 | FLOAT_SHADOW: 'floatShadow', // 信息窗口阴影所在容器 41 | LABEL: 'labelPane', // 文本标注所在容器 42 | MARKER: 'markerPane', // 标注图标所在容器 43 | MARKER_MOUSE: 'markerMouseTarget', // 标注点击区域所在容器 44 | MARKER_SHADOW: 'markerShadow', // 标注阴影所在容器 45 | MAP: 'mapPane', // 折现、多边形等矢量图形所在容器 46 | }; 47 | 48 | /** 49 | * 地图类型 50 | */ 51 | const MAP_TYPE = { 52 | NORMAL: 'BMAP_NORMAL_MAP', 53 | PERSPECTIVE: 'BMAP_PERSPECTIVE_MAP', 54 | SATELLITE: 'BMAP_SATELLITE_MAP', 55 | HYBRID: 'BMAP_HYBRID_MAP', 56 | }; 57 | 58 | /** 59 | * MapTypeControl的外观样式 60 | */ 61 | const MAP_TYPE_CONTROL_TYPE = { 62 | HORIZONTAL: 'BMAP_MAPTYPE_CONTROL_HORIZONTAL', 63 | DROPDOWN: 'BMAP_MAPTYPE_CONTROL_DROPDOWN', 64 | MAP: 'BMAP_MAPTYPE_CONTROL_MAP', 65 | }; 66 | 67 | /** 68 | * 平移缩放控件的类型 69 | */ 70 | const NAVIGATION_CONTROL_TYPE = { 71 | LARGE: 'BMAP_NAVIGATION_CONTROL_LARGE', 72 | SMALL: 'BMAP_NAVIGATION_CONTROL_SMALL', 73 | PAN: 'BMAP_NAVIGATION_CONTROL_PAN', 74 | ZOOM: 'BMAP_NAVIGATION_CONTROL_ZOOM', 75 | }; 76 | 77 | /** 78 | * 海量点预设的不同形状 79 | */ 80 | const SHAPE_TYPE = { 81 | CIRCLE: 'BMAP_POINT_SHAPE_CIRCLE', 82 | STAR: 'BMAP_POINT_SHAPE_STAR', 83 | SQUARE: 'BMAP_POINT_SHAPE_SQUARE', 84 | RHOMBUS: 'BMAP_POINT_SHAPE_RHOMBUS', 85 | WATERDROP: 'BMAP_POINT_SHAPE_WATERDROP', 86 | }; 87 | 88 | /** 89 | * 海量点预设的不同尺寸 90 | */ 91 | const SIZE_TYPE = { 92 | TINY: 'BMAP_POINT_SIZE_TINY', 93 | SMALLER: 'BMAP_POINT_SIZE_SMALLER', 94 | SMALL: 'BMAP_POINT_SIZE_SMALL', 95 | NORMAL: 'BMAP_POINT_SIZE_NORMAL', 96 | BIG: 'BMAP_POINT_SIZE_BIG', 97 | BIGGER: 'BMAP_POINT_SIZE_BIGGER', 98 | HUGE: 'BMAP_POINT_SIZE_HUGE', 99 | }; 100 | 101 | /** 102 | * 矢量图标类预设的图标样式 103 | */ 104 | const SYMBOL_SHAPE_TYPE = { 105 | CIRCLE: 'BMap_Symbol_SHAPE_CIRCLE', 106 | RECTANGLE: 'BMap_Symbol_SHAPE_RECTANGLE', 107 | RHOMBUS: 'BMap_Symbol_SHAPE_RHOMBUS', 108 | STAR: 'BMap_Symbol_SHAPE_STAR', 109 | BACKWARD_CLOSED_ARROW: 'BMap_Symbol_SHAPE_BACKWARD_CLOSED_ARROW', 110 | FORWARD_CLOSED_ARROW: 'BMap_Symbol_SHAPE_FORWARD_CLOSED_ARROW', 111 | BACKWARD_OPEN_ARROW: 'BMap_Symbol_SHAPE_BACKWARD_OPEN_ARROW', 112 | FORWARD_OPEN_ARROW: 'BMap_Symbol_SHAPE_FORWARD_OPEN_ARROW', 113 | POINT: 'BMap_Symbol_SHAPE_POINT', 114 | PLANE: 'BMap_Symbol_SHAPE_PLANE', 115 | CAMERA: 'BMap_Symbol_SHAPE_CAMERA', 116 | WARNING: 'BMap_Symbol_SHAPE_WARNING', 117 | SMILE: 'BMap_Symbol_SHAPE_SMILE', 118 | CLOCK: 'BMap_Symbol_SHAPE_CLOCK', 119 | }; 120 | 121 | /** 122 | * 驾车方案的策略配置 123 | */ 124 | const DRIVING_POLICY = { 125 | DEFAULT: 'BMAP_DRIVING_POLICY_DEFAULT', 126 | FIRST_HIGHWAYS: 'BMAP_DRIVING_POLICY_FIRST_HIGHWAYS', 127 | AVOID_HIGHWAYS: 'BMAP_DRIVING_POLICY_AVOID_HIGHWAYS', 128 | AVOID_CONGESTION: 'BMAP_DRIVING_POLICY_AVOID_CONGESTION', 129 | }; 130 | 131 | /** 132 | * 跨城公交换乘策略 133 | */ 134 | const INTERCITY_POLICY = { 135 | LEAST_TIME: 'BMAP_INTERCITY_POLICY_LEAST_TIME', 136 | EARLY_START: 'BMAP_INTERCITY_POLICY_EARLY_START', 137 | CHEAP_PRICE: 'BMAP_INTERCITY_POLICY_CHEAP_PRICE', 138 | }; 139 | 140 | /** 141 | * 市内公交方案换乘策略 142 | */ 143 | const TRANSIT_POLICY = { 144 | RECOMMEND: 'BMAP_TRANSIT_POLICY_RECOMMEND', 145 | LEAST_TIME: 'BMAP_TRANSIT_POLICY_LEAST_TIME', 146 | LEAST_TRANSFER: 'BMAP_TRANSIT_POLICY_LEAST_TRANSFER', 147 | LEAST_WALKING: 'BMAP_TRANSIT_POLICY_LEAST_WALKING', 148 | AVOID_SUBWAYS: 'BMAP_TRANSIT_POLICY_AVOID_SUBWAYS', 149 | FIRST_SUBWAYS: 'BMAP_TRANSIT_POLICY_FIRST_SUBWAYS', 150 | }; 151 | 152 | /** 153 | * 跨城交通方式策略 154 | */ 155 | const TRANSIT_TYPE_POLICY = { 156 | TRAIN: 'BMAP_TRANSIT_TYPE_POLICY_TRAIN', 157 | AIRPLANE: 'BMAP_TRANSIT_TYPE_POLICY_AIRPLANE', 158 | COACH: 'BMAP_TRANSIT_TYPE_POLICY_COACH', 159 | }; 160 | 161 | export default { 162 | ANIMATION, 163 | CONTEXT_MENU_ICON, 164 | CONTROL_ANCHOR, 165 | LENGTH_UNIT, 166 | MAP_PANES, 167 | MAP_TYPE, 168 | MAP_TYPE_CONTROL_TYPE, 169 | NAVIGATION_CONTROL_TYPE, 170 | SHAPE_TYPE, 171 | SIZE_TYPE, 172 | SYMBOL_SHAPE_TYPE, 173 | DRIVING_POLICY, 174 | INTERCITY_POLICY, 175 | TRANSIT_POLICY, 176 | TRANSIT_TYPE_POLICY, 177 | }; 178 | -------------------------------------------------------------------------------- /src/core/index.js: -------------------------------------------------------------------------------- 1 | import Map from './Map'; 2 | import BMapUtil from './utils/map'; 3 | import Util from './utils'; 4 | import initCustomControl from './Control/Custom'; 5 | import CityList from './Control/CityList'; 6 | import Copyright from './Control/Copyright'; 7 | import Navigation from './Control/Navigation'; 8 | import MapType from './Control/MapType'; 9 | import Scale from './Control/Scale'; 10 | import Panorama from './Control/Panorama'; 11 | import OverviewMap from './Control/OverviewMap'; 12 | import Geolocation from './Control/Geolocation'; 13 | import initCustomOverlay from './Overlay/Custom'; 14 | import Marker from './Overlay/Marker'; 15 | import InfoWindow from './Overlay/InfoWindow'; 16 | import Circle from './Overlay/Circle'; 17 | import Polygon from './Overlay/Polygon'; 18 | import Polyline from './Overlay/Polyline'; 19 | import Label from './Overlay/Label'; 20 | import GroundOverlay from './Overlay/GroundOverlay'; 21 | import PointCollection from './Overlay/PointCollection'; 22 | import Icon from './Overlay/Icon'; 23 | import IconSequence from './Overlay/IconSequence'; 24 | import Symbol from './Overlay/Symbol'; 25 | import AutoComplete from './AutoComplete'; 26 | import Constants from './constants'; 27 | import TileLayer from './Layer/TileLayer'; 28 | import TrafficLayer from './Layer/TrafficLayer'; 29 | import DistanceTool from './Library/DistanceTool'; 30 | import HeatMap from './Library/HeatMap'; 31 | import CurveLine from './Library/CurveLine'; 32 | 33 | export { 34 | BMapUtil, 35 | Util, 36 | initCustomControl, 37 | CityList, 38 | Copyright, 39 | Navigation, 40 | MapType, 41 | Scale, 42 | Panorama, 43 | OverviewMap, 44 | Geolocation, 45 | initCustomOverlay, 46 | Marker, 47 | Circle, 48 | Polygon, 49 | Label, 50 | InfoWindow, 51 | Polyline, 52 | Constants, 53 | AutoComplete, 54 | GroundOverlay, 55 | PointCollection, 56 | Icon, 57 | IconSequence, 58 | Symbol, 59 | TileLayer, 60 | TrafficLayer, 61 | DistanceTool, 62 | HeatMap, 63 | CurveLine, 64 | }; 65 | 66 | const addBMapScript = (ak, version = 3) => { 67 | if (!global.BMap && !global.mapLoader) { 68 | global.mapLoader = new Promise((resolve) => { 69 | const script = document.createElement('script'); 70 | script.src = `https://api.map.baidu.com/api?v=${version}.0&ak=${ak}&callback=initBMapCallBack`; 71 | document.head.appendChild(script); 72 | global.initBMapCallBack = () => { 73 | resolve(global.BMap); 74 | document.head.removeChild(script); 75 | delete global.mapLoader; 76 | delete global.initBMapCallBack; 77 | }; 78 | }); 79 | } 80 | return global.mapLoader; 81 | }; 82 | 83 | const initMap = async (container, config) => { 84 | await addBMapScript(config.ak, config.version); 85 | return new Map(container, config); 86 | }; 87 | 88 | export default initMap; 89 | -------------------------------------------------------------------------------- /src/core/options/autoComplete.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'types', 4 | 'location', 5 | 'inputValue', 6 | ], 7 | }; 8 | -------------------------------------------------------------------------------- /src/core/options/circle.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'center', 4 | 'radius', 5 | 'strokeColor', 6 | 'fillColor', 7 | 'strokeOpacity', 8 | 'fillOpacity', 9 | 'strokeWeight', 10 | 'strokeStyle', 11 | ], 12 | BOOLEAN: [ 13 | 'editing', 14 | 'massClear', 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /src/core/options/ground.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'bounds', 4 | 'opacity', 5 | 'imageURL', 6 | 'displayOnMinLevel', 7 | 'displayOnMaxLevel', 8 | ], 9 | }; 10 | -------------------------------------------------------------------------------- /src/core/options/infoWindow.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'width', 4 | 'height', 5 | 'title', 6 | 'content', 7 | 'maxContent', 8 | ], 9 | BOOLEAN: [ 10 | 'autoPan', 11 | 'closeOnClick', 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /src/core/options/label.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'style', 4 | 'content', 5 | 'position', 6 | 'offset', 7 | 'title', 8 | 'zIndex', 9 | ], 10 | BOOLEAN: [ 11 | 'massClear', 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /src/core/options/map.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'center', 4 | 'minZoom', 5 | 'maxZoom', 6 | 'defaultCursor', 7 | 'draggingCursor', 8 | 'mapStyle', 9 | 'mapStyleV2', 10 | 'zoom', 11 | ], 12 | BOOLEAN: [ 13 | 'dragging', 14 | 'scrollWheelZoom', 15 | 'doubleClickZoom', 16 | 'keyboard', 17 | 'inertialDragging', 18 | 'continuousZoom', 19 | 'pinchToZoom', 20 | 'autoResize', 21 | ], 22 | }; 23 | -------------------------------------------------------------------------------- /src/core/options/marker.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'icon', 4 | 'position', 5 | 'offset', 6 | 'label', 7 | 'title', 8 | 'zIndex', 9 | 'animation', 10 | 'rotation', 11 | ], 12 | BOOLEAN: [ 13 | 'massClear', 14 | 'dragging', 15 | ], 16 | }; 17 | -------------------------------------------------------------------------------- /src/core/options/polygon.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'path', 4 | 'strokeColor', 5 | 'fillColor', 6 | 'strokeOpacity', 7 | 'fillOpacity', 8 | 'strokeWeight', 9 | 'strokeStyle', 10 | ], 11 | BOOLEAN: [ 12 | 'editing', 13 | 'massClear', 14 | ], 15 | }; 16 | -------------------------------------------------------------------------------- /src/core/options/polyline.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'path', 4 | 'strokeColor', 5 | 'strokeOpacity', 6 | 'strokeWeight', 7 | 'strokeStyle', 8 | ], 9 | BOOLEAN: [ 10 | 'editing', 11 | 'massClear', 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /src/core/options/symbol.js: -------------------------------------------------------------------------------- 1 | export default { 2 | SET: [ 3 | 'path', 4 | 'anchor', 5 | 'rotation', 6 | 'scale', 7 | 'strokeWeight', 8 | 'strokeColor', 9 | 'strokeOpacity', 10 | 'fillColor', 11 | 'fillOpacity', 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /src/core/utils/index.js: -------------------------------------------------------------------------------- 1 | import isEqual from 'lodash.isequal'; 2 | import BMapUtil from './map'; 3 | 4 | const numberRe = /^[0-9]+.?[0-9]*/; 5 | 6 | /** 7 | * 是否为Point 8 | * @param {*} point 9 | */ 10 | const isPoint = point => numberRe.test(point.lng) && typeof numberRe.test(point.lat); 11 | 12 | /** 13 | * 是否为BMap.Point 14 | * @param {*} point 15 | */ 16 | const isBPoint = point => isPoint(point) && point.equals; 17 | 18 | /** 19 | * 是否为Size 20 | * @param {*} point 21 | */ 22 | const isSize = size => numberRe.test(size.width) && typeof numberRe.test(size.height); 23 | 24 | /** 25 | * 是否为BMap.Size 26 | * @param {*} size 27 | */ 28 | const isBSize = size => isSize(size) && size.equals; 29 | 30 | /** 31 | * 是否为矩形范围 32 | * @param {*} bounds 33 | */ 34 | const isBounds = bounds => numberRe.test(bounds.sw) && numberRe.test(bounds.ne); 35 | 36 | /** 37 | * 是否为BMap.Bounds 38 | * @param {*} bounds 39 | */ 40 | const isBBounds = bounds => isBounds(bounds) && bounds.equals; 41 | 42 | /** 43 | * 是否为空 44 | * @param {*} obj 45 | */ 46 | const isNil = obj => obj === undefined || obj === null; 47 | 48 | /** 49 | * 是否为字符串 50 | * @param {*} str 51 | */ 52 | const isString = str => typeof str === 'string'; 53 | 54 | /** 55 | * 首字母转为大写 56 | * @param {*} str 57 | */ 58 | const firstUpperCase = str => str.replace(/^\S/, s => s.toUpperCase()); 59 | 60 | /** 61 | * 首字母转为小写 62 | * @param {*} str 63 | */ 64 | const firstLowerCase = str => str.replace(/^\S/, s => s.toLowerCase()); 65 | 66 | /** 67 | * 获取行政区包含点集合 68 | * @param {*} name 行政区名称 69 | */ 70 | const getBoundary = name => new Promise((resolve, reject) => { 71 | const boundary = new global.BMap.Boundary(); 72 | 73 | boundary.get(name, (res) => { 74 | const count = res.boundaries.length; 75 | if (count === 0) { 76 | reject(); 77 | } 78 | const area = []; 79 | let allPoints = []; 80 | for (let i = 0; i < count; i += 1) { 81 | const arr = res.boundaries[i].split(';').map((item) => { 82 | const pointArr = item.split(','); 83 | return BMapUtil.BPoint({ lng: pointArr[0], lat: pointArr[1].trim() }); 84 | }); 85 | allPoints = allPoints.concat(arr); 86 | area.push(arr); 87 | } 88 | 89 | resolve({ 90 | area, 91 | points: allPoints, 92 | }); 93 | }); 94 | }); 95 | 96 | /** 97 | * 将传入值转换为 BMap.Point 98 | * @param {*} point 点对象 { lng, lat } 99 | * @param {*} propsName 用于错误提示 100 | */ 101 | const convert2BPoint = (point, propsName = 'point') => { 102 | if (isNil(point)) { 103 | throw Error(`Missing property \`${propsName}\``); 104 | } 105 | if (!isPoint(point)) { 106 | throw Error(`The \`${propsName}\` property should be a literal value \`{ lng, lat }\``); 107 | } else if (!isBPoint(point)) { 108 | point = BMapUtil.BPoint({ ...point }); 109 | } 110 | return point; 111 | }; 112 | 113 | /** 114 | * 将传入值转换为 BMap.Size 115 | * @param {*} point 矩形尺寸 { width, height } 116 | * @param {*} propsName 用于错误提示 117 | */ 118 | const convert2BSize = (size, propsName = 'size') => { 119 | if (isNil(size)) { 120 | throw Error(`Missing property \`${propsName}\``); 121 | } 122 | if (!isSize(size)) { 123 | throw Error(`The \`${propsName}\` property should be a literal value \`{ width, height }\``); 124 | } 125 | if (!isBSize(size)) { 126 | size = BMapUtil.BSize({ ...size }); 127 | } 128 | return size; 129 | }; 130 | 131 | /** 132 | * 将值转换为 BMap.Bounds 133 | * @param {*} point 矩形区域 { sw, ne } 134 | * @param {*} propsName 用于错误提示 135 | */ 136 | const convert2BBounds = (bounds, propsName = 'bounds') => { 137 | if (isNil(bounds)) { 138 | throw Error(`Missing property \`${propsName}\``); 139 | } 140 | if (!isBounds(bounds)) { 141 | throw Error(`The \`${propsName}\` property should be a literal value \`{ width, height }\``); 142 | } 143 | if (!isBBounds(bounds)) { 144 | bounds = BMapUtil.BBounds({ ...bounds }); 145 | } 146 | return bounds; 147 | }; 148 | 149 | /** 150 | * 为目标对象绑定事件 151 | * @param {*} target 目标对象 152 | * @param {*} events 事件集合 153 | */ 154 | const bindEvents = (target, events = {}) => { 155 | Object.keys(events).forEach((eventName) => { 156 | const eventType = typeof events[eventName]; 157 | if (eventType !== 'function') { 158 | console.warn(`Events's props value should be a function, but got '${eventType}'`); 159 | } 160 | const callback = (...args) => { 161 | if (eventType === 'function') { 162 | events[eventName].call(null, ...args); 163 | } 164 | }; 165 | target.events = target.events || {}; 166 | target.addEventListener(eventName, callback); 167 | target.events[`${eventName}`] = callback; 168 | }); 169 | }; 170 | 171 | /** 172 | * 将目标对象中已绑定事件移除 173 | * @param {*} target 174 | */ 175 | const unbindEvents = (target) => { 176 | const { events = {} } = target; 177 | Object.keys(events).forEach((eventName) => { 178 | const event = events[eventName]; 179 | target.removeEventListener(eventName, event); 180 | }); 181 | target.events = {}; 182 | }; 183 | 184 | /** 185 | * 处理 target.setXXX 方法 186 | * @param {*} target 目标对象 187 | * @param {*} options 属性集合 188 | * @param {*} values 值集合 189 | */ 190 | const processSetOptions = (target, options, values) => { 191 | options.forEach((key) => { 192 | if (values[key] || typeof values[key] === 'boolean') { 193 | const upKey = firstUpperCase(key); 194 | if (target[`set${upKey}`]) { 195 | target[`set${upKey}`](values[key]); 196 | } 197 | } 198 | }); 199 | }; 200 | 201 | /** 202 | * 处理 target.enableXXX 、 target.disableXXX 方法 203 | * @param {*} target 目标对象 204 | * @param {*} options 属性集合 205 | * @param {*} values 值集合 206 | */ 207 | const processBooleanOptions = (target, options, values) => { 208 | options.forEach((key) => { 209 | if (values[key] || typeof values[key] === 'boolean') { 210 | const upKey = firstUpperCase(key); 211 | const prefix = values[key] ? 'enable' : 'disable'; 212 | if (target[`${prefix}${upKey}`]) { 213 | target[`${prefix}${upKey}`](); 214 | } 215 | } 216 | }); 217 | }; 218 | 219 | /** 220 | * 比较新旧config,返回差异集合 221 | * @param {*} oldConfig 222 | * @param {*} newConfig 223 | */ 224 | const compareConfig = (oldConfig, newConfig) => { 225 | const result = { ...oldConfig, ...newConfig }; 226 | const keys = Object.keys(result); 227 | for (let i = 0, len = keys.length; i < len; i += 1) { 228 | const key = keys[i]; 229 | if (!isNil(oldConfig[key]) && isEqual(oldConfig[key], result[key])) { 230 | delete result[key]; 231 | } 232 | } 233 | return result; 234 | }; 235 | 236 | /** 237 | * 转换Control配置项 238 | * @param {*} param0 239 | */ 240 | const convertControlOptions = ({ anchor, offset }) => { 241 | const result = {}; 242 | 243 | if (anchor) { 244 | result.anchor = !isNil(global[anchor]) ? global[anchor] : anchor; 245 | } 246 | 247 | if (offset) { 248 | result.offset = convert2BSize(offset, 'offset'); 249 | } 250 | return result; 251 | }; 252 | 253 | /** 254 | * 处理Control显示隐藏 255 | * @param {*} target 256 | * @param {*} visible 257 | */ 258 | const processControlVisible = (target, visible) => { 259 | if (!isNil(target) && !isNil(visible)) { 260 | return visible ? target.show() : target.hide(); 261 | } 262 | return null; 263 | }; 264 | 265 | const libScriptsMap = {}; 266 | /** 267 | * 同步请求第三方script 268 | * @param {*} src script链接 269 | * 270 | * 此处保证每个script在整个文档流中有且只有一个,不重复添加 271 | */ 272 | const syncScript = (src) => { 273 | let scriptLoader = libScriptsMap[src]; 274 | if (!scriptLoader) { 275 | // eslint-disable-next-line no-multi-assign 276 | libScriptsMap[src] = scriptLoader = new Promise((resolved) => { 277 | const script = document.createElement('script'); 278 | script.src = src; 279 | // eslint-disable-next-line no-multi-assign 280 | script.onload = script.onreadystatechange = function loaded() { 281 | // for IE 282 | if (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') { 283 | resolved(); 284 | } 285 | }; 286 | document.head.appendChild(script); 287 | }); 288 | } 289 | 290 | return scriptLoader; 291 | }; 292 | 293 | export default { 294 | syncScript, 295 | isPoint, 296 | isBPoint, 297 | isSize, 298 | isBSize, 299 | isBounds, 300 | isBBounds, 301 | isNil, 302 | isString, 303 | getBoundary, 304 | convert2BPoint, 305 | convert2BSize, 306 | convert2BBounds, 307 | bindEvents, 308 | unbindEvents, 309 | processSetOptions, 310 | processBooleanOptions, 311 | compareConfig, 312 | firstLowerCase, 313 | convertControlOptions, 314 | processControlVisible, 315 | }; 316 | -------------------------------------------------------------------------------- /src/core/utils/map.js: -------------------------------------------------------------------------------- 1 | const BMapUtil = { 2 | BMap(container, opts) { 3 | return new global.BMap.Map(container, opts); 4 | }, 5 | BPoint({ lng, lat }) { 6 | return new global.BMap.Point(lng, lat); 7 | }, 8 | BSize({ width, height }) { 9 | return new global.BMap.Size(Number(width), Number(height)); 10 | }, 11 | BPixel({ x, y }) { 12 | return new global.BMap.Pixel(x, y); 13 | }, 14 | BBounds({ sw, ne }) { 15 | const swPoint = BMapUtil.BPoint(sw); 16 | const nePoint = BMapUtil.BPoint(ne); 17 | 18 | return new global.BMap.Bounds(swPoint, nePoint); 19 | }, 20 | BMenuItem(text, callback, opts) { 21 | return new global.BMap.MenuItem(text, callback, opts); 22 | }, 23 | BContextMenu(subMenus = []) { 24 | const contextMenu = new global.BMap.ContextMenu(); 25 | subMenus.forEach((item) => { 26 | contextMenu.addItem(item); 27 | if (item.separator) { 28 | contextMenu.addSeparator(); 29 | } 30 | }); 31 | return contextMenu; 32 | }, 33 | BIcon(url, size, opts) { 34 | return new global.BMap.Icon(url, size, opts); 35 | }, 36 | BIconSequence(symbol, offset, repeat, fixedRotation) { 37 | return new global.BMap.IconSequence(symbol, offset, repeat, fixedRotation); 38 | }, 39 | BControl() { 40 | return new global.BMap.Control(); 41 | }, 42 | BCityListControl(opts) { 43 | return new global.BMap.CityListControl(opts); 44 | }, 45 | BCopyrightControl(opts) { 46 | return new global.BMap.CopyrightControl(opts); 47 | }, 48 | BNavigationControl(opts) { 49 | return new global.BMap.NavigationControl(opts); 50 | }, 51 | BMapTypeControl(opts) { 52 | return new global.BMap.MapTypeControl(opts); 53 | }, 54 | BScaleControl(opts) { 55 | return new global.BMap.ScaleControl(opts); 56 | }, 57 | BPanoramaControl(opts) { 58 | return new global.BMap.PanoramaControl(opts); 59 | }, 60 | BOverviewMapControl(opts) { 61 | return new global.BMap.OverviewMapControl(opts); 62 | }, 63 | BGeolocationControl(opts) { 64 | return new global.BMap.GeolocationControl(opts); 65 | }, 66 | BOverlay() { 67 | return new global.BMap.Overlay(); 68 | }, 69 | BMarker(point, opts) { 70 | return new global.BMap.Marker(point, opts); 71 | }, 72 | BLabel(content, opts) { 73 | return new global.BMap.Label(content, opts); 74 | }, 75 | BCircle(center, radius, opts) { 76 | return new global.BMap.Circle(center, radius, opts); 77 | }, 78 | BPolyline(points, opts) { 79 | return new global.BMap.Polyline(points, opts); 80 | }, 81 | BInfoWindow(content, opts) { 82 | return new global.BMap.InfoWindow(content, opts); 83 | }, 84 | BPolygon(points, opts) { 85 | return new global.BMap.Polygon(points, opts); 86 | }, 87 | BGroundOverlay(bounds, opts) { 88 | return new global.BMap.GroundOverlay(bounds, opts); 89 | }, 90 | BPointCollection(points, opts) { 91 | return new global.BMap.PointCollection(points, opts); 92 | }, 93 | BAutocomplete(opts) { 94 | return new global.BMap.Autocomplete(opts); 95 | }, 96 | BSymbol(path, opts) { 97 | return new global.BMap.Symbol(path, opts); 98 | }, 99 | BTileLayer(opts) { 100 | return new global.BMap.TileLayer(opts); 101 | }, 102 | BTrafficLayer(opts) { 103 | return new global.BMap.TrafficLayer(opts); 104 | }, 105 | BLocalSearch(location, opts) { 106 | return new global.BMap.LocalSearch(location, opts); 107 | }, 108 | BGeolocation() { 109 | return new global.BMap.Geolocation(); 110 | }, 111 | BConvertor() { 112 | return new global.BMap.Convertor(); 113 | }, 114 | BTransitRoute(location, opts) { 115 | return new global.BMap.TransitRoute(location, opts); 116 | }, 117 | BWalkingRoute(location, opts) { 118 | return new global.BMap.WalkingRoute(location, opts); 119 | }, 120 | BRidingRoute(location, opts) { 121 | return new global.BMap.RidingRoute(location, opts); 122 | }, 123 | BDrivingRoute(location, opts) { 124 | return new global.BMap.DrivingRoute(location, opts); 125 | }, 126 | /** 127 | * 根据关键字查询位置信息 128 | * @param {*} keyword 关键字 129 | * @param {*} location 定位信息[map实例/string/point] 130 | */ 131 | search(keyword, location) { 132 | return new Promise((resolve) => { 133 | const local = BMapUtil.BLocalSearch(location, { 134 | onSearchComplete(result) { 135 | const list = []; 136 | for (let i = 0, len = result.getCurrentNumPois(); i < len - 1; i += 1) { 137 | list.push(result.getPoi(i)); 138 | } 139 | resolve(result); 140 | }, 141 | }); 142 | local.search(keyword); 143 | }); 144 | }, 145 | 146 | /** 147 | * 获取当前位置信息 148 | */ 149 | getCurrentPosition() { 150 | return new Promise((resolve, reject) => { 151 | const geo = BMapUtil.BGeolocation(); 152 | geo.getCurrentPosition((result) => { 153 | const status = geo.getStatus(); 154 | if (status === global.BMAP_STATUS_SUCCESS) { 155 | resolve(result); 156 | } else { 157 | reject(status); 158 | } 159 | }); 160 | }); 161 | }, 162 | 163 | /** 164 | * 对指定的地址进行解析,返回坐标点 165 | * @param {*} address 166 | * @param {*} city 167 | */ 168 | getPoint(address, city) { 169 | return new Promise((resolve, reject) => { 170 | const geo = new global.BMap.Geocoder(); 171 | geo.getPoint(address, (point) => { 172 | if (point) { 173 | resolve(point); 174 | } else { 175 | reject(); 176 | } 177 | }, city); 178 | }); 179 | }, 180 | 181 | /** 182 | * 对指定坐标点解析,返回地址信息 183 | * @param {*} point 184 | */ 185 | getLocation(point) { 186 | return new Promise((resolve, reject) => { 187 | const geo = new global.BMap.Geocoder(); 188 | // change the point to bpoint 189 | if (point.lng && point.lat) { 190 | point = BMapUtil.BPoint(point); 191 | } 192 | geo.getLocation(point, (result) => { 193 | if (result) { 194 | resolve(result); 195 | } else { 196 | reject(); 197 | } 198 | }); 199 | }); 200 | }, 201 | }; 202 | 203 | export default BMapUtil; 204 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 基础类 3 | */ 4 | export { default as Base } from './components/Base'; 5 | 6 | /** 7 | * 基础组件 8 | */ 9 | export { default as Map } from './components/Map'; 10 | export { default as CustomControl } from './components/Control/Custom'; 11 | export { default as CustomOverlay } from './components/Overlay/Custom'; 12 | export { default as AutoComplete } from './components/AutoComplete'; 13 | 14 | /** 15 | * 常用控件 16 | */ 17 | export { default as Navigation } from './components/Control/Navigation'; 18 | export { default as OverviewMap } from './components/Control/OverviewMap'; 19 | export { default as Scale } from './components/Control/Scale'; 20 | export { default as MapType } from './components/Control/MapType'; 21 | export { default as CopyrightControl } from './components/Control/CopyrightControl'; 22 | export { default as Geolocation } from './components/Control/Geolocation'; 23 | export { default as Panorama } from './components/Control/Panorama'; 24 | export { default as CityList } from './components/Control/CityList'; 25 | 26 | /** 27 | * 常用覆盖物 28 | */ 29 | export { default as Marker } from './components/Overlay/Marker'; 30 | export { default as Label } from './components/Overlay/Label'; 31 | export { default as Polyline } from './components/Overlay/Polyline'; 32 | export { default as Polygon } from './components/Overlay/Polygon'; 33 | export { default as Circle } from './components/Overlay/Circle'; 34 | export { default as InfoWindow } from './components/Overlay/InfoWindow'; 35 | export { default as Ground } from './components/Overlay/Ground'; 36 | export { default as PointCollection } from './components/Overlay/PointCollection'; 37 | export { default as Boundary } from './components/Overlay/Boundary'; 38 | 39 | /** 40 | * 地图图层 41 | */ 42 | export { default as TileLayer } from './components/Layer/TileLayer'; 43 | export { default as TrafficLayer } from './components/Layer/TrafficLayer'; 44 | 45 | /** 46 | * 第三方开源库 47 | */ 48 | export { default as DistanceTool } from './components/Library/DistanceTool'; 49 | export { default as HeatMap } from './components/Library/HeatMap'; 50 | export { default as CurveLine } from './components/Library/CurveLine'; 51 | 52 | export { default as Constants } from './core/constants'; 53 | export { default as BMapUtil } from './core/utils/map'; 54 | --------------------------------------------------------------------------------