diff --git a/.storybook/addons.ts b/.storybook/addons.ts index fa8ed5f333..518ae7e9ee 100644 --- a/.storybook/addons.ts +++ b/.storybook/addons.ts @@ -1,3 +1,3 @@ // import '@storybook/addon-actions/register'; -import '@storybook/addon-notes/register'; -import '@storybook/addon-storysource/register'; +// import '@storybook/addon-notes/register'; +// import '@storybook/addon-storysource/register'; diff --git a/.storybook/config.ts b/.storybook/config.ts index 57f82de959..8d0e91a35c 100644 --- a/.storybook/config.ts +++ b/.storybook/config.ts @@ -1,13 +1,12 @@ // tslint:disable-next-line:no-submodule-imports import '!style-loader!css-loader!sass-loader!./iframe.scss'; -// import '@storybook/addon-console'; import { addParameters, configure } from '@storybook/react'; import { create } from '@storybook/theming'; addParameters({ options: { isFullscreen: false, - showAddonsPanel: true, + showAddonsPanel: false, showSearchBox: false, panelPosition: 'bottom', hierarchySeparator: /\./, diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js index 2d3b00e6e0..a6d68c08d1 100644 --- a/.storybook/webpack.config.js +++ b/.storybook/webpack.config.js @@ -20,12 +20,12 @@ module.exports = ({ config }) => { config.module.rules.push({ test: /\.stories\.tsx?$/, - loaders: [ - { - loader: require.resolve('@storybook/addon-storysource/loader'), - options: { parser: 'typescript' }, - }, - ], + // loaders: [ + // { + // loader: require.resolve('@storybook/addon-storysource/loader'), + // options: { parser: 'typescript' }, + // }, + // ], enforce: 'pre', },{ test: /\.stories\.css?$/, diff --git a/docs/api/layer/line_layer/arc.zh.md b/docs/api/layer/line_layer/arc.zh.md index c30e60d7b4..fc32fe1c10 100644 --- a/docs/api/layer/line_layer/arc.zh.md +++ b/docs/api/layer/line_layer/arc.zh.md @@ -3,3 +3,50 @@ title: 弧线图 order: 1 --- 将两个点的连线绘制成弧形,绘制的弧线可以是贝塞尔曲线,大圆航线,通常用来表示两种地理事物关系和联系,或者人口迁移,物流起点目的地等 + +## 使用 + +### 数据 +绘制弧线只需提供起始点坐标即可 + +```javascript + source(data, { + parser: { + type: 'csv', + x: 'lng1', + y: 'lat1', + x1: 'lng2', + y1: 'lat2' + } + }) +``` + +### shape + +弧线支持两种弧线算法 + +- arc 绘制弧线 通过贝塞尔曲线算法技术弧线 +- greatcircle 大圆航线,地图两个点的最近距离不是两个点连线,而是大圆航线 +- arc3d 3d 弧线地图 3D 视角 + + +### 示例代码 + +```javascript +const layer = new LineLayer({}) + .source(data, { + parser: { + type: 'csv', + x: 'lng1', + y: 'lat1', + x1: 'lng2', + y1: 'lat2' + } + }) + .size(1) + .shape('arc') + .color('#8C1EB2') + .style({ + opacity: 0.8, + }); +``` diff --git a/docs/api/layer/line_layer/path.zh.md b/docs/api/layer/line_layer/path.zh.md index c03f4c619b..7590d945f2 100644 --- a/docs/api/layer/line_layer/path.zh.md +++ b/docs/api/layer/line_layer/path.zh.md @@ -3,3 +3,22 @@ title: 路径图 order: 1 --- 用一组首尾不闭合的点坐标对来定位的线图层,通常用来表示轨迹,线路,道路等 + +## 使用 + +### shape +shape 设置成line即可绘制路线图 +- line + +### size +路径图线的size支持两个维度 + +- width 宽度 +- height 高度 + +```javascript + layer.size([2,10]) // 绘制宽度为2,高度为10的路径 + + layer.size('',[]) +``` + diff --git a/docs/api/layer/point_layer/bubble.zh.md b/docs/api/layer/point_layer/bubble.zh.md index c3f479e3c4..1c40c140d9 100644 --- a/docs/api/layer/point_layer/bubble.zh.md +++ b/docs/api/layer/point_layer/bubble.zh.md @@ -6,7 +6,15 @@ order: 1 ## 使用 -气泡图通过PointLayer对象实例化,shape 设置成 **circle** +气泡图通过PointLayer对象实例化, + +### shape + + 通常气泡图shape 设置为 **circle** + +### size + +气泡图大小,需要指定数据映射字段 ```javascript diff --git a/docs/api/layer/point_layer/dot.zh.md b/docs/api/layer/point_layer/dot.zh.md new file mode 100644 index 0000000000..be0809b75b --- /dev/null +++ b/docs/api/layer/point_layer/dot.zh.md @@ -0,0 +1,44 @@ +--- +title: 亮度图 +order: 3 +--- +亮度图又称点密度图,单位面积的内点的个数越多,亮度会越亮,亮度图一般用来表达海量点数据分布情况 + +## 使用 + +### shape + - dot 如果需要使用亮度图可以将shape设置为dot,或者不设置shape +### color + - 无权重 + 如果数据没有权重可以将颜色设置为常量,渲染时会自动进行颜色叠加,点越多颜色约亮 + - 有权重 + 为数据有权重可以设置一组同一色相不同亮度的色带。 + + +```javascript +const pointLayer = new PointLayer() + .source(data) + .size(2) + .shape('dot') + .color('h8', [ + '#0A3663', + '#1558AC', + '#3771D9', + '#4D89E5', + '#64A5D3', + '#72BED6', + '#83CED6', + '#A6E1E0', + '#B8EFE2', + '#D7F9F0' + ]) + .style({ + opacity: 1 + }); + + scene.addLayer(pointLayer); +``` + +## 相关demo + +[城市亮度图](../../../../examples/point/dot) diff --git a/docs/api/layer/point_layer/intensity.zh.md b/docs/api/layer/point_layer/intensity.zh.md deleted file mode 100644 index b1fd6d5b5e..0000000000 --- a/docs/api/layer/point_layer/intensity.zh.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: 亮度图 -order: 3 ---- -亮度图又层点密度图,在地理区域上绘制海量的点,地图上单位面积的点越多亮度越高 - - -##使用 - -### shape - -亮度图可以不设置 diff --git a/docs/api/layer/point_layer/marker.zh.md b/docs/api/layer/point_layer/marker.zh.md index 0c5cb40a40..fd22bcf63f 100644 --- a/docs/api/layer/point_layer/marker.zh.md +++ b/docs/api/layer/point_layer/marker.zh.md @@ -3,3 +3,7 @@ title: 自定义 Marker order: 7 --- 可自定义点符号,通过自定义dom实现地图标注,富文本、动态点状符号都可用于地图上信息的标记。 + +## 使用 + +[Marker 文档](../../component) diff --git a/docs/api/layer/point_layer/scatter.zh.md b/docs/api/layer/point_layer/scatter.zh.md index 44043ab824..9ee1fac6de 100644 --- a/docs/api/layer/point_layer/scatter.zh.md +++ b/docs/api/layer/point_layer/scatter.zh.md @@ -19,10 +19,14 @@ order: 2 - rhombus - vesica -### 视觉通道设置 +散点图shape 一般设置成常量 -shape、size 设置成常量 -color 可以设置根据数据映射 +### color + +color 可以根据数据的差异设置成不同颜色,表示数据的不同分类。 + +### size +散点图一般等大小的图形,size 一般设置成常量 ```javascript diff --git a/docs/api/layer/point_layer/symbol.zh.md b/docs/api/layer/point_layer/symbol.zh.md index d782bb42f9..5861234beb 100644 --- a/docs/api/layer/point_layer/symbol.zh.md +++ b/docs/api/layer/point_layer/symbol.zh.md @@ -43,3 +43,4 @@ new PointLayer() strokeWidth: 1 }) ``` +## 相关demo diff --git a/docs/api/map.en.md b/docs/api/map.en.md new file mode 100644 index 0000000000..01e1fad38a --- /dev/null +++ b/docs/api/map.en.md @@ -0,0 +1,107 @@ +--- +title: 地图 Map +order: 2 +--- + +# 简介 + +L7 专注数据可视化层数据表达,目前L7 还不支持独立的地图引擎,需要引入第三方引擎,目前支持 高德地图和 MapBox两种。 +L7 在内部解决了不同底图地图直接的差异,同时L7层面统一管理地图的操作方法。 + +## Map + +### 引入Map + +```javascropt + + import { GaodeMap } from '@antv/l7-maps'; + + import { Mapbox } from '@antv/l7-maps'; +``` + +### 实例化 + +⚠️ 使用地图申请地图token,L7 内部设置了默认token,仅供测试使用 + +#### 高德地图实例化 + +```javascript + + const L7AMap = new GaodeMap({ + pitch: 35.210526315789465, + style: 'dark', + center: [ 104.288144, 31.239692 ], + zoom: 4.4, + token:'xxxx - token' + }) + +``` + +#### Mapbox 地图实例化 + +```javascript +const scene = new Scene({ + id: 'map', + map: new Mapbox({ + style: 'dark', + center: [ 103.83735604457024, 1.360253881403068 ], + pitch: 4.00000000000001, + zoom: 10.210275860702593, + rotation: 19.313180925794313 + token:'xxxx - token' + }) +}); +``` + +### 传入外部实例 + +为了支持已有地图项目快速接入L7的能力,L7 提供传入地图实例的方法。如果你是新项目推荐使用Scene初始化地图 + +⚠️ scene id 参数需要地图的Map实例是同个容器。 + +⚠️ 传入地图实例需要自行引入相关地图的API + +#### 传入高德地图实例 + +```javascript + const map = new AMap.Map('map', { + viewMode: '3D', + resizeEnable: true, // 是否监控地图容器尺寸变化 + zoom: 11, // 初始化地图层级 + center: [116.397428, 39.90923], // 初始化地图中心点 + }); + const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + mapInstance: map, + }), + }); + +``` + +#### 传入Mapbox 地图实例 + +```javascript + + mapboxgl.accessToken = + 'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ'; + const map = new mapboxgl.Map({ + container: 'map', // container id + style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location + center: [-74.5, 40], // starting position [lng, lat] + zoom: 9, // starting zoom + }); + + const scene = new Scene({ + id: 'map', + map: new Mapbox({ + mapInstance: map, + }), + }); +``` + + + + + + diff --git a/docs/api/map.zh.md b/docs/api/map.zh.md new file mode 100644 index 0000000000..61def5da7c --- /dev/null +++ b/docs/api/map.zh.md @@ -0,0 +1,107 @@ +--- +title: 地图 Map +order: 2 +--- + +# 简介 + +L7 专注数据可视化层数据表达,目前L7 还不支持独立的地图引擎,需要引入第三方引擎,目前支持 高德地图和 MapBox两种。= +L7 在内部解决了不同底图地图直接的差异,同时L7层面统一管理地图的操作方法。 + +## Map + +### 引入Map + +```javascropt + + import { GaodeMap } from '@antv/l7-maps'; + + import { Mapbox } from '@antv/l7-maps'; +``` + +### 实例化 + +⚠️ 使用地图申请地图token,L7 内部设置了默认token,仅供测试使用 + +#### 高德地图实例化 + +```javascript + + const L7AMap = new GaodeMap({ + pitch: 35.210526315789465, + style: 'dark', + center: [ 104.288144, 31.239692 ], + zoom: 4.4, + token:'xxxx - token' + }) + +``` + +#### Mapbox 地图实例化 + +```javascript +const scene = new Scene({ + id: 'map', + map: new Mapbox({ + style: 'dark', + center: [ 103.83735604457024, 1.360253881403068 ], + pitch: 4.00000000000001, + zoom: 10.210275860702593, + rotation: 19.313180925794313 + token:'xxxx - token' + }) +}); +``` + +### 传入外部实例 + +为了支持已有地图项目快速接入L7的能力,L7 提供传入地图实例的方法。如果你是新项目推荐使用Scene初始化地图 + +⚠️ scene id 参数需要地图的Map实例是同个容器。 + +⚠️ 传入地图实例需要自行引入相关地图的API + +#### 传入高德地图实例 + +```javascript + const map = new AMap.Map('map', { + viewMode: '3D', + resizeEnable: true, // 是否监控地图容器尺寸变化 + zoom: 11, // 初始化地图层级 + center: [116.397428, 39.90923], // 初始化地图中心点 + }); + const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + mapInstance: map, + }), + }); + +``` + +#### 传入Mapbox 地图实例 + +```javascript + + mapboxgl.accessToken = + 'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ'; + const map = new mapboxgl.Map({ + container: 'map', // container id + style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location + center: [-74.5, 40], // starting position [lng, lat] + zoom: 9, // starting zoom + }); + + const scene = new Scene({ + id: 'map', + map: new Mapbox({ + mapInstance: map, + }), + }); +``` + + + + + + diff --git a/examples/point/dot/demo/meta.json b/examples/point/dot/demo/meta.json new file mode 100644 index 0000000000..998543128d --- /dev/null +++ b/examples/point/dot/demo/meta.json @@ -0,0 +1,19 @@ +{ + "title": { + "zh": "中文分类", + "en": "Category" + }, + "demos": [ + { + "filename": "normal2.js", + "title": "城市亮度图", + "screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*ypZCT6pqv84AAAAAAAAAAABkARQnAQ" + }, + { + "filename": "normal.js", + "title": "海量点", + "screenshot":"https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*xr8BQouXGvoAAAAAAAAAAABkARQnAQ" + } + + ] +} diff --git a/examples/point/scatter/demo/normal.js b/examples/point/dot/demo/normal.js similarity index 100% rename from examples/point/scatter/demo/normal.js rename to examples/point/dot/demo/normal.js diff --git a/examples/point/scatter/demo/normal2.js b/examples/point/dot/demo/normal2.js similarity index 100% rename from examples/point/scatter/demo/normal2.js rename to examples/point/dot/demo/normal2.js diff --git a/examples/point/dot/index.en.md b/examples/point/dot/index.en.md new file mode 100644 index 0000000000..e60275da5b --- /dev/null +++ b/examples/point/dot/index.en.md @@ -0,0 +1,4 @@ +--- +title: Dot Intensity +order: 1 +--- diff --git a/examples/point/dot/index.zh.md b/examples/point/dot/index.zh.md new file mode 100644 index 0000000000..b28d7a59de --- /dev/null +++ b/examples/point/dot/index.zh.md @@ -0,0 +1,4 @@ +--- +title: "亮度图" +order: 1 +--- diff --git a/examples/point/scatter/demo/meta.json b/examples/point/scatter/demo/meta.json index 998543128d..27d083e3d6 100644 --- a/examples/point/scatter/demo/meta.json +++ b/examples/point/scatter/demo/meta.json @@ -5,14 +5,10 @@ }, "demos": [ { - "filename": "normal2.js", - "title": "城市亮度图", - "screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*ypZCT6pqv84AAAAAAAAAAABkARQnAQ" - }, - { - "filename": "normal.js", - "title": "海量点", - "screenshot":"https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*xr8BQouXGvoAAAAAAAAAAABkARQnAQ" + "filename": "scatter.js", + "title": "散点图", + "screenshot":"https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*LnlmQ7sFWigAAAAAAAAAAABkARQnAQ" + } ] diff --git a/examples/point/scatter/demo/scatter.js b/examples/point/scatter/demo/scatter.js new file mode 100644 index 0000000000..f09afbfdce --- /dev/null +++ b/examples/point/scatter/demo/scatter.js @@ -0,0 +1,47 @@ +import { Scene, PointLayer } from '@antv/l7'; +import { GaodeMap } from '@antv/l7-maps'; + +const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + style: 'light', + center: [ -121.24357, 37.58264 ], + pitch: 0, + zoom: 6.45 + }) +}); + +fetch( + 'https://gw.alipayobjects.com/os/basement_prod/6c4bb5f2-850b-419d-afc4-e46032fc9f94.csv' +) + .then(res => res.text()) + .then(data => { + const pointLayer = new PointLayer({}) + .source(data, { + parser: { + type: 'csv', + x: 'Longitude', + y: 'Latitude' + } + }) + .shape('circle') + .size(4) + .color('Magnitude', [ + '#0A3663', + '#1558AC', + '#3771D9', + '#4D89E5', + '#64A5D3', + '#72BED6', + '#83CED6', + '#A6E1E0', + '#B8EFE2', + '#D7F9F0' + ]) + .style({ + opacity: 0.5, + strokeWidth: 0 + }); + + scene.addLayer(pointLayer); + }); diff --git a/examples/tutorial/map/demo/amapInstance.js b/examples/tutorial/map/demo/amapInstance.js new file mode 100644 index 0000000000..25ce7fd595 --- /dev/null +++ b/examples/tutorial/map/demo/amapInstance.js @@ -0,0 +1,14 @@ +import { Scene } from '@antv/l7'; +import { GaodeMap } from '@antv/l7-maps'; + +const map = new AMap.Map('container', { + resizeEnable: true, // 是否监控地图容器尺寸变化 + zoom: 11, // 初始化地图层级 + center: [ 116.397428, 39.90923 ] // 初始化地图中心点 +}); +new Scene({ + id: 'map', + map: new GaodeMap({ + mapInstance: map + }) +}); diff --git a/packages/core/src/services/config/warnInfo.ts b/packages/core/src/services/config/warnInfo.ts index ba879a7b7a..345a506278 100644 --- a/packages/core/src/services/config/warnInfo.ts +++ b/packages/core/src/services/config/warnInfo.ts @@ -1,10 +1,12 @@ export interface IWarnInfo { MapToken: string; + SDK: string; [key: string]: any; } const WarnInfo: IWarnInfo = { - MapToken: '您正在使用 Demo测试地图token,如果生成环境中使用去对应地图请注册Token', - SDK: 's', + MapToken: + '您正在使用 Demo测试地图token,如果生成环境中使用去对应地图请注册Token', + SDK: '请确认引入了mapbox-gl api且在L7之前引入', }; export default WarnInfo; diff --git a/packages/core/src/services/map/IMapService.ts b/packages/core/src/services/map/IMapService.ts index ba0cb37965..8491d24a10 100644 --- a/packages/core/src/services/map/IMapService.ts +++ b/packages/core/src/services/map/IMapService.ts @@ -66,11 +66,15 @@ export const MapServiceEvent = ['mapload']; /** * 地图初始化配置项 */ -export interface IMapConfig { +export interface IMapConfig { + /** + * 地图实例 + */ + mapInstance?: RawMap; /** * 容器 DOM id */ - id: string; + id: string | HTMLDivElement; /** * 地图 diff --git a/packages/core/src/services/scene/ISceneService.ts b/packages/core/src/services/scene/ISceneService.ts index 373238cf55..372aa824ef 100644 --- a/packages/core/src/services/scene/ISceneService.ts +++ b/packages/core/src/services/scene/ISceneService.ts @@ -9,6 +9,7 @@ export interface ISceneService { init(config: IMapConfig & IRenderConfig): void; addLayer(layer: ILayer): void; render(): void; + getSceneContainer(): HTMLDivElement; destroy(): void; } // scene 事件 diff --git a/packages/core/src/services/scene/SceneService.ts b/packages/core/src/services/scene/SceneService.ts index 5813ed1e3e..3ddfa9774d 100644 --- a/packages/core/src/services/scene/SceneService.ts +++ b/packages/core/src/services/scene/SceneService.ts @@ -184,7 +184,6 @@ export default class Scene extends EventEmitter implements ISceneService { } this.rendering = true; - // 首次初始化,或者地图的容器被强制销毁的需要重新初始化 if (!this.inited) { // 还未初始化完成需要等待 @@ -207,6 +206,10 @@ export default class Scene extends EventEmitter implements ISceneService { this.rendering = false; } + public getSceneContainer(): HTMLDivElement { + return this.$container as HTMLDivElement; + } + public destroy() { this.emit('destroy'); this.inited = false; diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index d70a1f20be..d6627c2875 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -437,12 +437,17 @@ export default class BaseLayer extends EventEmitter } public active(options: IActiveOption) { - this.updateLayerConfig({ - enableHighlight: isObject(options) ? true : options, - highlightColor: isObject(options) - ? options.color - : this.getLayerConfig().highlightColor, - }); + const activeOption: Partial = {}; + activeOption.enableHighlight = isObject(options) ? true : options; + if (isObject(options)) { + activeOption.enableHighlight = true; + if (options.color) { + activeOption.highlightColor = options.color; + } + } else { + activeOption.enableHighlight = !!options; + } + this.updateLayerConfig(activeOption); return this; } public setActive( diff --git a/packages/layers/src/plugins/DataSourcePlugin.ts b/packages/layers/src/plugins/DataSourcePlugin.ts index e99b486125..6de90f0b61 100644 --- a/packages/layers/src/plugins/DataSourcePlugin.ts +++ b/packages/layers/src/plugins/DataSourcePlugin.ts @@ -10,19 +10,24 @@ export default class DataSourcePlugin implements ILayerPlugin { layer.hooks.init.tap('DataSourcePlugin', () => { const { data, options } = layer.sourceOption; layer.setSource(new Source(data, options)); + this.updateClusterData(layer); }); // 检测数据是不否需要更新 layer.hooks.beforeRenderData.tap('DataSourcePlugin', (flag) => { - const source = layer.getSource(); - const cluster = source.cluster; - const { zoom = 0, maxZoom = 16 } = source.clusterOptions; - const newZoom = this.mapService.getZoom(); - if (cluster && Math.abs(zoom - newZoom) > 1 && maxZoom > zoom) { - source.updateClusterData(Math.floor(newZoom) + 1); - return true; - } - return false; + return this.updateClusterData(layer); }); } + + private updateClusterData(layer: ILayer): boolean { + const source = layer.getSource(); + const cluster = source.cluster; + const { zoom = 0, maxZoom = 16 } = source.clusterOptions; + const newZoom = this.mapService.getZoom(); + if (cluster && Math.abs(zoom - newZoom) > 1 && maxZoom > zoom) { + source.updateClusterData(Math.floor(newZoom)); + return true; + } + return false; + } } diff --git a/packages/layers/src/point/index.ts b/packages/layers/src/point/index.ts index 4215b9e774..300bc1bfb2 100644 --- a/packages/layers/src/point/index.ts +++ b/packages/layers/src/point/index.ts @@ -51,6 +51,9 @@ export default class PointLayer extends BaseLayer { return 'normal'; } else { const shape = item.shape; + if (shape === 'dot') { + return 'normal'; + } if (shape2d?.indexOf(shape as string) !== -1) { return 'fill'; } diff --git a/packages/maps/src/amap/index.ts b/packages/maps/src/amap/index.ts index 6b448b6a73..a88a5eadc3 100644 --- a/packages/maps/src/amap/index.ts +++ b/packages/maps/src/amap/index.ts @@ -228,28 +228,37 @@ export default class AMapService minZoom = 0, maxZoom = 18, token = AMAP_API_KEY, + mapInstance, ...rest } = this.config; // 高德地图创建独立的container; - // @ts-ignore - this.$mapContainer = this.creatAmapContainer(id); // tslint:disable-next-line:typedef await new Promise((resolve) => { const resolveMap = () => { - // @ts-ignore - this.map = new AMap.Map(this.$mapContainer, { - mapStyle: this.getMapStyle(style), - zooms: [minZoom, maxZoom], - viewMode: '3D', - ...rest, - }); - - // 监听地图相机事件 - this.map.on('camerachange', this.handleCameraChanged); - resolve(); + if (mapInstance) { + this.map = mapInstance as AMap.Map & IAMapInstance; + this.$mapContainer = this.map.getContainer(); + setTimeout(() => { + this.map.on('camerachange', this.handleCameraChanged); + resolve(); + }, 30); + } else { + this.$mapContainer = this.creatAmapContainer( + id as string | HTMLDivElement, + ); + // @ts-ignore + this.map = new AMap.Map(this.$mapContainer, { + mapStyle: this.getMapStyle(style), + zooms: [minZoom, maxZoom], + viewMode: '3D', + ...rest, + }); + // 监听地图相机事件 + this.map.on('camerachange', this.handleCameraChanged); + resolve(); + } }; - if (!document.getElementById(AMAP_SCRIPT_ID)) { // 异步加载高德地图 // @see https://lbs.amap.com/api/javascript-api/guide/abc/load @@ -257,7 +266,6 @@ export default class AMapService window.initAMap = (): void => { amapLoaded = true; resolveMap(); - if (pendingResolveQueue.length) { pendingResolveQueue.forEach((r) => r()); pendingResolveQueue = []; @@ -273,7 +281,7 @@ export default class AMapService $jsapi.src = url; document.head.appendChild($jsapi); } else { - if (amapLoaded) { + if (amapLoaded || mapInstance) { resolveMap(); } else { pendingResolveQueue.push(resolveMap); @@ -363,7 +371,6 @@ export default class AMapService $amapdiv.style.cssText += ` position: absolute; top: 0; - z-index:2; height: 100%; width: 100%; `; diff --git a/packages/maps/src/mapbox/index.ts b/packages/maps/src/mapbox/index.ts index f746028697..13952b6796 100644 --- a/packages/maps/src/mapbox/index.ts +++ b/packages/maps/src/mapbox/index.ts @@ -192,9 +192,9 @@ export default class MapboxService style = 'light', token = MAPBOX_API_KEY, rotation = 0, + mapInstance, ...rest } = this.config; - this.$mapContainer = document.getElementById(id); this.viewport = new Viewport(); @@ -210,14 +210,21 @@ export default class MapboxService if (token === MAPBOX_API_KEY && style !== 'blank') { this.logger.warn(this.configService.getSceneWarninfo('MapToken')); } - // @ts-ignore - this.map = new mapboxgl.Map({ - container: id, - style: this.getMapStyle(style), - attributionControl, - bearing: rotation, - ...rest, - }); + if (mapInstance) { + // @ts-ignore + this.map = mapInstance; + this.$mapContainer = this.map.getContainer(); + } else { + this.$mapContainer = this.creatAmapContainer(id); + // @ts-ignore + this.map = new mapboxgl.Map({ + container: id, + style: this.getMapStyle(style), + attributionControl, + bearing: rotation, + ...rest, + }); + } this.map.on('load', this.handleCameraChanged); this.map.on('move', this.handleCameraChanged); @@ -276,6 +283,14 @@ export default class MapboxService this.cameraChangedCallback(this.viewport); }; + private creatAmapContainer(id: string | HTMLDivElement) { + let $wrapper = id as HTMLDivElement; + if (typeof id === 'string') { + $wrapper = document.getElementById(id) as HTMLDivElement; + } + return $wrapper; + } + private removeLogoControl(): void { // @ts-ignore const controls = this.map._controls as IControl[]; diff --git a/packages/scene/src/index.ts b/packages/scene/src/index.ts index 62c49a8b80..305b57bf52 100644 --- a/packages/scene/src/index.ts +++ b/packages/scene/src/index.ts @@ -106,6 +106,7 @@ class Scene public addLayer(layer: ILayer): void { // 为当前图层创建一个容器 + // TODO: 初始化的时候设置 容器 const layerContainer = createLayerContainer(this.container); layer.setContainer(layerContainer); this.sceneService.addLayer(layer); diff --git a/stories/Layers/components/Arcline.tsx b/stories/Layers/components/Arcline.tsx index e81ae3ca1a..a746fbcc8c 100644 --- a/stories/Layers/components/Arcline.tsx +++ b/stories/Layers/components/Arcline.tsx @@ -23,6 +23,7 @@ export default class ArcLineDemo extends React.Component { zoom: 2, }), }); + this.scene = scene; const lineLayer = new LineLayer({ enablePicking: true, enableHighlight: true, diff --git a/stories/Layers/components/Point.tsx b/stories/Layers/components/Point.tsx index 10ce3b4e0f..9c4e9f7cc5 100644 --- a/stories/Layers/components/Point.tsx +++ b/stories/Layers/components/Point.tsx @@ -26,23 +26,25 @@ export default class Point3D extends React.Component { zoom: 3, }), }); - this.scene = scene; - - const pointLayer = new PointLayer({}) - .source(pointsData, { - cluster: true, - }) - .shape('circle') - .scale('point_count', { - type: 'quantile', - }) - .size('point_count', [5, 10, 15, 20, 25]) - .color('red') - .style({ - opacity: 0.3, - strokeWidth: 1, - }); - scene.addLayer(pointLayer); + scene.on('loaded', () => { + const pointLayer = new PointLayer({}) + .source(pointsData, { + cluster: true, + }) + .shape('circle') + .scale('point_count', { + type: 'quantile', + }) + .size('point_count', [5, 10, 15, 20, 25]) + // .size(10) + .color('red') + .style({ + opacity: 0.3, + strokeWidth: 1, + }); + scene.addLayer(pointLayer); + this.scene = scene; + }); } public render() { diff --git a/stories/Layers/components/PointImage.tsx b/stories/Layers/components/PointImage.tsx index dfb746a6fd..a5241d1e6b 100644 --- a/stories/Layers/components/PointImage.tsx +++ b/stories/Layers/components/PointImage.tsx @@ -1,5 +1,5 @@ import { PointLayer, Scene } from '@antv/l7'; -import { GaodeMap } from '@antv/l7-maps'; +import { GaodeMap, Mapbox } from '@antv/l7-maps'; import * as React from 'react'; export default class PointImage extends React.Component { // @ts-ignore @@ -15,13 +15,14 @@ export default class PointImage extends React.Component { ); const scene = new Scene({ id: 'map', - map: new GaodeMap({ + map: new Mapbox({ center: [121.4, 31.258134], zoom: 15, pitch: 0, style: 'dark', }), }); + this.scene = scene; scene.addImage( '00', 'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*Rq6tQ5b4_JMAAAAAAAAAAABkARQnAQ', diff --git a/stories/Layers/components/Polygon3D.tsx b/stories/Layers/components/Polygon3D.tsx index c607d07515..bf42016185 100644 --- a/stories/Layers/components/Polygon3D.tsx +++ b/stories/Layers/components/Polygon3D.tsx @@ -54,6 +54,7 @@ export default class Polygon3D extends React.Component { opacity: 1.0, }); scene.addLayer(layer); + this.scene = scene; } public render() { diff --git a/stories/Layers/components/Text.tsx b/stories/Layers/components/Text.tsx index 13f5d4ffcb..fca96db54f 100644 --- a/stories/Layers/components/Text.tsx +++ b/stories/Layers/components/Text.tsx @@ -54,7 +54,6 @@ export default class Point3D extends React.Component { ]) .size('scalerank', [2, 4, 6, 8, 10]); scene.addLayer(pointLayer); - console.log(pointLayer); scene.render(); this.scene = scene; } diff --git a/stories/Layers/components/column.tsx b/stories/Layers/components/column.tsx index 5e83acb16c..77060db564 100644 --- a/stories/Layers/components/column.tsx +++ b/stories/Layers/components/column.tsx @@ -22,7 +22,7 @@ export default class Column extends React.Component { rotation: 134.9507, }), }); - + this.scene = scene; fetch( 'https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json', ) diff --git a/stories/Layers/components/data_update.tsx b/stories/Layers/components/data_update.tsx index c25f8c46f2..26e22e90db 100644 --- a/stories/Layers/components/data_update.tsx +++ b/stories/Layers/components/data_update.tsx @@ -45,6 +45,7 @@ export default class DataUpdate extends React.Component { .source(pointOnCircle(0)) .shape('circle') .size(15) // default 1 + .active(false) .color('#2F54EB') .style({ strokeColor: '#fff', @@ -54,10 +55,7 @@ export default class DataUpdate extends React.Component { scene.addLayer(layer); function animateMarker(timestamp: number) { layer.setData(pointOnCircle(timestamp / 1000)); - scene.render(); - - // setTimeout(animateMarker, 100); requestAnimationFrame(animateMarker); } layer.on('inited', () => { diff --git a/stories/MapAdaptor/Map.stories.tsx b/stories/MapAdaptor/Map.stories.tsx index a2276c3e4d..6fb447d6a1 100644 --- a/stories/MapAdaptor/Map.stories.tsx +++ b/stories/MapAdaptor/Map.stories.tsx @@ -2,6 +2,8 @@ import { storiesOf } from '@storybook/react'; import * as React from 'react'; import GaodeMap from './components/AMap'; import Mapbox from './components/Mapbox'; +import MapboxInstance from './components/MapboxInstance'; +import AMapinstance from './components/MapInstance'; import Mixed from './components/Mixed'; import MultiAMap from './components/MultiAMap'; import MultiMapbox from './components/MultiMapbox'; @@ -12,9 +14,15 @@ storiesOf('地图底图', module) .add('高德地图', () => , { notes: { markdown: notes }, }) + .add('高德地图实例', () => , { + notes: { markdown: notes }, + }) .add('Mapbox', () => , { notes: { markdown: notes }, }) + .add('Mapbox地图实例', () => , { + notes: { markdown: notes }, + }) .add('多个高德地图实例', () => , { notes: { markdown: notes }, }) diff --git a/stories/MapAdaptor/components/MapInstance.tsx b/stories/MapAdaptor/components/MapInstance.tsx new file mode 100644 index 0000000000..1251d5dd23 --- /dev/null +++ b/stories/MapAdaptor/components/MapInstance.tsx @@ -0,0 +1,78 @@ +// @ts-ignore +import { PolygonLayer, Scene } from '@antv/l7'; +import { GaodeMap } from '@antv/l7-maps'; +import * as React from 'react'; + +export default class GaodeMapComponent extends React.Component { + // @ts-ignore + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const response = await fetch( + 'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json', + ); + const data = await response.json(); + // @ts-ignore + window.initAMap = () => { + const map = new AMap.Map('map', { + viewMode: '3D', + resizeEnable: true, // 是否监控地图容器尺寸变化 + zoom: 11, // 初始化地图层级 + center: [116.397428, 39.90923], // 初始化地图中心点 + }); + const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + mapInstance: map, + }), + }); + const layer = new PolygonLayer({ + enablePicking: false, + }); + layer + .source(data) + .size('name', [0, 10000, 50000, 30000, 100000]) + .color('name', [ + '#2E8AE6', + '#69D1AB', + '#DAF291', + '#FFD591', + '#FF7A45', + '#CF1D49', + ]) + .shape('fill') + .style({ + opacity: 0.8, + }); + scene.addLayer(layer); + scene.render(); + this.scene = scene; + }; + const url: string = + 'https://webapi.amap.com/maps?v=1.4.15&key=15cd8a57710d40c9b7c0e3cc120f1200&plugin=Map3D&callback=initAMap'; + const $jsapi = document.createElement('script'); + $jsapi.id = 'amap-script'; + $jsapi.charset = 'utf-8'; + $jsapi.src = url; + document.head.appendChild($jsapi); + } + + public render() { + return ( +
+ ); + } +} diff --git a/stories/MapAdaptor/components/MapboxInstance.tsx b/stories/MapAdaptor/components/MapboxInstance.tsx new file mode 100644 index 0000000000..71b66a068a --- /dev/null +++ b/stories/MapAdaptor/components/MapboxInstance.tsx @@ -0,0 +1,63 @@ +// @ts-ignore +import { PolygonLayer, Scene } from '@antv/l7'; +import { Mapbox } from '@antv/l7-maps'; +import * as React from 'react'; +import mapboxgl from 'mapbox-gl'; + +export default class MapboxInstance extends React.Component { + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const response = await fetch( + 'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json', + ); + mapboxgl.accessToken = + 'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ'; + const map = new mapboxgl.Map({ + container: 'map', // container id + style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location + center: [-74.5, 40], // starting position [lng, lat] + zoom: 9, // starting zoom + }); + + const scene = new Scene({ + id: 'map', + map: new Mapbox({ + mapInstance: map, + }), + }); + this.scene = scene; + const layer = new PolygonLayer({}); + + layer + .source(await response.json()) + .size('name', [0, 10000, 50000, 30000, 100000]) + .color('name', () => { + return 'red'; + }) + .shape('fill') + .style({ + opacity: 0.8, + }); + scene.addLayer(layer); + } + + public render() { + return ( +
+ ); + } +}