diff --git a/dev-demos/layer/popup/popup.tsx b/dev-demos/layer/popup/popup.tsx index 3bbaad47e1..6818831c4b 100644 --- a/dev-demos/layer/popup/popup.tsx +++ b/dev-demos/layer/popup/popup.tsx @@ -1,4 +1,4 @@ -import { GaodeMap, PointLayer, Popup, Scene } from '@antv/l7'; +import { GaodeMap, PointLayer, Popup, Scene, Fullscreen } from '@antv/l7'; import { featureCollection, point } from '@turf/turf'; import React, { useState } from 'react'; // tslint:disable-next-line:no-duplicate-imports @@ -23,6 +23,8 @@ const Demo: FunctionComponent = () => { const newPopup = new Popup({ closeOnClick: false, closeOnEsc: true, + followCursor: true, + offsets: [0, 10], }); newPopup.setLnglat({ lng: 120.104697, @@ -41,6 +43,9 @@ const Demo: FunctionComponent = () => { scene.addLayer(pointLayer); setPopup(newPopup); + + const fullscreen = new Fullscreen(); + scene.addControl(fullscreen); }); }, []); diff --git a/packages/component/src/css/popup.less b/packages/component/src/css/popup.less index d54daaacf0..6adaef6d94 100644 --- a/packages/component/src/css/popup.less +++ b/packages/component/src/css/popup.less @@ -31,14 +31,14 @@ .l7-popup-close-button { position: absolute; - top: 2px; - right: 2px; + top: 3px; + right: 3px; padding: 0; background-color: transparent; border: 0; border-radius: 0 3px 0 0; cursor: pointer; - font-size: 16px; + font-size: 14px; &:hover { background-color: rgba(0, 0, 0, 0.05); } diff --git a/packages/component/src/popup/popup.ts b/packages/component/src/popup/popup.ts index 31d24049ce..79033c4a34 100644 --- a/packages/component/src/popup/popup.ts +++ b/packages/component/src/popup/popup.ts @@ -16,8 +16,22 @@ import { } from '@antv/l7-utils'; import { EventEmitter } from 'eventemitter3'; import { Container } from 'inversify'; +import { debounce } from 'lodash'; export default class Popup extends EventEmitter implements IPopup { + /** + * 当前是否互斥气泡 + */ + public get autoClose() { + return this.popupOption.autoClose; + } + + /** + * 当前 Popup 是否为销毁 + */ + public get isDestroy() { + return !this.mapsService; + } /** * 配置 * @protected @@ -69,6 +83,18 @@ export default class Popup extends EventEmitter implements IPopup { */ protected isShow: boolean = true; + protected onMouseMove = debounce( + (e: MouseEvent) => { + const container = this.mapsService.getMapContainer(); + const { left = 0, top = 0 } = container?.getBoundingClientRect() ?? {}; + this.setPopupOffset(e.clientX - left, e.clientY - top); + }, + 16, + { + maxWait: 16, + }, + ); + constructor(cfg?: Partial) { super(); this.popupOption = { @@ -78,14 +104,6 @@ export default class Popup extends EventEmitter implements IPopup { bindAll(['update', 'onClickClose', 'remove'], this); } - public get autoClose() { - return this.popupOption.autoClose; - } - - public get isDestroy() { - return !this.mapsService; - } - public getIsShow() { return this.isShow; } @@ -110,6 +128,12 @@ export default class Popup extends EventEmitter implements IPopup { this.bindEscEvent(); } + if (this.popupOption.followCursor) { + this.mapsService + .getContainer() + ?.addEventListener('mousemove', this.onMouseMove); + } + this.emit('open'); return this; } @@ -135,6 +159,9 @@ export default class Popup extends EventEmitter implements IPopup { this.mapsService.off('viewchange', this.update); this.mapsService.off('click', this.onClickClose); window.removeEventListener('keypress', this.onKeyDown); + this.mapsService + .getContainer() + ?.removeEventListener('mousemove', this.onMouseMove); // @ts-ignore delete this.mapsService; } @@ -320,6 +347,7 @@ export default class Popup extends EventEmitter implements IPopup { autoPan: false, autoClose: true, closeOnEsc: false, + followCursor: false, }; } @@ -382,13 +410,17 @@ export default class Popup extends EventEmitter implements IPopup { * @protected */ protected updateLngLatPosition() { - if (!this.mapsService) { + if (!this.mapsService && this.popupOption.followCursor) { return; } const { lng, lat } = this.lngLat; + const { x, y } = this.mapsService.lngLatToContainer([lng, lat]); + this.setPopupOffset(x, y); + } + + protected setPopupOffset(left: number, top: number) { const { offsets } = this.popupOption; - 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'; + this.container.style.left = left + offsets[0] + 'px'; + this.container.style.top = top - offsets[1] + 'px'; } } diff --git a/packages/core/src/services/component/IPopupService.ts b/packages/core/src/services/component/IPopupService.ts index f9c0399234..11edca67ba 100644 --- a/packages/core/src/services/component/IPopupService.ts +++ b/packages/core/src/services/component/IPopupService.ts @@ -14,6 +14,7 @@ export interface IPopupOption { stopPropagation: boolean; autoPan: boolean; autoClose: boolean; + followCursor: boolean; className?: string; style?: string; }