mirror of https://gitee.com/antv-l7/antv-l7
Shihui (#1009)
* feat: 新增 canvasLayer、修复 mapbox 地图下 mapchange 事件失效 * style: lint style * feat: 优化 canvasLayer show dragend 模式的事件 * style: lint style
This commit is contained in:
parent
c95839c137
commit
781b2586e1
|
@ -63,6 +63,7 @@ export interface ILayerModelInitializationOptions {
|
|||
|
||||
export interface ILayerModel {
|
||||
render(): void;
|
||||
renderUpdate?(): void;
|
||||
getUninforms(): IModelUniform;
|
||||
getDefaultStyle(): unknown;
|
||||
getAnimateUniforms(): IModelUniform;
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import BaseLayer from '../core/BaseLayer';
|
||||
import { ICanvasLayerStyleOptions } from '../core/interface';
|
||||
import CanvasModels, { CanvasModelType } from './models/index';
|
||||
export default class CanvasLayer extends BaseLayer<ICanvasLayerStyleOptions> {
|
||||
public type: string = 'CanvasLayer';
|
||||
public buildModels() {
|
||||
const modelType = this.getModelType();
|
||||
this.layerModel = new CanvasModels[modelType](this);
|
||||
this.models = this.layerModel.initModels();
|
||||
}
|
||||
public rebuildModels() {
|
||||
this.models = this.layerModel.buildModels();
|
||||
}
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
protected getDefaultConfig() {
|
||||
const type = this.getModelType();
|
||||
const defaultConfig = {
|
||||
canvas: {},
|
||||
};
|
||||
return defaultConfig[type];
|
||||
}
|
||||
|
||||
protected getModelType(): CanvasModelType {
|
||||
return 'canvas';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
import BaseModel from '../../core/BaseModel';
|
||||
import {
|
||||
CanvasUpdateType,
|
||||
ICanvasLayerStyleOptions,
|
||||
} from '../../core/interface';
|
||||
|
||||
export default class CanvaModel extends BaseModel {
|
||||
protected updateMode: CanvasUpdateType = CanvasUpdateType.AWAYS;
|
||||
protected canvas: HTMLCanvasElement;
|
||||
protected ctx: CanvasRenderingContext2D;
|
||||
protected prevSize: [number, number];
|
||||
public renderUpdate = () => {
|
||||
const {
|
||||
zIndex = 10,
|
||||
update = CanvasUpdateType.AWAYS,
|
||||
} = this.layer.getLayerConfig() as ICanvasLayerStyleOptions;
|
||||
if (+this.canvas.style.zIndex === zIndex) {
|
||||
this.canvas.style.zIndex = zIndex + '';
|
||||
}
|
||||
if (this.updateMode !== update) {
|
||||
this.updateMode = update as CanvasUpdateType;
|
||||
this.unBindListener();
|
||||
this.bindListener();
|
||||
}
|
||||
};
|
||||
|
||||
public unBindListener = () => {
|
||||
this.mapService.off('mapchange', this.renderCanvas);
|
||||
this.mapService.off('zoomstart', this.clearCanvas);
|
||||
this.mapService.off('zoomend', this.renderCanvas);
|
||||
this.mapService.off('movestart', this.clearCanvas);
|
||||
this.mapService.off('moveend', this.renderCanvas);
|
||||
};
|
||||
|
||||
public bindListener = () => {
|
||||
if (this.updateMode === CanvasUpdateType.AWAYS) {
|
||||
this.mapService.on('mapchange', this.renderCanvas);
|
||||
} else {
|
||||
this.mapService.on('zoomstart', this.clearCanvas);
|
||||
this.mapService.on('zoomend', this.renderCanvas);
|
||||
this.mapService.on('movestart', this.clearCanvas);
|
||||
this.mapService.on('moveend', this.renderCanvas);
|
||||
}
|
||||
};
|
||||
|
||||
public clearModels(): void {
|
||||
if (this.canvas) {
|
||||
document.removeChild(this.canvas);
|
||||
// @ts-ignore
|
||||
this.canvas = null;
|
||||
}
|
||||
this.unBindListener();
|
||||
}
|
||||
|
||||
public initModels() {
|
||||
const {
|
||||
update = CanvasUpdateType.AWAYS,
|
||||
} = this.layer.getLayerConfig() as ICanvasLayerStyleOptions;
|
||||
this.updateMode = update as CanvasUpdateType;
|
||||
this.initCanvas();
|
||||
|
||||
this.renderCanvas();
|
||||
|
||||
this.bindListener();
|
||||
|
||||
this.mapService.getContainer();
|
||||
return [];
|
||||
}
|
||||
|
||||
public initCanvas(): void {
|
||||
const { zIndex } = this.layer.getLayerConfig() as ICanvasLayerStyleOptions;
|
||||
const size = this.mapService.getSize();
|
||||
const [width, height] = size;
|
||||
const {
|
||||
width: viewWidth,
|
||||
height: viewHeight,
|
||||
} = this.rendererService.getViewportSize();
|
||||
this.prevSize = [viewWidth, viewHeight];
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
this.canvas = canvas;
|
||||
canvas.width = viewWidth;
|
||||
canvas.height = viewHeight;
|
||||
canvas.style.pointerEvents = 'none';
|
||||
canvas.style.width = width + 'px';
|
||||
canvas.style.height = height + 'px';
|
||||
canvas.style.position = 'absolute';
|
||||
canvas.style.top = '0';
|
||||
canvas.style.left = '0';
|
||||
canvas.style.zIndex = zIndex + '';
|
||||
this.mapService.getContainer()?.appendChild(canvas);
|
||||
|
||||
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
public clearCanvas = () => {
|
||||
if (this.ctx) {
|
||||
const { width: w, height: h } = this.rendererService.getViewportSize();
|
||||
this.ctx.clearRect(0, 0, w, h);
|
||||
}
|
||||
};
|
||||
|
||||
public renderCanvas = () => {
|
||||
const {
|
||||
width: viewWidth,
|
||||
height: viewHeight,
|
||||
} = this.rendererService.getViewportSize();
|
||||
if (this.prevSize[0] !== viewWidth || this.prevSize[1] !== viewHeight) {
|
||||
this.prevSize = [viewWidth, viewHeight];
|
||||
const size = this.mapService.getSize();
|
||||
const [width, height] = size;
|
||||
this.canvas.width = viewWidth;
|
||||
this.canvas.height = viewHeight;
|
||||
this.canvas.style.width = width + 'px';
|
||||
this.canvas.style.height = height + 'px';
|
||||
}
|
||||
|
||||
const {
|
||||
drawingOnCanvas,
|
||||
} = this.layer.getLayerConfig() as ICanvasLayerStyleOptions;
|
||||
|
||||
if (this.ctx) {
|
||||
drawingOnCanvas(this.ctx, this.mapService, [viewWidth, viewHeight]);
|
||||
}
|
||||
};
|
||||
|
||||
public buildModels() {
|
||||
return this.initModels();
|
||||
}
|
||||
|
||||
protected registerBuiltinAttributes() {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import CanvasModel from './canvas';
|
||||
export type CanvasModelType = 'canvas';
|
||||
|
||||
const CanvasModels: { [key in CanvasModelType]: any } = {
|
||||
canvas: CanvasModel,
|
||||
};
|
||||
|
||||
export default CanvasModels;
|
|
@ -1118,6 +1118,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
this.hooks.beforeRender.call();
|
||||
this.layerModelNeedUpdate = false;
|
||||
}
|
||||
|
||||
if (this.layerModel.renderUpdate) {
|
||||
this.layerModel.renderUpdate();
|
||||
}
|
||||
this.models.forEach((model) => {
|
||||
model.draw(
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IAnimateOption } from '@antv/l7-core';
|
||||
import { IAnimateOption, IMapService } from '@antv/l7-core';
|
||||
import { generateColorRamp, getMask, IColorRamp } from '@antv/l7-utils';
|
||||
import { styleColor, styleOffset, styleSingle } from '../core/BaseModel';
|
||||
import {
|
||||
|
@ -106,6 +106,20 @@ export interface IImageLayerStyleOptions {
|
|||
maskInside?: boolean;
|
||||
}
|
||||
|
||||
export enum CanvasUpdateType {
|
||||
'AWAYS' = 'aways',
|
||||
'DRAGEND' = 'dragend',
|
||||
}
|
||||
export interface ICanvasLayerStyleOptions {
|
||||
zIndex: number;
|
||||
update: CanvasUpdateType | string;
|
||||
drawingOnCanvas: (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
mapService: IMapService,
|
||||
size: [number, number],
|
||||
) => void;
|
||||
}
|
||||
|
||||
export interface IHeatMapLayerStyleOptions {
|
||||
opacity: number;
|
||||
intensity: number;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { container, ILayerPlugin, TYPES } from '@antv/l7-core';
|
||||
import CanvasLayer from './canvas';
|
||||
import CityBuildingLayer from './citybuliding/building';
|
||||
import BaseLayer from './core/BaseLayer';
|
||||
import './glsl.d';
|
||||
|
@ -141,6 +142,7 @@ export {
|
|||
PolygonLayer,
|
||||
LineLayer,
|
||||
CityBuildingLayer,
|
||||
CanvasLayer,
|
||||
ImageLayer,
|
||||
ImageTileLayer,
|
||||
RasterLayer,
|
||||
|
|
|
@ -91,6 +91,7 @@ export default class L7EarthService implements IEarthService<Map> {
|
|||
}
|
||||
public off(type: string, handle: (...args: any[]) => void): void {
|
||||
this.map.off(EventMap[type] || type, handle);
|
||||
this.eventEmitter.off(type, handle);
|
||||
}
|
||||
|
||||
public getContainer(): HTMLElement | null {
|
||||
|
|
|
@ -86,6 +86,7 @@ export default class L7MapService implements IMapService<Map> {
|
|||
}
|
||||
public off(type: string, handle: (...args: any[]) => void): void {
|
||||
this.map.off(EventMap[type] || type, handle);
|
||||
this.eventEmitter.off(type, handle);
|
||||
}
|
||||
|
||||
public getContainer(): HTMLElement | null {
|
||||
|
|
|
@ -94,6 +94,7 @@ export default class MapboxService
|
|||
}
|
||||
public off(type: string, handle: (...args: any[]) => void): void {
|
||||
this.map.off(EventMap[type] || type, handle);
|
||||
this.eventEmitter.off(type, handle);
|
||||
}
|
||||
|
||||
public getContainer(): HTMLElement | null {
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
import { CanvasLayer, Scene, IMapService } from '@antv/l7';
|
||||
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Demo extends React.Component {
|
||||
// @ts-ignore
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
// map: new Mapbox({
|
||||
pitch: 0,
|
||||
// style: 'dark',
|
||||
center: [96.99215001469588, 29.281597225674773],
|
||||
zoom: 2.194613775109773,
|
||||
}),
|
||||
});
|
||||
this.scene = scene;
|
||||
|
||||
scene.on('loaded', () => {
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/basement_prod/337ddbb7-aa3f-4679-ab60-d64359241955.json',
|
||||
)
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
const layer = new CanvasLayer({}).style({
|
||||
zIndex: 10,
|
||||
update: 'aways',
|
||||
// update: 'dragend',
|
||||
drawingOnCanvas: (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
mapService: IMapService,
|
||||
size: [number, number],
|
||||
) => {
|
||||
const [width, height] = size;
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.fillStyle = 'rgba(0, 200, 0, 0.2)';
|
||||
data.features.map((feature: any) => {
|
||||
let pixelCenter = mapService.lngLatToContainer(
|
||||
feature.geometry.coordinates,
|
||||
);
|
||||
pixelCenter.x *= window.devicePixelRatio;
|
||||
pixelCenter.y *= window.devicePixelRatio;
|
||||
if (
|
||||
pixelCenter.x < 0 ||
|
||||
pixelCenter.y < 0 ||
|
||||
pixelCenter.x > width ||
|
||||
pixelCenter.y > height
|
||||
)
|
||||
return;
|
||||
ctx.beginPath();
|
||||
ctx.arc(
|
||||
pixelCenter.x,
|
||||
pixelCenter.y,
|
||||
feature.properties.capacity / 200,
|
||||
0,
|
||||
Math.PI * 2,
|
||||
);
|
||||
ctx.fill();
|
||||
ctx.closePath();
|
||||
});
|
||||
},
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
setTimeout(() => {
|
||||
console.log('reSet');
|
||||
layer.style({
|
||||
update: 'dragend',
|
||||
});
|
||||
scene.render();
|
||||
}, 3000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,9 +4,11 @@ import Water from './components/water';
|
|||
import Ocean from './components/ocean';
|
||||
import Taifong from './components/taifeng'
|
||||
import Radar from './components/radar';
|
||||
import CanvasDemo from './components/canvas';
|
||||
|
||||
storiesOf('Object', module)
|
||||
.add('water', () => <Water />)
|
||||
.add('Ocean', () => <Ocean />)
|
||||
.add('Taifong', () => <Taifong />)
|
||||
.add('Radar', () => <Radar/>)
|
||||
.add('Radar', () => <Radar/>)
|
||||
.add('CanvasDemo', () => <CanvasDemo/>)
|
Loading…
Reference in New Issue