diff --git a/docs/api/layer/point_layer/cluster.zh.md b/docs/api/layer/point_layer/cluster.zh.md index e61f0e4fc5..014d341e42 100644 --- a/docs/api/layer/point_layer/cluster.zh.md +++ b/docs/api/layer/point_layer/cluster.zh.md @@ -43,7 +43,7 @@ order: 5 layer.source(pointsData, { cluster: true, }); - + // 设置配置项 layer.source(pointsData, { cluster: true, diff --git a/docs/api/map.en.md b/docs/api/map.en.md index fcc8748431..f749276df8 100644 --- a/docs/api/map.en.md +++ b/docs/api/map.en.md @@ -5,7 +5,7 @@ order: 2 # 简介 -L7 专注数据可视化层数据表达,目前 L7 还不支持独立的地图引擎,需要引入第三方引擎,目前支持 高德地图和 MapBox 两种。 +L7 专注数据可视化层数据表达,目前 L7 还不支持独立的地图引擎,需要引入第三方引擎,目前支持 高德地图和 MapBox 两种。= L7 在内部解决了不同底图地图直接的差异,同时 L7 层面统一管理地图的操作方法。 ## Map @@ -25,6 +25,15 @@ L7 在内部解决了不同底图地图直接的差异,同时 L7 层面统一 #### 高德地图实例化 +高德地图 API 配置参数 + +- token + 注册高德 [API token](https://lbs.amap.com/api/javascript-api/guide/abc/prepare) + +- plugin {array} `['AMap.ElasticMarker','AMap.CircleEditor']` + + 加载[高德地图插件](https://lbs.amap.com/api/javascript-api/guide/abc/plugins) + ```javascript const L7AMap = new GaodeMap({ pitch: 35.210526315789465, @@ -32,6 +41,7 @@ const L7AMap = new GaodeMap({ center: [104.288144, 31.239692], zoom: 4.4, token: 'xxxx - token', + plugin: [], // 可以不设置 }); ``` @@ -59,6 +69,8 @@ const scene = new Scene({ ⚠️ 传入地图实例需要自行引入相关地图的 API +⚠️ viewMode 设置为 3D 模式 + #### 传入高德地图实例 ```javascript @@ -76,6 +88,9 @@ const scene = new Scene({ }); ``` +[示例地址](/zh/examples/tutorial/map#amapInstance) +[代码地址](https://github.com/antvis/L7/blob/master/examples/tutorial/map/demo/amapInstance.js) + #### 传入 Mapbox 地图实例 ```javascript diff --git a/docs/api/map.zh.md b/docs/api/map.zh.md index 4059644cf3..f749276df8 100644 --- a/docs/api/map.zh.md +++ b/docs/api/map.zh.md @@ -25,6 +25,15 @@ L7 在内部解决了不同底图地图直接的差异,同时 L7 层面统一 #### 高德地图实例化 +高德地图 API 配置参数 + +- token + 注册高德 [API token](https://lbs.amap.com/api/javascript-api/guide/abc/prepare) + +- plugin {array} `['AMap.ElasticMarker','AMap.CircleEditor']` + + 加载[高德地图插件](https://lbs.amap.com/api/javascript-api/guide/abc/plugins) + ```javascript const L7AMap = new GaodeMap({ pitch: 35.210526315789465, @@ -32,6 +41,7 @@ const L7AMap = new GaodeMap({ center: [104.288144, 31.239692], zoom: 4.4, token: 'xxxx - token', + plugin: [], // 可以不设置 }); ``` @@ -59,6 +69,8 @@ const scene = new Scene({ ⚠️ 传入地图实例需要自行引入相关地图的 API +⚠️ viewMode 设置为 3D 模式 + #### 传入高德地图实例 ```javascript diff --git a/docs/api/source/json.zh.md b/docs/api/source/json.zh.md index 5ded5808b8..e78a6e6308 100644 --- a/docs/api/source/json.zh.md +++ b/docs/api/source/json.zh.md @@ -187,7 +187,6 @@ layer.source( parser:{ type:'json', coordinates: "coord", - } } }) diff --git a/examples/raster/basic/demo/raster.js b/examples/raster/basic/demo/raster.js new file mode 100644 index 0000000000..5de0bc592e --- /dev/null +++ b/examples/raster/basic/demo/raster.js @@ -0,0 +1,57 @@ +import { RasterLayer, Scene } from '@antv/l7'; +import { GaodeMap } from '@antv/l7-maps'; +import * as GeoTIFF from 'geotiff'; +const scene = new Scene({ + id: 'map', + map: new GaodeMap({ + pitch: 0, + style: 'dark', + center: [ 115.5268, 34.3628 ], + zoom: 3 + }) +}); +addLayer(); +async function getTiffData() { + const response = await fetch( + 'https://gw.alipayobjects.com/os/rmsportal/XKgkjjGaAzRyKupCBiYW.dat' + ); + const arrayBuffer = await response.arrayBuffer(); + const tiff = await GeoTIFF.fromArrayBuffer(arrayBuffer); + const image = await tiff.getImage(); + const width = image.getWidth(); + const height = image.getHeight(); + const values = await image.readRasters(); + return { + data: values[0], + width, + height, + min: 0, + max: 8000 + }; +} + +async function addLayer() { + const tiffdata = await getTiffData(); + + const layer = new RasterLayer({}); + layer + .source(tiffdata.data, { + parser: { + type: 'raster', + width: tiffdata.width, + height: tiffdata.height, + extent: [ 73.482190241, 3.82501784112, 135.106618732, 57.6300459963 ] + } + }) + .style({ + heightRatio: 100, + opacity: 0.8, + domain: [ 0, 8000 ], + rampColors: { + colors: [ '#FF4818', '#F7B74A', '#FFF598', '#91EABC', '#2EA9A1', '#206C7C' ].reverse(), + positions: [ 0, 0.2, 0.4, 0.6, 0.8, 1.0 ] + } + }); + + scene.addLayer(layer); +} diff --git a/packages/core/src/services/config/ConfigService.ts b/packages/core/src/services/config/ConfigService.ts index ea6a0245e2..ccd6e92559 100644 --- a/packages/core/src/services/config/ConfigService.ts +++ b/packages/core/src/services/config/ConfigService.ts @@ -46,7 +46,7 @@ const defaultLayerConfig: Partial = { 'vesica', ], shape3d: ['cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn'], - minZoom: 0, + minZoom: -1, maxZoom: 24, visible: true, autoFit: false, diff --git a/packages/core/src/services/config/__tests__/schema.spec.ts b/packages/core/src/services/config/__tests__/schema.spec.ts index 7e532b9a28..4e44415c10 100644 --- a/packages/core/src/services/config/__tests__/schema.spec.ts +++ b/packages/core/src/services/config/__tests__/schema.spec.ts @@ -40,12 +40,12 @@ describe('ConfigService', () => { const { valid, errorText } = configService.validateMapConfig({ zoom: 100, minZoom: 100, - maxZoom: -1, + maxZoom: -2, }); expect(valid).toBeFalsy(); - expect(errorText).toMatch('zoom should be <= 20'); - expect(errorText).toMatch('minZoom should be <= 20'); - expect(errorText).toMatch('maxZoom should be >= 0'); + expect(errorText).toMatch('zoom should be <= 24'); + expect(errorText).toMatch('minZoom should be <= 24'); + expect(errorText).toMatch('maxZoom should be >= -1'); expect( configService.validateMapConfig({ diff --git a/packages/core/src/services/config/mapConfigSchema.ts b/packages/core/src/services/config/mapConfigSchema.ts index 23dff45d03..05001e3b7d 100644 --- a/packages/core/src/services/config/mapConfigSchema.ts +++ b/packages/core/src/services/config/mapConfigSchema.ts @@ -6,18 +6,18 @@ export default { // 地图缩放等级 zoom: { type: 'number', - minimum: 0, - maximum: 20, + minimum: -1, + maximum: 24, }, minZoom: { type: 'number', - minimum: 0, - maximum: 20, + minimum: -1, + maximum: 24, }, maxZoom: { type: 'number', - minimum: 0, - maximum: 20, + minimum: -1, + maximum: 24, }, // 地图中心点 center: { diff --git a/packages/core/src/services/config/warnInfo.ts b/packages/core/src/services/config/warnInfo.ts index 345a506278..6337797d1c 100644 --- a/packages/core/src/services/config/warnInfo.ts +++ b/packages/core/src/services/config/warnInfo.ts @@ -5,7 +5,7 @@ export interface IWarnInfo { } const WarnInfo: IWarnInfo = { MapToken: - '您正在使用 Demo测试地图token,如果生成环境中使用去对应地图请注册Token', + '您正在使用 Demo测试地图token,如果生产环境中使用去对应地图请注册Token', SDK: '请确认引入了mapbox-gl api且在L7之前引入', }; diff --git a/packages/core/src/services/map/IMapService.ts b/packages/core/src/services/map/IMapService.ts index 8491d24a10..42a41b2a41 100644 --- a/packages/core/src/services/map/IMapService.ts +++ b/packages/core/src/services/map/IMapService.ts @@ -71,6 +71,10 @@ export interface IMapConfig { * 地图实例 */ mapInstance?: RawMap; + /** + * 高德地图API插件 + */ + plugin?: string[]; /** * 容器 DOM id */ diff --git a/packages/layers/src/core/BaseLayer.ts b/packages/layers/src/core/BaseLayer.ts index ce2148ae35..7a5ca9169d 100644 --- a/packages/layers/src/core/BaseLayer.ts +++ b/packages/layers/src/core/BaseLayer.ts @@ -424,7 +424,9 @@ export default class BaseLayer extends EventEmitter this.buildModels(); return this; } - public style(options: object & Partial): ILayer { + public style( + options: Partial & Partial, + ): ILayer { const { passes, ...rest } = options; // passes 特殊处理 @@ -582,7 +584,6 @@ export default class BaseLayer extends EventEmitter } public isVisible(): boolean { const zoom = this.mapService.getZoom(); - const { visible, minZoom = -Infinity, diff --git a/packages/layers/src/core/BaseModel.ts b/packages/layers/src/core/BaseModel.ts index 5e95fe2295..f81c28e342 100644 --- a/packages/layers/src/core/BaseModel.ts +++ b/packages/layers/src/core/BaseModel.ts @@ -11,6 +11,7 @@ import { ILayer, ILayerConfig, ILayerModel, + ILayerService, IMapService, IModel, IModelUniform, @@ -44,6 +45,7 @@ export default class BaseModel protected styleAttributeService: IStyleAttributeService; protected mapService: IMapService; protected cameraService: ICameraService; + protected layerService: ILayerService; constructor(layer: ILayer) { this.layer = layer; @@ -57,6 +59,10 @@ export default class BaseModel this.cameraService = layer .getContainer() .get(TYPES.ICameraService); + this.layerService = layer + .getContainer() + .get(TYPES.ILayerService); + // 注册 Attribute this.registerBuiltinAttributes(); // 开启动画 diff --git a/packages/layers/src/image/index.ts b/packages/layers/src/image/index.ts new file mode 100644 index 0000000000..dccec6301f --- /dev/null +++ b/packages/layers/src/image/index.ts @@ -0,0 +1,35 @@ +import BaseLayer from '../core/BaseLayer'; +import ImageModels, { ImageModelType } from './models/index'; +interface IImageLayerStyleOptions { + opacity: number; +} +export default class ImageLayer extends BaseLayer { + public type: string = 'ImageLayer'; + protected getConfigSchema() { + return { + properties: { + opacity: { + type: 'number', + minimum: 0, + maximum: 1, + }, + }, + }; + } + protected getDefaultConfig() { + const type = this.getModelType(); + const defaultConfig = { + image: {}, + }; + return defaultConfig[type]; + } + protected buildModels() { + const modelType = this.getModelType(); + this.layerModel = new ImageModels[modelType](this); + this.models = this.layerModel.buildModels(); + } + + protected getModelType(): ImageModelType { + return 'image'; + } +} diff --git a/packages/layers/src/image/models/image.ts b/packages/layers/src/image/models/image.ts new file mode 100644 index 0000000000..29bf661046 --- /dev/null +++ b/packages/layers/src/image/models/image.ts @@ -0,0 +1,99 @@ +import { + AttributeType, + gl, + IEncodeFeature, + ILayer, + ILayerPlugin, + ILogService, + IModel, + IModelUniform, + IRasterParserDataItem, + IStyleAttributeService, + ITexture2D, + lazyInject, + TYPES, +} from '@antv/l7-core'; +import { generateColorRamp, IColorRamp } from '@antv/l7-utils'; +import BaseModel from '../../core/BaseModel'; +import { RasterImageTriangulation } from '../../core/triangulation'; +import ImageFrag from '../shaders/image_frag.glsl'; +import ImageVert from '../shaders/image_vert.glsl'; + +interface IImageLayerStyleOptions { + opacity: number; +} +export default class ImageModel extends BaseModel { + protected texture: ITexture2D; + public getUninforms(): IModelUniform { + const { opacity } = this.layer.getLayerConfig() as IImageLayerStyleOptions; + return { + u_opacity: opacity || 1, + u_texture: this.texture, + }; + } + public buildModels() { + const source = this.layer.getSource(); + const { createTexture2D } = this.rendererService; + this.texture = createTexture2D({ + height: 0, + width: 0, + }); + source.data.images.then((imageData: HTMLImageElement[]) => { + this.texture = createTexture2D({ + data: imageData[0], + width: imageData[0].width, + height: imageData[0].height, + }); + this.layerService.renderLayers(); + }); + return [ + this.layer.buildLayerModel({ + moduleName: 'RasterImage', + vertexShader: ImageVert, + fragmentShader: ImageFrag, + triangulation: RasterImageTriangulation, + primitive: gl.TRIANGLES, + depth: { enable: false }, + blend: this.getBlend(), + }), + ]; + } + + protected getConfigSchema() { + return { + properties: { + opacity: { + type: 'number', + minimum: 0, + maximum: 1, + }, + }, + }; + } + + protected registerBuiltinAttributes() { + // point layer size; + this.styleAttributeService.registerStyleAttribute({ + name: 'uv', + type: AttributeType.Attribute, + descriptor: { + name: 'a_Uv', + buffer: { + // give the WebGL driver a hint that this buffer may change + usage: gl.DYNAMIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 2, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + ) => { + return [vertex[3], vertex[4]]; + }, + }, + }); + } +} diff --git a/packages/layers/src/image/models/index.ts b/packages/layers/src/image/models/index.ts new file mode 100644 index 0000000000..d26526bd16 --- /dev/null +++ b/packages/layers/src/image/models/index.ts @@ -0,0 +1,8 @@ +import ImageModel from './image'; +export type ImageModelType = 'image'; + +const ImageModels: { [key in ImageModelType]: any } = { + image: ImageModel, +}; + +export default ImageModels; diff --git a/packages/layers/src/raster/shaders/image_frag.glsl b/packages/layers/src/image/shaders/image_frag.glsl similarity index 100% rename from packages/layers/src/raster/shaders/image_frag.glsl rename to packages/layers/src/image/shaders/image_frag.glsl diff --git a/packages/layers/src/raster/shaders/image_vert.glsl b/packages/layers/src/image/shaders/image_vert.glsl similarity index 100% rename from packages/layers/src/raster/shaders/image_vert.glsl rename to packages/layers/src/image/shaders/image_vert.glsl diff --git a/packages/layers/src/index.ts b/packages/layers/src/index.ts index b5a8435969..b9a487a8b1 100644 --- a/packages/layers/src/index.ts +++ b/packages/layers/src/index.ts @@ -3,11 +3,11 @@ import CityBuildingLayer from './citybuliding/building'; import BaseLayer from './core/BaseLayer'; import './glsl.d'; import HeatmapLayer from './heatmap'; +import ImageLayer from './image'; import LineLayer from './line/index'; import PointLayer from './point'; import PolygonLayer from './polygon'; -import ImageLayer from './raster/image'; -import RasterLayer from './raster/raster'; +import RasterLayer from './raster'; import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin'; import DataMappingPlugin from './plugins/DataMappingPlugin'; diff --git a/packages/layers/src/raster/image.ts b/packages/layers/src/raster/image.ts index 341d1af340..164b9417bb 100644 --- a/packages/layers/src/raster/image.ts +++ b/packages/layers/src/raster/image.ts @@ -1,106 +1,106 @@ -import { - AttributeType, - gl, - IEncodeFeature, - ILayer, - ITexture2D, -} from '@antv/l7-core'; -import BaseLayer from '../core/BaseLayer'; -import { RasterImageTriangulation } from '../core/triangulation'; -import rasterImageFrag from './shaders/image_frag.glsl'; -import rasterImageVert from './shaders/image_vert.glsl'; -interface IRaterLayerStyleOptions { - opacity: number; -} +// import { +// AttributeType, +// gl, +// IEncodeFeature, +// ILayer, +// ITexture2D, +// } from '@antv/l7-core'; +// import BaseLayer from '../core/BaseLayer'; +// import { RasterImageTriangulation } from '../core/triangulation'; +// import rasterImageFrag from './shaders/image_frag.glsl'; +// import rasterImageVert from './shaders/image_vert.glsl'; +// interface IRaterLayerStyleOptions { +// opacity: number; +// } -export default class ImageLayer extends BaseLayer { - public type: string = 'ImageLayer'; - protected texture: ITexture2D; +// export default class ImageLayer extends BaseLayer { +// public type: string = 'ImageLayer'; +// protected texture: ITexture2D; - protected getConfigSchema() { - return { - properties: { - opacity: { - type: 'number', - minimum: 0, - maximum: 1, - }, - }, - }; - } +// protected getConfigSchema() { +// return { +// properties: { +// opacity: { +// type: 'number', +// minimum: 0, +// maximum: 1, +// }, +// }, +// }; +// } - protected renderModels() { - const { opacity } = this.getLayerConfig(); - if (this.texture) { - this.models.forEach((model) => - model.draw({ - uniforms: { - u_opacity: opacity || 1, - u_texture: this.texture, - }, - }), - ); - } +// protected renderModels() { +// const { opacity } = this.getLayerConfig(); +// if (this.texture) { +// this.models.forEach((model) => +// model.draw({ +// uniforms: { +// u_opacity: opacity || 1, +// u_texture: this.texture, +// }, +// }), +// ); +// } - return this; - } +// return this; +// } - protected buildModels() { - this.registerBuiltinAttributes(); - const source = this.getSource(); - const { createTexture2D } = this.rendererService; - source.data.images.then((imageData: HTMLImageElement[]) => { - this.texture = createTexture2D({ - data: imageData[0], - width: imageData[0].width, - height: imageData[0].height, - }); - this.renderModels(); - }); - this.models = [ - this.buildLayerModel({ - moduleName: 'RasterImage', - vertexShader: rasterImageVert, - fragmentShader: rasterImageFrag, - triangulation: RasterImageTriangulation, - primitive: gl.TRIANGLES, - depth: { enable: false }, - blend: { - enable: true, - func: { - srcRGB: gl.SRC_ALPHA, - srcAlpha: 1, - dstRGB: gl.ONE_MINUS_SRC_ALPHA, - dstAlpha: 1, - }, - }, - }), - ]; - } +// protected buildModels() { +// this.registerBuiltinAttributes(); +// const source = this.getSource(); +// const { createTexture2D } = this.rendererService; +// source.data.images.then((imageData: HTMLImageElement[]) => { +// this.texture = createTexture2D({ +// data: imageData[0], +// width: imageData[0].width, +// height: imageData[0].height, +// }); +// this.renderModels(); +// }); +// this.models = [ +// this.buildLayerModel({ +// moduleName: 'RasterImage', +// vertexShader: rasterImageVert, +// fragmentShader: rasterImageFrag, +// triangulation: RasterImageTriangulation, +// primitive: gl.TRIANGLES, +// depth: { enable: false }, +// blend: { +// enable: true, +// func: { +// srcRGB: gl.SRC_ALPHA, +// srcAlpha: 1, +// dstRGB: gl.ONE_MINUS_SRC_ALPHA, +// dstAlpha: 1, +// }, +// }, +// }), +// ]; +// } - private registerBuiltinAttributes() { - // point layer size; - this.styleAttributeService.registerStyleAttribute({ - name: 'uv', - type: AttributeType.Attribute, - descriptor: { - name: 'a_Uv', - buffer: { - // give the WebGL driver a hint that this buffer may change - usage: gl.DYNAMIC_DRAW, - data: [], - type: gl.FLOAT, - }, - size: 2, - update: ( - feature: IEncodeFeature, - featureIdx: number, - vertex: number[], - attributeIdx: number, - ) => { - return [vertex[3], vertex[4]]; - }, - }, - }); - } -} +// private registerBuiltinAttributes() { +// // point layer size; +// this.styleAttributeService.registerStyleAttribute({ +// name: 'uv', +// type: AttributeType.Attribute, +// descriptor: { +// name: 'a_Uv', +// buffer: { +// // give the WebGL driver a hint that this buffer may change +// usage: gl.DYNAMIC_DRAW, +// data: [], +// type: gl.FLOAT, +// }, +// size: 2, +// update: ( +// feature: IEncodeFeature, +// featureIdx: number, +// vertex: number[], +// attributeIdx: number, +// ) => { +// return [vertex[3], vertex[4]]; +// }, +// }, +// }); +// } +// } diff --git a/packages/layers/src/raster/index.ts b/packages/layers/src/raster/index.ts new file mode 100644 index 0000000000..24514ae65b --- /dev/null +++ b/packages/layers/src/raster/index.ts @@ -0,0 +1,42 @@ +import { IColorRamp } from '@antv/l7-utils'; +import BaseLayer from '../core/BaseLayer'; +import RasterModels, { RasterModelType } from './models/index'; +interface IRasterLayerStyleOptions { + opacity: number; + domain: [number, number]; + noDataValue: number; + clampLow: boolean; + clampHigh: boolean; + rampColors: IColorRamp; +} +export default class RaterLayer extends BaseLayer { + public type: string = 'RasterLayer'; + protected getConfigSchema() { + return { + properties: { + opacity: { + type: 'number', + minimum: 0, + maximum: 1, + }, + }, + }; + } + protected getDefaultConfig() { + const type = this.getModelType(); + const defaultConfig = { + raster: {}, + raster3d: {}, + }; + return defaultConfig[type]; + } + protected buildModels() { + const modelType = this.getModelType(); + this.layerModel = new RasterModels[modelType](this); + this.models = this.layerModel.buildModels(); + } + + protected getModelType(): RasterModelType { + return 'raster'; + } +} diff --git a/packages/layers/src/raster/models/index.ts b/packages/layers/src/raster/models/index.ts new file mode 100644 index 0000000000..8a94ccb605 --- /dev/null +++ b/packages/layers/src/raster/models/index.ts @@ -0,0 +1,9 @@ +import RasterModel from './raster'; +export type RasterModelType = 'raster' | 'raster3d'; + +const RasterModels: { [key in RasterModelType]: any } = { + raster: RasterModel, + raster3d: RasterModel, +}; + +export default RasterModels; diff --git a/packages/layers/src/raster/models/raster.ts b/packages/layers/src/raster/models/raster.ts new file mode 100644 index 0000000000..f9e579fb38 --- /dev/null +++ b/packages/layers/src/raster/models/raster.ts @@ -0,0 +1,113 @@ +import { + AttributeType, + gl, + IEncodeFeature, + ILayer, + ILayerPlugin, + ILogService, + IModel, + IModelUniform, + IRasterParserDataItem, + IStyleAttributeService, + ITexture2D, + lazyInject, + TYPES, +} from '@antv/l7-core'; +import { generateColorRamp, IColorRamp } from '@antv/l7-utils'; +import BaseModel from '../../core/BaseModel'; +import { RasterImageTriangulation } from '../../core/triangulation'; +import rasterFrag from '../shaders/raster_2d_frag.glsl'; +import rasterVert from '../shaders/raster_2d_vert.glsl'; + +interface IRasterLayerStyleOptions { + opacity: number; + domain: [number, number]; + noDataValue: number; + clampLow: boolean; + clampHigh: boolean; + rampColors: IColorRamp; +} +export default class RasterModel extends BaseModel { + protected texture: ITexture2D; + protected colorTexture: ITexture2D; + public getUninforms() { + const { + opacity = 1, + clampLow = true, + clampHigh = true, + noDataValue = -9999999, + domain = [0, 1], + } = this.layer.getLayerConfig() as IRasterLayerStyleOptions; + + return { + u_opacity: opacity || 1, + u_texture: this.texture, + u_domain: domain, + u_clampLow: clampLow, + u_clampHigh: typeof clampHigh !== 'undefined' ? clampHigh : clampLow, + u_noDataValue: noDataValue, + u_colorTexture: this.colorTexture, + }; + } + + public buildModels() { + const source = this.layer.getSource(); + const { createTexture2D } = this.rendererService; + const parserDataItem = source.data.dataArray[0]; + this.texture = createTexture2D({ + data: parserDataItem.data, + width: parserDataItem.width, + height: parserDataItem.height, + format: gl.LUMINANCE, + type: gl.FLOAT, + // aniso: 4, + }); + const { + rampColors, + } = this.layer.getLayerConfig() as IRasterLayerStyleOptions; + const imageData = generateColorRamp(rampColors as IColorRamp); + this.colorTexture = createTexture2D({ + data: imageData.data, + width: imageData.width, + height: imageData.height, + flipY: true, + }); + return [ + this.layer.buildLayerModel({ + moduleName: 'RasterImageData', + vertexShader: rasterVert, + fragmentShader: rasterFrag, + triangulation: RasterImageTriangulation, + primitive: gl.TRIANGLES, + depth: { enable: false }, + blend: this.getBlend(), + }), + ]; + } + + protected registerBuiltinAttributes() { + // point layer size; + this.styleAttributeService.registerStyleAttribute({ + name: 'uv', + type: AttributeType.Attribute, + descriptor: { + name: 'a_Uv', + buffer: { + // give the WebGL driver a hint that this buffer may change + usage: gl.DYNAMIC_DRAW, + data: [], + type: gl.FLOAT, + }, + size: 2, + update: ( + feature: IEncodeFeature, + featureIdx: number, + vertex: number[], + attributeIdx: number, + ) => { + return [vertex[3], vertex[4]]; + }, + }, + }); + } +} diff --git a/packages/layers/src/raster/raster.ts b/packages/layers/src/raster/raster.ts index 1aaea3c4bd..45fb71957c 100644 --- a/packages/layers/src/raster/raster.ts +++ b/packages/layers/src/raster/raster.ts @@ -5,12 +5,14 @@ import { ILayer, ILayerPlugin, ILogService, + IModelUniform, IRasterParserDataItem, IStyleAttributeService, ITexture2D, lazyInject, TYPES, } from '@antv/l7-core'; + import { generateColorRamp, IColorRamp } from '@antv/l7-utils'; import BaseLayer from '../core/BaseLayer'; import { RasterTriangulation } from './buffers/triangulation'; @@ -30,6 +32,9 @@ export default class RasterLayer extends BaseLayer { protected texture: ITexture2D; protected colorTexture: ITexture2D; + public getAnimateUniforms(): IModelUniform { + return {}; + } protected getConfigSchema() { return { properties: { diff --git a/packages/layers/src/raster/shaders/raster_2d_frag.glsl b/packages/layers/src/raster/shaders/raster_2d_frag.glsl index b2be740612..7819b12ed9 100644 --- a/packages/layers/src/raster/shaders/raster_2d_frag.glsl +++ b/packages/layers/src/raster/shaders/raster_2d_frag.glsl @@ -4,15 +4,26 @@ uniform sampler2D u_texture; uniform sampler2D u_colorTexture; uniform float u_min; uniform float u_max; +uniform vec2 u_domain; +uniform float u_noDataValue; +uniform bool u_clampLow: true; +uniform bool u_clampHigh: true; varying vec2 v_texCoord; void main() { - float value = texture2D(u_texture,vec2(v_texCoord.x,v_texCoord.y)).a; - value = clamp(value,u_min,u_max); - float value1 = (value - u_min) / (u_max -u_min); - vec2 ramp_pos = vec2( - fract(16.0 * (1.0 - value1)), - floor(16.0 * (1.0 - value1)) / 16.0); - gl_FragColor = texture2D(u_colorTexture,ramp_pos);; + float value = texture2D(u_texture,vec2(v_texCoord.x,v_texCoord.y)).r; + if (value == u_noDataValue) + gl_FragColor = vec4(0.0, 0, 0, 0.0); + else if ((!u_clampLow && value < u_domain[0]) || (!u_clampHigh && value > u_domain[1])) + gl_FragColor = vec4(0, 0, 0, 0); + else { + float normalisedValue =(value - u_domain[0]) / (u_domain[1] -u_domain[0]); + vec2 ramp_pos = vec2( + fract(16.0 * (1.0 - normalisedValue)), + floor(16.0 * (1.0 - normalisedValue)) / 16.0); + gl_FragColor = texture2D(u_colorTexture, ramp_pos); + } + + } diff --git a/packages/maps/src/amap/index.ts b/packages/maps/src/amap/index.ts index 60f55ed26e..cf9f00e974 100644 --- a/packages/maps/src/amap/index.ts +++ b/packages/maps/src/amap/index.ts @@ -229,6 +229,7 @@ export default class AMapService maxZoom = 18, token = AMAP_API_KEY, mapInstance, + plugin = [], ...rest } = this.config; // 高德地图创建独立的container; @@ -273,7 +274,9 @@ export default class AMapService if (token === AMAP_API_KEY) { this.logger.warn(this.configService.getSceneWarninfo('MapToken')); } - const url: string = `https://webapi.amap.com/maps?v=${AMAP_VERSION}&key=${token}&plugin=Map3D&callback=initAMap`; + const url: string = `https://webapi.amap.com/maps?v=${AMAP_VERSION}&key=${token}&plugin=Map3D${plugin.join( + ',', + )}&callback=initAMap`; const $jsapi = document.createElement('script'); $jsapi.id = AMAP_SCRIPT_ID; $jsapi.charset = 'utf-8'; diff --git a/packages/renderer/src/regl/index.ts b/packages/renderer/src/regl/index.ts index 7b3f0bb968..2991980163 100644 --- a/packages/renderer/src/regl/index.ts +++ b/packages/renderer/src/regl/index.ts @@ -52,7 +52,6 @@ export default class ReglRendererService implements IRendererService { // TODO: use extensions extensions: [ 'OES_element_index_uint', - // 'EXT_shader_texture_lod', // IBL 兼容性问题 'EXT_blend_minmax', 'OES_standard_derivatives', // wireframe // 'OES_texture_float', // shadow map 兼容性问题 @@ -60,7 +59,7 @@ export default class ReglRendererService implements IRendererService { 'angle_instanced_arrays', 'EXT_texture_filter_anisotropic', // VSM shadow map ], - // optionalExtensions: ['oes_texture_float_linear'], + optionalExtensions: ['oes_texture_float_linear', 'OES_texture_float'], profile: true, onDone: (err: Error | null, r?: regl.Regl | undefined): void => { if (err || !r) { diff --git a/stories/Layers/components/RasterImage.tsx b/stories/Layers/components/RasterImage.tsx index 06628c5c23..3043995061 100644 --- a/stories/Layers/components/RasterImage.tsx +++ b/stories/Layers/components/RasterImage.tsx @@ -15,7 +15,7 @@ export default class ImageLayerDemo extends React.Component { map: new Mapbox({ center: [121.268, 30.3628], pitch: 0, - style: 'mapbox://styles/mapbox/streets-v9', + style: 'dark', zoom: 10, }), }); @@ -30,7 +30,6 @@ export default class ImageLayerDemo extends React.Component { }, ); scene.addLayer(layer); - scene.render(); this.scene = scene; } diff --git a/stories/Layers/components/RasterLayer.tsx b/stories/Layers/components/RasterLayer.tsx index 90a2479563..4f2a97a641 100644 --- a/stories/Layers/components/RasterLayer.tsx +++ b/stories/Layers/components/RasterLayer.tsx @@ -1,14 +1,19 @@ import { RasterLayer, Scene } from '@antv/l7'; import { Mapbox } from '@antv/l7-maps'; +import * as dat from 'dat.gui'; // @ts-ignore import * as GeoTIFF from 'geotiff/dist/geotiff.bundle.js'; import * as React from 'react'; export default class ImageLayerDemo extends React.Component { private scene: Scene; + private gui: dat.GUI; public componentWillUnmount() { this.scene.destroy(); + if (this.gui) { + this.gui.destroy(); + } } public async componentDidMount() { @@ -17,7 +22,7 @@ export default class ImageLayerDemo extends React.Component { map: new Mapbox({ center: [121.268, 30.3628], pitch: 0, - style: 'mapbox://styles/mapbox/streets-v9', + style: 'dark', zoom: 2, }), }); @@ -36,6 +41,8 @@ export default class ImageLayerDemo extends React.Component { }) .style({ opacity: 0.8, + domain: [100, 4000], + clampLow: true, rampColors: { colors: [ '#002466', @@ -53,8 +60,45 @@ export default class ImageLayerDemo extends React.Component { }, }); scene.addLayer(layer); - scene.render(); + this.scene = scene; + /*** 运行时修改样式属性 ***/ + const gui = new dat.GUI(); + this.gui = gui; + const styleOptions = { + clampLow: true, + clampHigh: true, + noDataValue: -9999999, + min: 100, + max: 4000, + }; + const rasterFolder = gui.addFolder('栅格可视化'); + rasterFolder.add(styleOptions, 'clampLow').onChange((clampLow: boolean) => { + layer.style({ + clampLow, + }); + scene.render(); + }); + rasterFolder + .add(styleOptions, 'clampHigh') + .onChange((clampHigh: boolean) => { + layer.style({ + clampHigh, + }); + scene.render(); + }); + rasterFolder.add(styleOptions, 'min', 0, 9000).onChange((min: number) => { + layer.style({ + domain: [min, styleOptions.max], + }); + scene.render(); + }); + rasterFolder.add(styleOptions, 'max', 0, 9000).onChange((max: number) => { + layer.style({ + domain: [styleOptions.min, max], + }); + scene.render(); + }); } public render() {