diff --git a/docs/api/layer/layer.zh.md b/docs/api/layer/layer.zh.md index bf4a3519bd..dd75034d6a 100644 --- a/docs/api/layer/layer.zh.md +++ b/docs/api/layer/layer.zh.md @@ -24,6 +24,10 @@ new Layer(option) ## 配置项 +### name + +设置图层名称,可根据 name 获取 layer; + ### visable 图层是否可见   {bool } default true @@ -40,6 +44,15 @@ new Layer(option) 图层显示最大缩放等级 (0-18)   {number}  default 18 +### blend + +图层元素混合效果 + +- normal 正常效果 默认 +- additive 叠加模式 +- subtractive 相减模式 +- max 最大值 + # 方法 ### source @@ -284,6 +297,13 @@ scene.render(); layer.setData(data); ``` +### setBlend(type) + +设置图层叠加方法 +参数: + +- type blend 类型 + ## 图层控制方法 ### show @@ -422,3 +442,13 @@ layer.on('unmousedown', (ev) => {}); // 图层外单击按下时触发 layer.on('uncontextmenu', (ev) => {}); // 图层外点击右键 layer.on('unpick', (ev) => {}); // 图层外的操作的所有事件 ``` + +## 图层事件 + +### inited + +图层初始化完成后触发 + +### remove + +图层移除时触发 diff --git a/packages/core/src/services/config/ConfigService.ts b/packages/core/src/services/config/ConfigService.ts index cb1db914a9..4ff7d497ad 100644 --- a/packages/core/src/services/config/ConfigService.ts +++ b/packages/core/src/services/config/ConfigService.ts @@ -50,6 +50,7 @@ const defaultLayerConfig: Partial = { visible: true, autoFit: false, zIndex: 0, + blend: 'normal', pickedFeatureID: -1, enableMultiPassRenderer: true, enablePicking: true, diff --git a/packages/core/src/services/layer/ILayerService.ts b/packages/core/src/services/layer/ILayerService.ts index 81b7339f36..b376a83104 100644 --- a/packages/core/src/services/layer/ILayerService.ts +++ b/packages/core/src/services/layer/ILayerService.ts @@ -3,7 +3,11 @@ import { SyncBailHook, SyncHook, SyncWaterfallHook } from 'tapable'; import Clock from '../../utils/clock'; import { ISceneConfig } from '../config/IConfigService'; import { IMapService } from '../map/IMapService'; -import { IModel, IModelInitializationOptions } from '../renderer/IModel'; +import { + IBlendOptions, + IModel, + IModelInitializationOptions, +} from '../renderer/IModel'; import { IMultiPassRenderer, IPass, @@ -22,6 +26,16 @@ import { StyleAttributeOption, Triangulation, } from './IStyleAttributeService'; +export enum BlendType { + normal = 'normal', + additive = 'additive', + subtractive = 'subtractive', + min = 'min', + max = 'max', +} +export interface IBlendTypes { + [key: string]: Partial; +} export interface IDataState { dataSourceNeedUpdate: boolean; dataMappingNeedUpdate: boolean; @@ -38,6 +52,7 @@ export interface ILayerModelInitializationOptions { export interface ILayerModel { render(): void; getUninforms(): IModelUniform; + getBlend(): IBlendOptions; buildModels(): IModel[]; } export interface IModelUniform { @@ -57,7 +72,8 @@ export interface IActiveOption { export interface ILayer { id: string; // 一个场景中同一类型 Layer 可能存在多个 - name: string; // 代表 Layer 的类型 + type: string; // 代表 Layer 的类型 + name: string; // inited: boolean; // 是否初始化完成 zIndex: number; plugins: ILayerPlugin[]; @@ -120,6 +136,7 @@ export interface ILayer { isVisible(): boolean; setMaxZoom(min: number): ILayer; setMinZoom(max: number): ILayer; + setBlend(type: keyof typeof BlendType): void; // animate(field: string, option: any): ILayer; render(): ILayer; destroy(): void; @@ -190,6 +207,8 @@ export interface ILayerConfig { visible: boolean; zIndex: number; autoFit: boolean; + name: string; // + blend: keyof typeof BlendType; pickedFeatureID: number; enableMultiPassRenderer: boolean; passes: Array; diff --git a/packages/core/src/services/layer/LayerService.ts b/packages/core/src/services/layer/LayerService.ts index d2afaebf07..fa9125e758 100644 --- a/packages/core/src/services/layer/LayerService.ts +++ b/packages/core/src/services/layer/LayerService.ts @@ -38,8 +38,8 @@ export default class LayerService implements ILayerService { return this.layers; } - public getLayer(id: string): ILayer | undefined { - return this.layers.find((layer) => layer.id === id); + public getLayer(name: string): ILayer | undefined { + return this.layers.find((layer) => layer.name === name); } public remove(layer: ILayer): void { @@ -47,6 +47,7 @@ export default class LayerService implements ILayerService { if (layerIndex > -1) { this.layers.splice(layerIndex, 1); } + layer.emit('remove', null); layer.destroy(); this.renderLayers(); } diff --git a/packages/core/src/services/log/LogService.ts b/packages/core/src/services/log/LogService.ts index 3deb2005ec..e648b11c28 100644 --- a/packages/core/src/services/log/LogService.ts +++ b/packages/core/src/services/log/LogService.ts @@ -4,7 +4,7 @@ import { ILogService } from './ILogService'; const Logger = new Log({ id: 'L7' }).enable(true); // // 只输出 debug 级别以上的日志信息 -Logger.priority = 4; +Logger.priority = 5; @injectable() export default class LogService implements ILogService { diff --git a/packages/core/src/services/renderer/IModel.ts b/packages/core/src/services/renderer/IModel.ts index 10eb40de0e..7606932486 100644 --- a/packages/core/src/services/renderer/IModel.ts +++ b/packages/core/src/services/renderer/IModel.ts @@ -3,6 +3,30 @@ import { IAttribute } from './IAttribute'; import { IElements } from './IElements'; import { IUniform } from './IUniform'; +export interface IBlendOptions { + // gl.enable(gl.BLEND) + enable: boolean; + // gl.blendFunc + func: BlendingFunctionSeparate; + // gl.blendEquation + equation: { + // TODO: EXT_blend_minmax + rgb: + | gl.FUNC_ADD + | gl.FUNC_SUBTRACT + | gl.FUNC_REVERSE_SUBTRACT + | gl.MIN_EXT + | gl.MAX_EXT; + alpha?: + | gl.FUNC_ADD + | gl.FUNC_SUBTRACT + | gl.FUNC_REVERSE_SUBTRACT + | gl.MIN_EXT + | gl.MAX_EXT; + }; + // gl.blendColor + color: [number, number, number, number]; +} type stencilOp = | gl.ZERO | gl.KEEP @@ -153,20 +177,7 @@ export interface IModelInitializationOptions { /** * blending */ - blend?: Partial<{ - // gl.enable(gl.BLEND) - enable: boolean; - // gl.blendFunc - func: BlendingFunctionSeparate; - // gl.blendEquation - equation: { - // TODO: EXT_blend_minmax - rgb: gl.FUNC_ADD | gl.FUNC_SUBTRACT | gl.FUNC_REVERSE_SUBTRACT; - alpha: gl.FUNC_ADD | gl.FUNC_SUBTRACT | gl.FUNC_REVERSE_SUBTRACT; - }; - // gl.blendColor - color: [number, number, number, number]; - }>; + blend?: Partial; /** * stencil @@ -221,6 +232,8 @@ export interface IModelDrawOptions { [key: string]: IAttribute; }; elements?: IElements; + + blend?: IBlendOptions; } /** diff --git a/packages/core/src/services/renderer/gl.ts b/packages/core/src/services/renderer/gl.ts index 37bdcd96b4..8238266d07 100644 --- a/packages/core/src/services/renderer/gl.ts +++ b/packages/core/src/services/renderer/gl.ts @@ -60,6 +60,10 @@ export enum gl { FUNC_SUBTRACT = 0x800a, FUNC_REVERSE_SUBTRACT = 0x800b, + /** Blend Min Max */ + MAX_EXT = 0x8008, + MIN_EXT = 0x8007, + /* Separate Blend Functions */ BLEND_DST_RGB = 0x80c8, BLEND_SRC_RGB = 0x80c9, diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index 4a2f628691..3f752ad676 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -1,4 +1,5 @@ import { + BlendType, gl, IActiveOption, IAnimateOption, @@ -34,10 +35,9 @@ import { ScaleTypes, StyleAttributeField, StyleAttributeOption, - TYPES, + TYPES } from '@antv/l7-core'; import Source from '@antv/l7-source'; -import { bindAll } from '@antv/l7-utils'; import { EventEmitter } from 'eventemitter3'; import { Container } from 'inversify'; import { isFunction, isObject } from 'lodash'; @@ -45,6 +45,7 @@ import { isFunction, isObject } from 'lodash'; import mergeJsonSchemas from 'merge-json-schemas'; import { SyncBailHook, SyncHook, SyncWaterfallHook } from 'tapable'; import { normalizePasses } from '../plugins/MultiPassRendererPlugin'; +import { BlendTypes } from '../utils/blend'; import baseLayerSchema from './schema'; /** * 分配 layer id @@ -55,6 +56,7 @@ export default class BaseLayer extends EventEmitter implements ILayer { public id: string = `${layerIdCounter++}`; public name: string; + public type: string; public visible: boolean = true; public zIndex: number = 0; public minZoom: number; @@ -165,6 +167,7 @@ export default class BaseLayer extends EventEmitter constructor(config: Partial = {}) { super(); + this.name = config.name || this.id; this.rawConfig = config; } @@ -299,6 +302,7 @@ export default class BaseLayer extends EventEmitter this.buildModels(); // 触发初始化完成事件; this.emit('inited'); + this.emit('added'); return this; } @@ -514,10 +518,18 @@ export default class BaseLayer extends EventEmitter this.interactionService.triggerSelect(id); } } + public setBlend(type: keyof typeof BlendType): void { + this.updateLayerConfig({ + blend: type, + }); + this.layerModelNeedUpdate = true; + this.render(); + } public show(): ILayer { this.updateLayerConfig({ visible: true, }); + return this; } @@ -685,15 +697,7 @@ export default class BaseLayer extends EventEmitter fs, vs, elements, - blend: { - enable: true, - func: { - srcRGB: gl.SRC_ALPHA, - srcAlpha: 1, - dstRGB: gl.ONE_MINUS_SRC_ALPHA, - dstAlpha: 1, - }, - }, + blend: BlendTypes[BlendType.normal], ...rest, }); } diff --git a/packages/layers/src/core/BaseModel.ts b/packages/layers/src/core/BaseModel.ts index 994f208b42..f21ae3b67e 100644 --- a/packages/layers/src/core/BaseModel.ts +++ b/packages/layers/src/core/BaseModel.ts @@ -1,5 +1,7 @@ import { + BlendType, IAttribute, + IBlendOptions, ICameraService, IElements, IFontService, @@ -17,7 +19,7 @@ import { Triangulation, TYPES, } from '@antv/l7-core'; - +import { BlendTypes } from '../utils/blend'; export default class BaseModel implements ILayerModel { public triangulation: Triangulation; @@ -54,7 +56,10 @@ export default class BaseModel implements ILayerModel { .get(TYPES.ICameraService); this.registerBuiltinAttributes(); } - + public getBlend(): IBlendOptions { + const { blend = 'normal' } = this.layer.getLayerConfig(); + return BlendTypes[BlendType[blend]] as IBlendOptions; + } public getUninforms(): IModelUniform { throw new Error('Method not implemented.'); } diff --git a/packages/layers/src/heatmap/index.ts b/packages/layers/src/heatmap/index.ts index d350dda55d..f10463232b 100644 --- a/packages/layers/src/heatmap/index.ts +++ b/packages/layers/src/heatmap/index.ts @@ -5,7 +5,7 @@ interface IPointLayerStyleOptions { opacity: number; } export default class HeatMapLayer extends BaseLayer { - public name: string = 'HeatMapLayer'; + public type: string = 'HeatMapLayer'; protected getConfigSchema() { return { properties: { diff --git a/packages/layers/src/line/dash.ts b/packages/layers/src/line/dash.ts index 2154e03a9f..212e7ba0bd 100644 --- a/packages/layers/src/line/dash.ts +++ b/packages/layers/src/line/dash.ts @@ -10,7 +10,7 @@ interface IDashLineLayerStyleOptions { export default class DashLineLayer extends BaseLayer< IDashLineLayerStyleOptions > { - public name: string = 'LineLayer'; + public type: string = 'LineLayer'; protected getConfigSchema() { return { diff --git a/packages/layers/src/line/index.ts b/packages/layers/src/line/index.ts index f46c4270b5..5a6b613e71 100644 --- a/packages/layers/src/line/index.ts +++ b/packages/layers/src/line/index.ts @@ -4,7 +4,7 @@ interface IPointLayerStyleOptions { opacity: number; } export default class LineLayer extends BaseLayer { - public name: string = 'LineLayer'; + public type: string = 'LineLayer'; private animateStartTime: number = 0; diff --git a/packages/layers/src/point/index.ts b/packages/layers/src/point/index.ts index 300bc1bfb2..62fd5bdea3 100644 --- a/packages/layers/src/point/index.ts +++ b/packages/layers/src/point/index.ts @@ -7,7 +7,7 @@ interface IPointLayerStyleOptions { strokeColor: string; } export default class PointLayer extends BaseLayer { - public name: string = 'PointLayer'; + public type: string = 'PointLayer'; protected getConfigSchema() { return { properties: { diff --git a/packages/layers/src/point/models/normal.ts b/packages/layers/src/point/models/normal.ts index 987a3924ee..c0ea63c2e6 100644 --- a/packages/layers/src/point/models/normal.ts +++ b/packages/layers/src/point/models/normal.ts @@ -1,5 +1,6 @@ import { AttributeType, + BlendType, gl, IEncodeFeature, IModel, @@ -8,9 +9,9 @@ import { import { rgb2arr } from '@antv/l7-utils'; import BaseModel from '../../core/BaseModel'; +import { BlendTypes } from '../../utils/blend'; import normalFrag from '../shaders/normal_frag.glsl'; import normalVert from '../shaders/normal_vert.glsl'; - interface IPointLayerStyleOptions { opacity: number; strokeWidth: number; @@ -38,7 +39,6 @@ export default class NormalModel extends BaseModel { u_stroke_color: rgb2arr(strokeColor), }; } - public buildModels(): IModel[] { return [ this.layer.buildLayerModel({ @@ -48,15 +48,7 @@ export default class NormalModel extends BaseModel { triangulation: PointTriangulation, depth: { enable: false }, primitive: gl.POINTS, - blend: { - enable: true, - func: { - srcRGB: gl.ONE, - srcAlpha: 1, - dstRGB: gl.ONE, - dstAlpha: 1, - }, - }, + blend: this.getBlend(), }), ]; } diff --git a/packages/layers/src/point/text.ts b/packages/layers/src/point/text.ts index 1e68a913e3..becc151b72 100644 --- a/packages/layers/src/point/text.ts +++ b/packages/layers/src/point/text.ts @@ -26,7 +26,7 @@ export function PointTriangulation(feature: IEncodeFeature) { }; } export default class TextLayer extends BaseLayer { - public name: string = 'PointLayer'; + public type: string = 'PointLayer'; protected getConfigSchema() { return { diff --git a/packages/layers/src/polygon/index.ts b/packages/layers/src/polygon/index.ts index 9957cfbfde..9e0dbd380b 100644 --- a/packages/layers/src/polygon/index.ts +++ b/packages/layers/src/polygon/index.ts @@ -7,7 +7,7 @@ interface IPolygonLayerStyleOptions { } export default class PolygonLayer extends BaseLayer { - public name: string = 'PolygonLayer'; + public type: string = 'PolygonLayer'; protected getConfigSchema() { return { diff --git a/packages/layers/src/raster/image.ts b/packages/layers/src/raster/image.ts index 3c5ac1b8af..ad48fcf4c9 100644 --- a/packages/layers/src/raster/image.ts +++ b/packages/layers/src/raster/image.ts @@ -14,7 +14,7 @@ interface IPointLayerStyleOptions { } export default class ImageLayer extends BaseLayer { - public name: string = 'ImageLayer'; + public type: string = 'ImageLayer'; protected texture: ITexture2D; protected getConfigSchema() { diff --git a/packages/layers/src/raster/raster.ts b/packages/layers/src/raster/raster.ts index b8035e2ab6..1aaea3c4bd 100644 --- a/packages/layers/src/raster/raster.ts +++ b/packages/layers/src/raster/raster.ts @@ -26,7 +26,7 @@ interface IRasterLayerStyleOptions { } export default class RasterLayer extends BaseLayer { - public name: string = 'e'; + public type: string = 'RasterLayer'; protected texture: ITexture2D; protected colorTexture: ITexture2D; diff --git a/packages/layers/src/raster/raster2d.ts b/packages/layers/src/raster/raster2d.ts index f82581ffbb..17ca71129b 100644 --- a/packages/layers/src/raster/raster2d.ts +++ b/packages/layers/src/raster/raster2d.ts @@ -12,7 +12,7 @@ interface IRasterLayerStyleOptions { } export default class Raster2dLayer extends BaseLayer { - public name: string = 'RasterLayer'; + public type: string = 'RasterLayer'; protected texture: ITexture2D; protected colorTexture: ITexture2D; diff --git a/packages/layers/src/utils/blend.ts b/packages/layers/src/utils/blend.ts new file mode 100644 index 0000000000..e209a58b8d --- /dev/null +++ b/packages/layers/src/utils/blend.ts @@ -0,0 +1,54 @@ +import { BlendType, gl, IBlendOptions, IBlendTypes } from '@antv/l7-core'; +export const BlendTypes: IBlendTypes = { + [BlendType.additive]: { + enable: true, + func: { + srcRGB: gl.ONE, + dstRGB: gl.ONE, + srcAlpha: 1, + dstAlpha: 1, + }, + }, + [BlendType.normal]: { + enable: true, + func: { + srcRGB: gl.SRC_ALPHA, + dstRGB: gl.ONE_MINUS_SRC_ALPHA, + srcAlpha: 1, + dstAlpha: 1, + }, + }, + [BlendType.subtractive]: { + enable: true, + func: { + srcRGB: gl.ONE, + dstRGB: gl.ONE, + srcAlpha: gl.ZERO, + dstAlpha: gl.ONE_MINUS_SRC_COLOR, + }, + equation: { + rgb: gl.FUNC_SUBTRACT, + alpha: gl.FUNC_SUBTRACT, + }, + }, + [BlendType.max]: { + enable: true, + func: { + srcRGB: gl.ONE, + dstRGB: gl.ONE, + }, + equation: { + rgb: gl.MAX_EXT, + }, + }, + [BlendType.min]: { + enable: true, + func: { + srcRGB: gl.ONE, + dstRGB: gl.ONE, + }, + equation: { + rgb: gl.MIN_EXT, + }, + }, +}; diff --git a/packages/maps/src/mapbox/index.ts b/packages/maps/src/mapbox/index.ts index 32377cea34..95786ec2f7 100644 --- a/packages/maps/src/mapbox/index.ts +++ b/packages/maps/src/mapbox/index.ts @@ -204,7 +204,7 @@ export default class MapboxService */ // 判断全局 mapboxgl 对象的加载 - if (!('mapInstance' in this.config) && !mapboxgl) { + if (!mapInstance && !mapboxgl) { // 用户有时传递进来的实例是继承于 mapbox 实例化的,不一定是 mapboxgl 对象。 this.logger.error(this.configService.getSceneWarninfo('SDK')); } @@ -213,13 +213,13 @@ export default class MapboxService token === MAPBOX_API_KEY && style !== 'blank' && !mapboxgl.accessToken && - !('mapInstance' in this.config) // 如果用户传递了 mapInstance,应该不去干预实例的 accessToken。 + !mapInstance // 如果用户传递了 mapInstance,应该不去干预实例的 accessToken。 ) { this.logger.warn(this.configService.getSceneWarninfo('MapToken')); } // 判断是否设置了 accessToken - if ('mapInstance' in this.config && !mapboxgl.accessToken) { + if (!mapInstance && !mapboxgl.accessToken) { // 用户有时传递进来的实例是继承于 mapbox 实例化的,不一定是 mapboxgl 对象。 mapboxgl.accessToken = token; } diff --git a/packages/renderer/src/regl/constants.ts b/packages/renderer/src/regl/constants.ts index f5696cc22d..a79d3a1a54 100644 --- a/packages/renderer/src/regl/constants.ts +++ b/packages/renderer/src/regl/constants.ts @@ -141,6 +141,8 @@ export const blendEquationMap: { [key: string]: regl.BlendingEquation; } = { [gl.FUNC_ADD]: 'add', + [gl.MIN_EXT]: 'min', + [gl.MAX_EXT]: 'max', [gl.FUNC_SUBTRACT]: 'subtract', [gl.FUNC_REVERSE_SUBTRACT]: 'reverse subtract', }; diff --git a/packages/renderer/src/regl/index.ts b/packages/renderer/src/regl/index.ts index 50697320f6..7b3f0bb968 100644 --- a/packages/renderer/src/regl/index.ts +++ b/packages/renderer/src/regl/index.ts @@ -53,6 +53,7 @@ export default class ReglRendererService implements IRendererService { extensions: [ 'OES_element_index_uint', // 'EXT_shader_texture_lod', // IBL 兼容性问题 + 'EXT_blend_minmax', 'OES_standard_derivatives', // wireframe // 'OES_texture_float', // shadow map 兼容性问题 'WEBGL_depth_texture', diff --git a/stories/Layers/Layers.stories.tsx b/stories/Layers/Layers.stories.tsx index 3800e9eae3..7def7130ca 100644 --- a/stories/Layers/Layers.stories.tsx +++ b/stories/Layers/Layers.stories.tsx @@ -5,6 +5,7 @@ import ArcLineDemo from './components/Arcline'; import Column from './components/column'; import DataUpdate from './components/data_update'; import HeatMapDemo from './components/HeatMap'; +import LightDemo from './components/light'; import LineLayer from './components/Line'; import PointDemo from './components/Point'; import Point3D from './components/Point3D'; @@ -17,6 +18,7 @@ import RasterLayerDemo from './components/RasterLayer'; storiesOf('图层', module) .add('点图层', () => ) .add('数据更新', () => ) + .add('亮度图', () => ) .add('3D点', () => ) .add('Column', () => ) .add('图片标注', () => ) diff --git a/stories/Layers/components/light.tsx b/stories/Layers/components/light.tsx new file mode 100644 index 0000000000..be9087972d --- /dev/null +++ b/stories/Layers/components/light.tsx @@ -0,0 +1,65 @@ +import { PointLayer, Scene } from '@antv/l7'; +import { GaodeMap, Mapbox } from '@antv/l7-maps'; +import * as React from 'react'; +// @ts-ignore +export default class Light extends React.Component { + // @ts-ignore + private scene: Scene; + + public componentWillUnmount() { + this.scene.destroy(); + } + + public async componentDidMount() { + const response = await fetch( + 'https://alipay-rmsdeploy-image.cn-hangzhou.alipay.aliyun-inc.com/antvdemo/assets/city/bj.csv', + ); + const pointsData = await response.text(); + + const scene = new Scene({ + id: 'map', + map: new Mapbox({ + pitch: 0, + style: 'dark', + center: [116.405289, 39.904987], + zoom: 6, + }), + }); + this.scene = scene; + scene.on('loaded', async () => { + const pointLayer = new PointLayer({ + blend: 'min', + }) + .source(pointsData, { + parser: { + type: 'csv', + x: 'lng', + y: 'lat', + }, + }) + .size(2) + .color("#FFFECC") + .style({ + opacity: 1, + }); + + scene.addLayer(pointLayer); + this.scene = scene; + }); + } + + public render() { + return ( +
+ ); + } +}