refactor(component): add popup marker service

This commit is contained in:
thinkinggis 2019-11-28 00:26:09 +08:00
parent e134a5598c
commit 3734898a5f
53 changed files with 432 additions and 272 deletions

View File

@ -8,6 +8,10 @@ Large-scale WebGL-powered Geospatial data visualization analysis framework.
![l7 demo](https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*SGU-QIZsnyoAAAAAAAAAAABkARQnAQ)
### Installation
```

View File

@ -1,13 +1,14 @@
import { PointLayer, Scale, Scene, Layers, Zoom } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
pitch: 0,
type: 'amap',
style: 'dark',
center: [ 121.40, 31.258134 ],
zoom: 14
map: new GaodeMap({
style: 'light',
pitch: 0,
center: [ 121.4316962, 31.26082325 ],
zoom: 15.056
})
});
fetch('https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json')
.then(res => res.json())
.then(data => {
@ -45,7 +46,6 @@ const zoomControl = new Zoom();
const scaleControl = new Scale({
position: 'bottomright'
});
scene.addControl(zoomControl);
scene.addControl(scaleControl);

View File

@ -1,17 +1,17 @@
import { Scale, Zoom, Scene } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'light',
center: [ -97.119140625, 38.75408327579141 ],
zoom: 2
map: new Mapbox({
style: 'light',
pitch: 0,
center: [ 107.054293, 35.246265 ],
zoom: 4.056
})
});
const zoomControl = new Zoom();
const scaleControl = new Scale({
position: 'rightbottom'
});
const scaleControl = new Scale();
scene.addControl(zoomControl);
scene.addControl(scaleControl);

View File

@ -7,10 +7,12 @@
{
"filename": "amap.js",
"title": "高德底图组件",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*yXzQRYcGTyoAAAAAAAAAAABkARQnAQ"
},
{
"filename": "mapbox.js",
"title": "MapBox底图组件"
"title": "MapBox底图组件",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*_SIYR50bbcoAAAAAAAAAAABkARQnAQ"
}
]
}

View File

@ -1,53 +0,0 @@
import { Scale, Zoom, Scene, Layers, PointLayer } from '@antv/l7';
const scene = new Scene({
id: 'map',
pitch: 0,
type: 'amap',
style: 'dark',
center: [ 121.40, 31.258134 ],
zoom: 5
});
fetch('https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json')
.then(res => res.json())
.then(data => {
const pointLayer =
new PointLayer({
})
.source(data, {
parser: {
type: 'json',
x: 'longitude',
y: 'latitude'
}
}).shape('circle')
.size('unit_price', [ 5, 25 ])
.color('name', [ '#49B5AD', '#5B8FF9' ])
.style({
opacity: 0.3,
strokeWidth: 1
});
scene.addLayer(pointLayer);
const overlayers = {
围栏填充: pointLayer
};
const baseLayers = {
基础地图: pointLayer
};
const layersControl = new Layers({
overlayers,
baseLayers
});
scene.addControl(layersControl);
});
const zoomControl = new Zoom();
const scaleControl = new Scale();
scene.addControl(zoomControl);
scene.addControl(scaleControl);

View File

@ -2,3 +2,4 @@
title: control
order: 2
---
How to use the map control

View File

@ -2,5 +2,4 @@
title: 组件
order: 2
---
如何使用组件

View File

@ -1,37 +1,11 @@
import { LineLayer, Scene } from '@antv/l7';
const scene = new Scene({
import { Scene } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
new Scene({
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'light',
center: [ 102.602992, 23.107329 ],
zoom: 13
map: new GaodeMap({
style: 'light',
pitch: 0,
center: [ 107.054293, 35.246265 ],
zoom: 4.056
})
});
fetch('https://gw.alipayobjects.com/os/rmsportal/ZVfOvhVCzwBkISNsuKCc.json')
.then(res => res.json())
.then(data => {
const layer =
new LineLayer({
})
.source(data)
.size(1)
.shape('line')
.color(
'ELEV',
[
'#E8FCFF',
'#CFF6FF',
'#A1E9ff',
'#65CEF7',
'#3CB1F0',
'#2894E0',
'#1772c2',
'#105CB3',
'#0D408C',
'#002466'
].reverse()
);
scene.addLayer(layer);
});

View File

@ -6,8 +6,8 @@
"demos": [
{
"filename": "line.js",
"title": "线图层",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*KCyXTJrePiYAAAAAAAAAAABkARQnAQ"
"title": "json数据"",
"screenshot": ""
}
]
}

View File

@ -2,3 +2,5 @@
title: Data
order: 1
---
coming soon ……

View File

@ -2,3 +2,4 @@
title: 数据
order: 1
---
在路上 ……

View File

@ -1,9 +1,11 @@
import { Scene } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
new Scene({
id: 'map',
pitch: 0,
type: 'amap',
style: 'dark',
center: [ 121.40, 31.258134 ],
zoom: 5
map: new GaodeMap({
style: 'light',
pitch: 0,
center: [ 107.054293, 35.246265 ],
zoom: 4.056
})
});

View File

@ -1,10 +1,11 @@
import { Scene } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
new Scene({
id: 'map',
pitch: 0,
type: 'mapbox',
style: 'light',
center: [ -97.119140625, 38.75408327579141 ],
zoom: 2
map: new Mapbox({
style: 'light',
pitch: 0,
center: [ 107.054293, 35.246265 ],
zoom: 4.056
})
});

View File

@ -7,12 +7,12 @@
{
"filename": "amap.js",
"title": "高德底图",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*KCyXTJrePiYAAAAAAAAAAABkARQnAQ"
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*F0JPSoLcSesAAAAAAAAAAABkARQnAQ"
},
{
"filename": "mapbox.js",
"title": "MapBox底图",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*KCyXTJrePiYAAAAAAAAAAABkARQnAQ"
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*_SIYR50bbcoAAAAAAAAAAABkARQnAQ"
}
]
}

View File

@ -2,5 +2,5 @@
title: map
order: 0
---
初始 L7 地图实例
how to use L7 Initialize third-party maps

View File

@ -1,9 +1,7 @@
---
title: 地图
order: 0
redirect_from:
- /zh/tutorial
---
初始 L7 地图实例
介绍如何初始化一个第三方底图

View File

@ -0,0 +1,21 @@
import { Scene, Marker, Popup } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new GaodeMap({
style: 'light',
pitch: 0,
center: [ 121.4316962, 31.26082325 ],
zoom: 12.056
})
});
// 创建默认 marker
const popup = new Popup({
offsets: [ 0, 20 ]
}).setText('hello');
const marker = new Marker()
.setLnglat([ 121.4316962, 31.26082325 ])
.setPopup(popup);
scene.addMarker(marker);

View File

@ -0,0 +1,17 @@
import { Scale, Zoom, Scene } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new Mapbox({
style: 'light',
pitch: 0,
center: [ 107.054293, 35.246265 ],
zoom: 4.056
})
});
const zoomControl = new Zoom();
const scaleControl = new Scale();
scene.addControl(zoomControl);
scene.addControl(scaleControl);

View File

@ -0,0 +1,18 @@
{
"title": {
"zh": "地图",
"en": "Category"
},
"demos": [
{
"filename": "amap.js",
"title": "添加默认Marker",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*Gzj7SYk-vdEAAAAAAAAAAABkARQnAQ"
},
{
"filename": "mapbox.js",
"title": "MapBox底图组件",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*_SIYR50bbcoAAAAAAAAAAABkARQnAQ"
}
]
}

View File

@ -0,0 +1,5 @@
---
title: control
order: 2
---
add Rich text annotation to scene

View File

@ -0,0 +1,5 @@
---
title: Marker
order: 2
---
通过添加dom实现富文本地图标注

View File

@ -114,7 +114,7 @@
"worker-loader": "^2.0.0"
},
"scripts": {
"start": "npm run site:develop",
"start": "npm run site:clean && npm run site:develop",
"site:develop": "BABEL_ENV=site gatsby develop --open -H 0.0.0.0",
"site:build": "npm run site:clean && BABEL_ENV=site gatsby build --prefix-paths",
"site:clean": "gatsby clean",

View File

@ -33,14 +33,8 @@ export default class Layers extends Control {
this.layers = [];
this.lastZIndex = 0;
this.handlingClick = false;
const { baseLayers = {}, overlayers = {} } = this.controlOption;
this.initLayers();
Object.keys(baseLayers).forEach((name: string, index: number) => {
this.addLayer(baseLayers[name], name, false);
});
Object.keys(overlayers).forEach((name: any, index: number) => {
this.addLayer(overlayers[name], name, true);
});
bindAll(
[
'checkDisabledLayers',
@ -131,6 +125,17 @@ export default class Layers extends Control {
this.overlaysList = DOM.create('div', className + '-overlays', form);
container.appendChild(form);
}
private initLayers() {
const { baseLayers = {}, overlayers = {} } = this.controlOption;
Object.keys(baseLayers).forEach((name: string, index: number) => {
// baseLayers[name].once('inited', this.update);
this.addLayer(baseLayers[name], name, false);
});
Object.keys(overlayers).forEach((name: any, index: number) => {
// overlayers[name].once('inited', this.update);
this.addLayer(overlayers[name], name, true);
});
}
private update() {
if (!this.container) {
@ -177,7 +182,7 @@ export default class Layers extends Control {
input = inputs[i];
layer = this.layerService.getLayer(input.layerId);
if (layer) {
input.disabled = !layer.isVisible();
input.disabled = !layer.inited || !layer.isVisible();
}
}
}
@ -251,10 +256,9 @@ export default class Layers extends Control {
private addItem(obj: any) {
const label = document.createElement('label');
const checked =
this.layerService.getLayer(obj.layer.id) && obj.layer.isVisible();
const layer = this.layerService.getLayer(obj.layer.id);
const checked = layer && layer.inited && obj.layer.isVisible();
let input: IInputItem;
if (obj.overlay) {
input = document.createElement('input') as IInputItem;
input.type = 'checkbox';

View File

@ -1,5 +1,6 @@
import { ILngLat, IMapService, IMarkerScene, IPopup } from '@antv/l7-core';
import { ILngLat, IMapService, IPoint, IPopup, TYPES } from '@antv/l7-core';
import { bindAll, DOM } from '@antv/l7-utils';
import { Container } from 'inversify';
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
// marker 支持 dragger 未完成
@ -14,9 +15,9 @@ export default class Marker {
private markerOption: IMarkerOption;
private defaultMarker: boolean;
private popup: IPopup; // TODO: POPup
private mapservice: IMapService<unknown>;
private mapsService: IMapService<unknown>;
private lngLat: ILngLat;
private scene: IMarkerScene;
private scene: Container;
constructor(option?: Partial<IMarkerOption>) {
this.markerOption = {
...this.getDefault(),
@ -36,29 +37,27 @@ export default class Marker {
};
}
public addTo(scene: IMarkerScene) {
this.scene = scene;
const mapService = scene.getMapService();
const { element, draggable } = this.markerOption;
public addTo(scene: Container) {
this.remove();
this.mapservice = mapService;
mapService.getMarkerContainer().appendChild(element as HTMLElement);
mapService.on('camerachange', this.update);
this.scene = scene;
this.mapsService = scene.get<IMapService>(TYPES.IMapService);
const { element, draggable } = this.markerOption;
this.mapsService.getMarkerContainer().appendChild(element as HTMLElement);
this.mapsService.on('camerachange', this.update);
// this.setDraggable(draggable);
this.update();
return this;
}
public remove() {
if (this.mapservice) {
this.mapservice.off('click', this.onMapClick);
this.mapservice.off('move', this.update);
this.mapservice.off('moveend', this.update);
this.mapservice.off('mousedown', this.addDragHandler);
this.mapservice.off('touchstart', this.addDragHandler);
this.mapservice.off('mouseup', this.onUp);
this.mapservice.off('touchend', this.onUp);
delete this.mapservice;
if (this.mapsService) {
this.mapsService.off('click', this.onMapClick);
this.mapsService.off('move', this.update);
this.mapsService.off('moveend', this.update);
this.mapsService.off('mousedown', this.addDragHandler);
this.mapsService.off('touchstart', this.addDragHandler);
this.mapsService.off('mouseup', this.onUp);
this.mapsService.off('touchend', this.onUp);
}
const { element } = this.markerOption;
if (element) {
@ -70,8 +69,15 @@ export default class Marker {
return this;
}
public setLnglat(lngLat: ILngLat) {
this.lngLat = lngLat;
public setLnglat(lngLat: ILngLat | IPoint) {
this.lngLat = lngLat as ILngLat;
if (Array.isArray(lngLat)) {
this.lngLat = {
lng: lngLat[0],
lat: lngLat[1],
};
}
if (this.popup) {
this.popup.setLnglat(this.lngLat);
}
@ -86,6 +92,14 @@ export default class Marker {
return this.markerOption.element as HTMLElement;
}
public setPopup(popup: IPopup) {
this.popup = popup;
if (this.lngLat) {
this.popup.setLnglat(this.lngLat);
}
return this;
}
public togglePopup() {
const popup = this.popup;
if (!popup) {
@ -115,7 +129,7 @@ export default class Marker {
}
private update() {
if (!this.mapservice) {
if (!this.mapsService) {
return;
}
const { element, anchor } = this.markerOption;
@ -131,12 +145,12 @@ export default class Marker {
}
private updatePosition() {
if (!this.mapservice) {
if (!this.mapsService) {
return;
}
const { element } = this.markerOption;
const { lng, lat } = this.lngLat;
const pos = this.mapservice.lngLatToContainer([lng, lat]);
const pos = this.mapsService.lngLatToContainer([lng, lat]);
if (element) {
element.style.left = pos.x + 'px';
element.style.top = pos.y + 'px';

View File

@ -1,6 +1,7 @@
import { ILngLat, IMapService, IMarkerScene, IPopup } from '@antv/l7-core';
import { ILngLat, IMapService, IPoint, IPopup, TYPES } from '@antv/l7-core';
import { bindAll, DOM } from '@antv/l7-utils';
import { EventEmitter } from 'eventemitter3';
import { Container } from 'inversify';
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
/** colse event */
@ -15,7 +16,7 @@ export interface IPopupOption {
}
export default class Popup extends EventEmitter implements IPopup {
private popupOption: IPopupOption;
private mapservice: IMapService<unknown>;
private mapsService: IMapService<unknown>;
private lngLat: ILngLat;
private content: HTMLElement;
private closeButton: HTMLElement;
@ -32,14 +33,13 @@ export default class Popup extends EventEmitter implements IPopup {
bindAll(['update', 'onClickClose', 'remove'], this);
}
public addTo(scene: IMarkerScene) {
const mapService = scene.getMapService();
this.mapservice = mapService;
this.mapservice.on('camerachange', this.update);
public addTo(scene: Container) {
this.mapsService = scene.get<IMapService>(TYPES.IMapService);
this.mapsService.on('camerachange', this.update);
this.update();
if (this.popupOption.closeOnClick) {
this.timeoutInstance = setTimeout(() => {
this.mapservice.on('click', this.onClickClose);
this.mapsService.on('click', this.onClickClose);
}, 30);
}
return this;
@ -62,9 +62,15 @@ export default class Popup extends EventEmitter implements IPopup {
}
public setLnglat(lngLat: ILngLat): this {
this.lngLat = lngLat;
if (this.mapservice) {
this.mapservice.on('camerachange', this.update);
this.lngLat = lngLat as ILngLat;
if (Array.isArray(lngLat)) {
this.lngLat = {
lng: lngLat[0],
lat: lngLat[1],
};
}
if (this.mapsService) {
this.mapsService.on('camerachange', this.update);
}
this.update();
return this;
@ -99,18 +105,18 @@ export default class Popup extends EventEmitter implements IPopup {
this.removeDom(this.container);
delete this.container;
}
if (this.mapservice) {
if (this.mapsService) {
// TODO: mapbox AMap 事件同步
this.mapservice.off('camerachange', this.update);
this.mapservice.off('click', this.onClickClose);
delete this.mapservice;
this.mapsService.off('camerachange', this.update);
this.mapsService.off('click', this.onClickClose);
delete this.mapsService;
}
clearTimeout(this.timeoutInstance);
this.emit('close');
return this;
}
public isOpen() {
return !!this.mapservice;
return !!this.mapsService;
}
private createContent() {
@ -166,10 +172,10 @@ export default class Popup extends EventEmitter implements IPopup {
private update() {
const hasPosition = this.lngLat;
const { className, maxWidth, anchor } = this.popupOption;
if (!this.mapservice || !hasPosition || !this.content) {
if (!this.mapsService || !hasPosition || !this.content) {
return;
}
const markerContainer = this.mapservice.getMarkerContainer();
const markerContainer = this.mapsService.getMarkerContainer();
if (!this.container && markerContainer) {
this.container = this.creatDom(
'div',
@ -198,12 +204,12 @@ export default class Popup extends EventEmitter implements IPopup {
}
private updatePosition() {
if (!this.mapservice) {
if (!this.mapsService) {
return;
}
const { lng, lat } = this.lngLat;
const { offsets } = this.popupOption;
const pos = this.mapservice.lngLatToContainer([lng, lat]);
const pos = this.mapsService.lngLatToContainer([lng, lat]);
this.container.style.left = pos.x + offsets[0] + 'px';
this.container.style.top = pos.y - offsets[1] + 'px';
}

View File

@ -43,7 +43,7 @@ export * from './services/asset/IIconService';
export * from './services/asset/IFontService';
export * from './services/component/IControlService';
export * from './services/component/IMarkerService';
export * from './services/component/IPopUpService';
export * from './services/component/IPopupService';
export * from './services/log/ILogService';
export * from './services/interaction/IInteractionService';

View File

@ -28,6 +28,8 @@ import FontService from './services/asset/FontService';
import IconService from './services/asset/IconService';
import CameraService from './services/camera/CameraService';
import ControlService from './services/component/ControlService';
import MarkerService from './services/component/MarkerService';
import PopupService from './services/component/PopupService';
import GlobalConfigService from './services/config/ConfigService';
import CoordinateSystemService from './services/coordinate/CoordinateSystemService';
import InteractionService from './services/interaction/InteractionService';
@ -38,6 +40,8 @@ import SceneService from './services/scene/SceneService';
import ShaderModuleService from './services/shader/ShaderModuleService';
/** PostProcessing passes */
import { IMarkerService } from './services/component/IMarkerService';
import { IPopupService } from './services/component/IPopupService';
import {
IMultiPassRenderer,
IPass,
@ -181,6 +185,15 @@ export function createSceneContainer() {
.bind<IControlService>(TYPES.IControlService)
.to(ControlService)
.inSingletonScope();
sceneContainer
.bind<IMarkerService>(TYPES.IMarkerService)
.to(MarkerService)
.inSingletonScope();
sceneContainer
.bind<IPopupService>(TYPES.IPopupService)
.to(PopupService)
.inSingletonScope();
// 绑定常规 passes
sceneContainer

View File

@ -1,26 +1,36 @@
import { DOM } from '@antv/l7-utils';
import { Container, injectable } from 'inversify';
import { TYPES } from '../../types';
import { IMapService } from '../map/IMapService';
import {
IControl,
IControlCorners,
IControlService,
IControlServiceCfg,
} from './IControlService';
@injectable()
export default class ControlService implements IControlService {
public container: HTMLElement;
public controlCorners: IControlCorners;
public controlContainer: HTMLElement;
public scene: Container;
public mapsService: IMapService;
private controls: IControl[] = [];
public init(cfg: IControlServiceCfg) {
private unAddControls: IControl[] = [];
public init(cfg: IControlServiceCfg, sceneContainer: Container) {
this.container = cfg.container;
this.scene = sceneContainer;
this.mapsService = sceneContainer.get<IMapService>(TYPES.IMapService);
this.initControlPos();
}
public addControl(ctr: IControl, sceneContainer: Container): void {
ctr.addTo(sceneContainer); // scene对象
this.controls.push(ctr);
const mapsService = sceneContainer.get<IMapService>(TYPES.IMapService);
if (mapsService.map) {
ctr.addTo(this.scene); // scene对象
this.controls.push(ctr);
} else {
this.unAddControls.push(ctr);
}
}
public removeControl(ctr: IControl): this {
const index = this.controls.indexOf(ctr);
@ -31,6 +41,14 @@ export default class ControlService implements IControlService {
return this;
}
public addControls() {
this.unAddControls.forEach((ctr: IControl) => {
ctr.addTo(this.scene); // scene对象
this.controls.push(ctr);
});
this.unAddControls = [];
}
public destroy(): void {
for (const ctr of this.controls) {
ctr.remove();

View File

@ -26,7 +26,8 @@ export interface IControlService {
container: HTMLElement;
controlCorners: IControlCorners;
controlContainer: HTMLElement;
init(cfg: IControlServiceCfg): void;
addControls(): void;
init(cfg: IControlServiceCfg, sceneContainer: Container): void;
addControl(ctr: IControl, sceneContainer: Container): void;
removeControl(ctr: IControl): void;
destroy(): void;

View File

@ -1,13 +1,28 @@
import { ILngLat, IMapService } from '../map/IMapService';
import { Container, injectable } from 'inversify';
import { ILngLat, IMapService, IPoint } from '../map/IMapService';
import { IPopup } from './IPopUpService';
export interface IMarkerScene {
getMapService(): IMapService<unknown>;
[key: string]: any;
}
export interface IMarkerServiceCfg {
container: HTMLElement;
}
export interface IMarker {
addTo(scene: IMarkerScene): void;
addTo(scene: Container): void;
remove(): void;
setLnglat(lngLat: ILngLat): this;
setLnglat(lngLat: ILngLat | IPoint): this;
getLnglat(): ILngLat;
getElement(): HTMLElement;
setPopup(popup: IPopup): void;
togglePopup(): this;
}
export interface IMarkerService {
container: HTMLElement;
addMarker(Marker: IMarker): void;
addMarkers(): void;
removeMarker(Marker: IMarker): void;
init(scene: Container): void;
destroy(): void;
}

View File

@ -1,7 +1,8 @@
import { Container } from 'inversify';
import { ILngLat, IMapService } from '../map/IMapService';
import { IMarkerScene } from './IMarkerService';
export interface IPopup {
addTo(scene: IMarkerScene): this;
addTo(scene: Container): this;
remove(): void;
setLnglat(lngLat: ILngLat): this;
getLnglat(): ILngLat;
@ -10,3 +11,9 @@ export interface IPopup {
setMaxWidth(maxWidth: string): this;
isOpen(): boolean;
}
export interface IPopupService {
addPopup(popup: IPopup): void;
removePopup(popup: IPopup): void;
init(scene: Container): void;
destroy(): void;
}

View File

@ -0,0 +1,41 @@
import { Container, injectable } from 'inversify';
import { TYPES } from '../../types';
import { IMapService } from '../map/IMapService';
import { IMarker, IMarkerService, IMarkerServiceCfg } from './IMarkerService';
@injectable()
export default class MarkerService implements IMarkerService {
public container: HTMLElement;
private scene: Container;
private mapsService: IMapService;
private markers: IMarker[] = [];
private unAddMarkers: IMarker[] = [];
public addMarker(marker: IMarker): void {
if (!this.mapsService.map) {
this.unAddMarkers.push(marker);
} else {
this.markers.push(marker);
marker.addTo(this.scene);
}
}
public addMarkers(): void {
this.unAddMarkers.forEach((marker: IMarker) => {
marker.addTo(this.scene);
this.markers.push(marker);
});
this.unAddMarkers = [];
}
public removeMarker(marker: IMarker): void {
marker.remove();
}
public init(scene: Container): void {
// this.container = cfg.container;
this.scene = scene;
this.mapsService = scene.get<IMapService>(TYPES.IMapService);
}
public destroy(): void {
this.markers.forEach((marker: IMarker) => {
marker.remove();
});
}
}

View File

@ -0,0 +1,28 @@
import { Container, injectable } from 'inversify';
import { TYPES } from '../../types';
import { IMapService } from '../map/IMapService';
import { IPopup, IPopupService } from './IPopupService';
@injectable()
export default class PopupService implements IPopupService {
private scene: Container;
private popup: IPopup;
public removePopup(popup: IPopup): void {
popup.remove();
}
public destroy(): void {
this.popup.remove();
}
public addPopup(popup: IPopup) {
this.popup.remove();
popup.addTo(this.scene);
this.popup = popup;
}
public init(scene: Container) {
this.scene = scene;
}
}

View File

@ -7,6 +7,7 @@ import { IFontService } from '../asset/IFontService';
import { IIconService } from '../asset/IIconService';
import { ICameraService, IViewport } from '../camera/ICameraService';
import { IControlService } from '../component/IControlService';
import { IMarkerService } from '../component/IMarkerService';
import { IGlobalConfigService, ISceneConfig } from '../config/IConfigService';
import { IInteractionService } from '../interaction/IInteractionService';
import { ILayer, ILayerService } from '../layer/ILayerService';
@ -59,6 +60,9 @@ export default class Scene extends EventEmitter implements ISceneService {
@inject(TYPES.IShaderModuleService)
private readonly shaderModuleService: IShaderModuleService;
@inject(TYPES.IMarkerService)
private readonly markerService: IMarkerService;
/**
*
*/
@ -112,12 +116,6 @@ export default class Scene extends EventEmitter implements ISceneService {
// 字体资源
this.fontService.init();
this.controlService.init({
container: document.getElementById(
this.configService.getSceneConfig(this.id).id || 'map',
) as HTMLElement,
});
/**
*
*/
@ -131,9 +129,12 @@ export default class Scene extends EventEmitter implements ISceneService {
});
this.map.init();
});
// this.controlService.addControls();
// 重新绑定非首次相机更新事件
this.map.onCameraChanged(this.handleMapCameraChanged);
this.map.addMarkerContainer();
// 初始化未加载的marker;
this.markerService.addMarkers();
this.logger.debug('map loaded');
});
@ -155,7 +156,6 @@ export default class Scene extends EventEmitter implements ISceneService {
// 初始化 container 上的交互
this.interactionService.init();
this.logger.debug(`scene ${this.id} renderer loaded`);
});
// TODOinit worker, fontAtlas...
@ -185,7 +185,7 @@ export default class Scene extends EventEmitter implements ISceneService {
await this.initPromise;
// FIXME: 初始化 marker 容器,可以放到 map 初始化方法中?
this.map.addMarkerContainer();
this.logger.info(' render inited');
this.emit('loaded');
this.inited = true;
@ -194,6 +194,8 @@ export default class Scene extends EventEmitter implements ISceneService {
// 尝试初始化未初始化的图层
this.layerService.initLayers();
this.layerService.renderLayers();
// 组件需要等待layer 初始化完成之后添加
this.controlService.addControls();
this.logger.debug(`scene ${this.id} render`);
this.rendering = false;
@ -205,6 +207,7 @@ export default class Scene extends EventEmitter implements ISceneService {
this.layerService.destroy();
this.interactionService.destroy();
this.controlService.destroy();
this.markerService.destroy();
this.removeAllListeners();
this.rendererService.destroy();
this.map.destroy();

View File

@ -113,8 +113,7 @@ float project_pixel(float pixel) {
return pixel;
}
vec2 project_pixel(vec2 pixel) {
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20
|| u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET) {
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20) {
// P20 坐标系下,为了和 Web 墨卡托坐标系统一zoom 默认减1
return pixel * pow(2.0, (19.0 - u_Zoom));
}

View File

@ -9,6 +9,8 @@ const TYPES = {
ILayerStyleService: Symbol.for('ILayerStyleService'),
ILogService: Symbol.for('ILogService'),
IMapService: Symbol.for('IMapService'),
IMarkerService: Symbol.for('IMarkerService'),
IPopupService: Symbol.for('PopupService'),
IFactoryMapService: Symbol.for('Factory<IMapService>'),
IRendererService: Symbol.for('IRendererService'),
IShaderModuleService: Symbol.for('IShaderModuleService'),

View File

@ -265,6 +265,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
this.buildModels();
this.inited = true;
// 触发初始化完成事件;
this.emit('inited');
return this;
}

View File

@ -1,8 +1,8 @@
import { AttributeType, gl, IEncodeFeature, IModel } from '@antv/l7-core';
import BaseModel from '../../core/BaseModel';
import { PointExtrudeTriangulation } from '../../core/triangulation';
import pointExtrudeVert from '../shaders/extrude_vert.glsl';
import pointExtrudeFrag from '../shaders/extrude_frag.glsl';
import pointExtrudeVert from '../shaders/extrude_vert.glsl';
interface IPointLayerStyleOptions {
opacity: number;
}

View File

@ -23,7 +23,7 @@ void main() {
vec2 offset = project_pixel(size.xy);
vec4 project_pos = project_position(vec4(a_Pos.xy, 0, 1.0));
vec4 pos = vec4(project_pos.xy + offset, project_pixel(size.z), 1.0);
vec4 pos = vec4(project_pos.xy + offset, size.z, 1.0);
float lightWeight = calc_lighting(pos);
v_color =vec4(a_Color.rgb * lightWeight, a_Color.w);

View File

@ -17,7 +17,8 @@ varying vec4 v_Color;
#pragma include "picking"
void main() {
vec4 project_pos = project_position(vec4(a_Position.xy, project_pixel(a_Position.z * a_Size), 1.0));
vec4 pos = vec4(a_Position.xy, a_Position.z * a_Size, 1.0);
vec4 project_pos = project_position(pos);
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));

View File

@ -1,7 +1,7 @@
export const MapTheme: {
[key: string]: any;
} = {
light: 'mapbox://styles/zcxduo/ck233y3ru1di71cnulo9jdg2v',
light: 'mapbox://styles/zcxduo/ck2ypyb1r3q9o1co1766dex29',
dark: 'mapbox://styles/zcxduo/ck241p6413s0b1cpayzldv7x7',
normal: 'mapbox://styles/mapbox/streets-v11',
};

View File

@ -26,6 +26,7 @@
"@antv/l7-core": "^2.0.0-beta.10",
"@antv/l7-maps": "^2.0.0-beta.10",
"@antv/l7-renderer": "^2.0.0-beta.10",
"@antv/l7-utils": "^2.0.0-beta.10",
"inversify": "^5.0.1",
"inversify-inject-decorators": "^3.1.0",
"mapbox-gl": "^1.2.1",

View File

@ -12,7 +12,10 @@ import {
ILngLat,
IMapService,
IMarker,
IMarkerService,
IPoint,
IPopup,
IPopupService,
IPostProcessingPass,
IRendererService,
ISceneConfig,
@ -22,6 +25,7 @@ import {
TYPES,
} from '@antv/l7-core';
import { ReglRendererService } from '@antv/l7-renderer';
import { DOM } from '@antv/l7-utils';
import { Container } from 'inversify';
import ILayerManager from './ILayerManager';
import IMapController from './IMapController';
@ -46,6 +50,8 @@ class Scene
private controlService: IControlService;
private layerService: ILayerService;
private iconService: IIconService;
private markerService: IMarkerService;
private popupService: IPopupService;
private container: Container;
@ -76,6 +82,14 @@ class Scene
);
this.layerService = sceneContainer.get<ILayerService>(TYPES.ILayerService);
this.markerService = sceneContainer.get<IMarkerService>(
TYPES.IMarkerService,
);
this.popupService = sceneContainer.get<IPopupService>(TYPES.IPopupService);
this.initComponent(id);
// 初始化 scene
this.sceneService.init(config);
// TODO: 初始化组件
@ -137,9 +151,12 @@ class Scene
// marker
public addMarker(marker: IMarker) {
marker.addTo(this);
this.markerService.addMarker(marker);
}
public addPopup(popup: IPopup) {
this.popupService.addPopup(popup);
}
public on(type: string, handle: (...args: any[]) => void): void {
SceneEventList.indexOf(type) === -1
? this.mapService.on(type, handle)
@ -237,6 +254,16 @@ class Scene
.whenTargetNamed(name);
}
private initComponent(id: string | HTMLDivElement) {
this.controlService.init(
{
container: DOM.getContainer(id),
},
this.container,
);
this.markerService.init(this.container);
this.popupService.init(this.container);
}
// 资源管理
}

View File

@ -1,24 +1,11 @@
const docStyle = window.document.documentElement.style;
type ELType = HTMLElement | SVGElement;
export function createRendererContainer(domId: string): HTMLDivElement | null {
const $wrapper = document.getElementById(domId);
if ($wrapper) {
const $container = document.createElement('div');
$container.style.cssText += `
position: absolute;
top: 0;
z-index:2;
height: 100%;
width: 100%;
pointer-events: none;
`;
$container.id = 'l7_canvaslayer';
$wrapper.appendChild($container);
return $container;
export function getContainer(domId: string | HTMLDivElement) {
let $dom = domId as HTMLDivElement;
if (typeof domId === 'string') {
$dom = document.getElementById(domId) as HTMLDivElement;
}
return null;
return $dom;
}
export function trim(str: string) {
@ -130,7 +117,7 @@ export function getClass(el: ELType) {
}
export function empty(el: ELType) {
while (el.firstChild) {
while (el && el.firstChild) {
el.removeChild(el.firstChild);
}
}

View File

@ -1,5 +1,5 @@
import { HeatmapLayer, Scene } from '@antv/l7';
import { AMap } from '@antv/l7-maps';
import { GaodeMap } from '@antv/l7-maps';
import * as React from 'react';
export default class GridHeatMap extends React.Component {
@ -17,7 +17,7 @@ export default class GridHeatMap extends React.Component {
const data = await response.text();
const scene = new Scene({
id: 'map',
map: new AMap({
map: new GaodeMap({
style: 'dark',
pitch: 0,
center: [110.097892, 33.853662],

View File

@ -1,5 +1,5 @@
import { PointLayer, Scene } from '@antv/l7';
import { AMap, Mapbox } from '@antv/l7-maps';
import { GaodeMap, Mapbox } from '@antv/l7-maps';
import * as React from 'react';
// @ts-ignore
import data from '../data/data.json';
@ -18,7 +18,7 @@ export default class Point3D extends React.Component {
const pointsData = await response.json();
const scene = new Scene({
id: 'map',
map: new AMap({
map: new GaodeMap({
center: [120.19382669582967, 30.258134],
pitch: 0,
style: 'light',

View File

@ -1,5 +1,5 @@
import { PointLayer, Scene } from '@antv/l7';
import { AMap } from '@antv/l7-maps';
import { GaodeMap } from '@antv/l7-maps';
import * as React from 'react';
export default class PointImage extends React.Component {
// @ts-ignore
@ -15,7 +15,7 @@ export default class PointImage extends React.Component {
);
const scene = new Scene({
id: 'map',
map: new AMap({
map: new GaodeMap({
center: [121.4, 31.258134],
zoom: 15,
pitch: 0,

View File

@ -1,5 +1,5 @@
import { PolygonLayer, Scene } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
import { GaodeMap } from '@antv/l7-maps';
import * as React from 'react';
function convertRGB2Hex(rgb: number[]) {
@ -25,42 +25,36 @@ export default class Polygon3D extends React.Component {
public async componentDidMount() {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
'https://gw.alipayobjects.com/os/basement_prod/972566c5-a2b9-4a7e-8da1-bae9d0eb0117.json'
);
const scene = new Scene({
id: 'map',
map: new Mapbox({
style: 'mapbox://styles/mapbox/streets-v9',
center: [110.19382669582967, 50.258134],
map: new GaodeMap({
pitch: 0,
zoom: 3,
}),
style: 'dark',
center: [ 114.050008, 22.529272 ],
zoom: 14.1
})
});
this.scene = scene;
const layer = new PolygonLayer({
enableLighting: true,
enablePicking: true,
enableHighlight: true,
// enableTAA: true,
});
layer
const layer = new PolygonLayer({})
.source(await response.json())
.size('name', [0, 10000, 50000, 30000, 100000])
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49',
])
.shape('extrude')
.size('h20', [100, 120, 160, 200, 260, 500])
.color('h20', [
'#816CAD',
'#A67FB5',
'#C997C7',
'#DEB8D4',
'#F5D4E6',
'#FAE4F1',
'#FFF3FC'
])
.style({
opacity: 1.0,
opacity: 1.0
});
scene.addLayer(layer);
scene.render();
this.scene = scene;
}
public render() {

View File

@ -1,6 +1,6 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import AMap from './components/AMap';
import GaodeMap from './components/AMap';
import Mapbox from './components/Mapbox';
import Mixed from './components/Mixed';
import MultiAMap from './components/MultiAMap';
@ -9,7 +9,7 @@ import MultiMapbox from './components/MultiMapbox';
import notes from './Map.md';
// @ts-ignore
storiesOf('地图底图', module)
.add('高德地图', () => <AMap />, {
.add('高德地图', () => <GaodeMap />, {
notes: { markdown: notes },
})
.add('Mapbox', () => <Mapbox />, {

View File

@ -1,9 +1,9 @@
// @ts-ignore
import { PolygonLayer, Scene } from '@antv/l7';
import { AMap } from '@antv/l7-maps';
import { GaodeMap } from '@antv/l7-maps';
import * as React from 'react';
export default class AMapComponent extends React.Component {
export default class GaodeMapComponent extends React.Component {
// @ts-ignore
private scene: Scene;
@ -18,7 +18,7 @@ export default class AMapComponent extends React.Component {
const data = await response.json();
const scene = new Scene({
id: 'map',
map: new AMap({
map: new GaodeMap({
center: [110.19382669582967, 50.258134],
pitch: 0,
style: 'dark',

View File

@ -1,6 +1,6 @@
// @ts-ignore
import { PointLayer, PolygonLayer, Scene } from '@antv/l7';
import { AMap, Mapbox } from '@antv/l7-maps';
import { GaodeMap, Mapbox } from '@antv/l7-maps';
import * as React from 'react';
// @ts-ignore
import pointsData from '../../assets/data/points.json';
@ -26,7 +26,7 @@ export default class Mixed extends React.Component {
const scene1 = new Scene({
id: 'map1',
map: new AMap({
map: new GaodeMap({
center: [110.19382669582967, 50.258134],
pitch: 0,
style: 'light',
@ -35,7 +35,7 @@ export default class Mixed extends React.Component {
});
const scene2 = new Scene({
id: 'map2',
map: new AMap({
map: new GaodeMap({
center: [110.19382669582967, 50.258134],
pitch: 0,
style: 'dark',

View File

@ -1,9 +1,9 @@
// @ts-ignore
import { Scene } from '@antv/l7';
import { AMap } from '@antv/l7-maps';
import { GaodeMap } from '@antv/l7-maps';
import * as React from 'react';
export default class MultiAMap extends React.Component {
export default class MultiGaodeMap extends React.Component {
private scene1: Scene;
private scene2: Scene;
@ -18,7 +18,7 @@ export default class MultiAMap extends React.Component {
);
const scene1 = new Scene({
id: 'map1',
map: new AMap({
map: new GaodeMap({
center: [110.19382669582967, 50.258134],
pitch: 0,
style: 'light',
@ -27,7 +27,7 @@ export default class MultiAMap extends React.Component {
});
const scene2 = new Scene({
id: 'map2',
map: new AMap({
map: new GaodeMap({
center: [110.19382669582967, 50.258134],
pitch: 0,
style: 'dark',