Merge pull request #145 from antvis/docs

feat: add raster layer
This commit is contained in:
@thinkinggis 2020-01-02 21:10:22 +08:00 committed by GitHub
commit 1fb532d0e7
28 changed files with 594 additions and 133 deletions

View File

@ -5,7 +5,7 @@ order: 2
# 简介 # 简介
L7 专注数据可视化层数据表达,目前 L7 还不支持独立的地图引擎,需要引入第三方引擎,目前支持 高德地图和 MapBox 两种。 L7 专注数据可视化层数据表达,目前 L7 还不支持独立的地图引擎,需要引入第三方引擎,目前支持 高德地图和 MapBox 两种。=
L7 在内部解决了不同底图地图直接的差异,同时 L7 层面统一管理地图的操作方法。 L7 在内部解决了不同底图地图直接的差异,同时 L7 层面统一管理地图的操作方法。
## Map ## 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 ```javascript
const L7AMap = new GaodeMap({ const L7AMap = new GaodeMap({
pitch: 35.210526315789465, pitch: 35.210526315789465,
@ -32,6 +41,7 @@ const L7AMap = new GaodeMap({
center: [104.288144, 31.239692], center: [104.288144, 31.239692],
zoom: 4.4, zoom: 4.4,
token: 'xxxx - token', token: 'xxxx - token',
plugin: [], // 可以不设置
}); });
``` ```
@ -59,6 +69,8 @@ const scene = new Scene({
⚠️ 传入地图实例需要自行引入相关地图的 API ⚠️ 传入地图实例需要自行引入相关地图的 API
⚠️ viewMode 设置为 3D 模式
#### 传入高德地图实例 #### 传入高德地图实例
```javascript ```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 地图实例 #### 传入 Mapbox 地图实例
```javascript ```javascript

View File

@ -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 ```javascript
const L7AMap = new GaodeMap({ const L7AMap = new GaodeMap({
pitch: 35.210526315789465, pitch: 35.210526315789465,
@ -32,6 +41,7 @@ const L7AMap = new GaodeMap({
center: [104.288144, 31.239692], center: [104.288144, 31.239692],
zoom: 4.4, zoom: 4.4,
token: 'xxxx - token', token: 'xxxx - token',
plugin: [], // 可以不设置
}); });
``` ```
@ -59,6 +69,8 @@ const scene = new Scene({
⚠️ 传入地图实例需要自行引入相关地图的 API ⚠️ 传入地图实例需要自行引入相关地图的 API
⚠️ viewMode 设置为 3D 模式
#### 传入高德地图实例 #### 传入高德地图实例
```javascript ```javascript

View File

@ -187,7 +187,6 @@ layer.source(
parser:{ parser:{
type:'json', type:'json',
coordinates: "coord", coordinates: "coord",
} }
} }
}) })

View File

@ -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);
}

View File

@ -46,7 +46,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
'vesica', 'vesica',
], ],
shape3d: ['cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn'], shape3d: ['cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn'],
minZoom: 0, minZoom: -1,
maxZoom: 24, maxZoom: 24,
visible: true, visible: true,
autoFit: false, autoFit: false,

View File

@ -40,12 +40,12 @@ describe('ConfigService', () => {
const { valid, errorText } = configService.validateMapConfig({ const { valid, errorText } = configService.validateMapConfig({
zoom: 100, zoom: 100,
minZoom: 100, minZoom: 100,
maxZoom: -1, maxZoom: -2,
}); });
expect(valid).toBeFalsy(); expect(valid).toBeFalsy();
expect(errorText).toMatch('zoom should be <= 20'); expect(errorText).toMatch('zoom should be <= 24');
expect(errorText).toMatch('minZoom should be <= 20'); expect(errorText).toMatch('minZoom should be <= 24');
expect(errorText).toMatch('maxZoom should be >= 0'); expect(errorText).toMatch('maxZoom should be >= -1');
expect( expect(
configService.validateMapConfig({ configService.validateMapConfig({

View File

@ -6,18 +6,18 @@ export default {
// 地图缩放等级 // 地图缩放等级
zoom: { zoom: {
type: 'number', type: 'number',
minimum: 0, minimum: -1,
maximum: 20, maximum: 24,
}, },
minZoom: { minZoom: {
type: 'number', type: 'number',
minimum: 0, minimum: -1,
maximum: 20, maximum: 24,
}, },
maxZoom: { maxZoom: {
type: 'number', type: 'number',
minimum: 0, minimum: -1,
maximum: 20, maximum: 24,
}, },
// 地图中心点 // 地图中心点
center: { center: {

View File

@ -5,7 +5,7 @@ export interface IWarnInfo {
} }
const WarnInfo: IWarnInfo = { const WarnInfo: IWarnInfo = {
MapToken: MapToken:
'您正在使用 Demo测试地图token如果生环境中使用去对应地图请注册Token', '您正在使用 Demo测试地图token如果生环境中使用去对应地图请注册Token',
SDK: '请确认引入了mapbox-gl api且在L7之前引入', SDK: '请确认引入了mapbox-gl api且在L7之前引入',
}; };

View File

@ -71,6 +71,10 @@ export interface IMapConfig<RawMap = {}> {
* *
*/ */
mapInstance?: RawMap; mapInstance?: RawMap;
/**
* API插件
*/
plugin?: string[];
/** /**
* DOM id * DOM id
*/ */

View File

@ -424,7 +424,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
this.buildModels(); this.buildModels();
return this; return this;
} }
public style(options: object & Partial<ILayerConfig>): ILayer { public style(
options: Partial<ChildLayerStyleOptions> & Partial<ILayerConfig>,
): ILayer {
const { passes, ...rest } = options; const { passes, ...rest } = options;
// passes 特殊处理 // passes 特殊处理
@ -582,7 +584,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
} }
public isVisible(): boolean { public isVisible(): boolean {
const zoom = this.mapService.getZoom(); const zoom = this.mapService.getZoom();
const { const {
visible, visible,
minZoom = -Infinity, minZoom = -Infinity,

View File

@ -11,6 +11,7 @@ import {
ILayer, ILayer,
ILayerConfig, ILayerConfig,
ILayerModel, ILayerModel,
ILayerService,
IMapService, IMapService,
IModel, IModel,
IModelUniform, IModelUniform,
@ -44,6 +45,7 @@ export default class BaseModel<ChildLayerStyleOptions = {}>
protected styleAttributeService: IStyleAttributeService; protected styleAttributeService: IStyleAttributeService;
protected mapService: IMapService; protected mapService: IMapService;
protected cameraService: ICameraService; protected cameraService: ICameraService;
protected layerService: ILayerService;
constructor(layer: ILayer) { constructor(layer: ILayer) {
this.layer = layer; this.layer = layer;
@ -57,6 +59,10 @@ export default class BaseModel<ChildLayerStyleOptions = {}>
this.cameraService = layer this.cameraService = layer
.getContainer() .getContainer()
.get<ICameraService>(TYPES.ICameraService); .get<ICameraService>(TYPES.ICameraService);
this.layerService = layer
.getContainer()
.get<ILayerService>(TYPES.ILayerService);
// 注册 Attribute // 注册 Attribute
this.registerBuiltinAttributes(); this.registerBuiltinAttributes();
// 开启动画 // 开启动画

View File

@ -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<IImageLayerStyleOptions> {
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';
}
}

View File

@ -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]];
},
},
});
}
}

View File

@ -0,0 +1,8 @@
import ImageModel from './image';
export type ImageModelType = 'image';
const ImageModels: { [key in ImageModelType]: any } = {
image: ImageModel,
};
export default ImageModels;

View File

@ -3,11 +3,11 @@ import CityBuildingLayer from './citybuliding/building';
import BaseLayer from './core/BaseLayer'; import BaseLayer from './core/BaseLayer';
import './glsl.d'; import './glsl.d';
import HeatmapLayer from './heatmap'; import HeatmapLayer from './heatmap';
import ImageLayer from './image';
import LineLayer from './line/index'; import LineLayer from './line/index';
import PointLayer from './point'; import PointLayer from './point';
import PolygonLayer from './polygon'; import PolygonLayer from './polygon';
import ImageLayer from './raster/image'; import RasterLayer from './raster';
import RasterLayer from './raster/raster';
import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin'; import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
import DataMappingPlugin from './plugins/DataMappingPlugin'; import DataMappingPlugin from './plugins/DataMappingPlugin';

View File

@ -1,106 +1,106 @@
import { // import {
AttributeType, // AttributeType,
gl, // gl,
IEncodeFeature, // IEncodeFeature,
ILayer, // ILayer,
ITexture2D, // ITexture2D,
} from '@antv/l7-core'; // } from '@antv/l7-core';
import BaseLayer from '../core/BaseLayer'; // import BaseLayer from '../core/BaseLayer';
import { RasterImageTriangulation } from '../core/triangulation'; // import { RasterImageTriangulation } from '../core/triangulation';
import rasterImageFrag from './shaders/image_frag.glsl'; // import rasterImageFrag from './shaders/image_frag.glsl';
import rasterImageVert from './shaders/image_vert.glsl'; // import rasterImageVert from './shaders/image_vert.glsl';
interface IRaterLayerStyleOptions { // interface IRaterLayerStyleOptions {
opacity: number; // opacity: number;
} // }
export default class ImageLayer extends BaseLayer<IRaterLayerStyleOptions> { // export default class ImageLayer extends BaseLayer<IRaterLayerStyleOptions> {
public type: string = 'ImageLayer'; // public type: string = 'ImageLayer';
protected texture: ITexture2D; // protected texture: ITexture2D;
protected getConfigSchema() { // protected getConfigSchema() {
return { // return {
properties: { // properties: {
opacity: { // opacity: {
type: 'number', // type: 'number',
minimum: 0, // minimum: 0,
maximum: 1, // maximum: 1,
}, // },
}, // },
}; // };
} // }
protected renderModels() { // protected renderModels() {
const { opacity } = this.getLayerConfig(); // const { opacity } = this.getLayerConfig();
if (this.texture) { // if (this.texture) {
this.models.forEach((model) => // this.models.forEach((model) =>
model.draw({ // model.draw({
uniforms: { // uniforms: {
u_opacity: opacity || 1, // u_opacity: opacity || 1,
u_texture: this.texture, // u_texture: this.texture,
}, // },
}), // }),
); // );
} // }
return this; // return this;
} // }
protected buildModels() { // protected buildModels() {
this.registerBuiltinAttributes(); // this.registerBuiltinAttributes();
const source = this.getSource(); // const source = this.getSource();
const { createTexture2D } = this.rendererService; // const { createTexture2D } = this.rendererService;
source.data.images.then((imageData: HTMLImageElement[]) => { // source.data.images.then((imageData: HTMLImageElement[]) => {
this.texture = createTexture2D({ // this.texture = createTexture2D({
data: imageData[0], // data: imageData[0],
width: imageData[0].width, // width: imageData[0].width,
height: imageData[0].height, // height: imageData[0].height,
}); // });
this.renderModels(); // this.renderModels();
}); // });
this.models = [ // this.models = [
this.buildLayerModel({ // this.buildLayerModel({
moduleName: 'RasterImage', // moduleName: 'RasterImage',
vertexShader: rasterImageVert, // vertexShader: rasterImageVert,
fragmentShader: rasterImageFrag, // fragmentShader: rasterImageFrag,
triangulation: RasterImageTriangulation, // triangulation: RasterImageTriangulation,
primitive: gl.TRIANGLES, // primitive: gl.TRIANGLES,
depth: { enable: false }, // depth: { enable: false },
blend: { // blend: {
enable: true, // enable: true,
func: { // func: {
srcRGB: gl.SRC_ALPHA, // srcRGB: gl.SRC_ALPHA,
srcAlpha: 1, // srcAlpha: 1,
dstRGB: gl.ONE_MINUS_SRC_ALPHA, // dstRGB: gl.ONE_MINUS_SRC_ALPHA,
dstAlpha: 1, // dstAlpha: 1,
}, // },
}, // },
}), // }),
]; // ];
} // }
private registerBuiltinAttributes() { // private registerBuiltinAttributes() {
// point layer size; // // point layer size;
this.styleAttributeService.registerStyleAttribute({ // this.styleAttributeService.registerStyleAttribute({
name: 'uv', // name: 'uv',
type: AttributeType.Attribute, // type: AttributeType.Attribute,
descriptor: { // descriptor: {
name: 'a_Uv', // name: 'a_Uv',
buffer: { // buffer: {
// give the WebGL driver a hint that this buffer may change // // give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW, // usage: gl.DYNAMIC_DRAW,
data: [], // data: [],
type: gl.FLOAT, // type: gl.FLOAT,
}, // },
size: 2, // size: 2,
update: ( // update: (
feature: IEncodeFeature, // feature: IEncodeFeature,
featureIdx: number, // featureIdx: number,
vertex: number[], // vertex: number[],
attributeIdx: number, // attributeIdx: number,
) => { // ) => {
return [vertex[3], vertex[4]]; // return [vertex[3], vertex[4]];
}, // },
}, // },
}); // });
} // }
} // }

View File

@ -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<IRasterLayerStyleOptions> {
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';
}
}

View File

@ -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;

View File

@ -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]];
},
},
});
}
}

View File

@ -5,12 +5,14 @@ import {
ILayer, ILayer,
ILayerPlugin, ILayerPlugin,
ILogService, ILogService,
IModelUniform,
IRasterParserDataItem, IRasterParserDataItem,
IStyleAttributeService, IStyleAttributeService,
ITexture2D, ITexture2D,
lazyInject, lazyInject,
TYPES, TYPES,
} from '@antv/l7-core'; } from '@antv/l7-core';
import { generateColorRamp, IColorRamp } from '@antv/l7-utils'; import { generateColorRamp, IColorRamp } from '@antv/l7-utils';
import BaseLayer from '../core/BaseLayer'; import BaseLayer from '../core/BaseLayer';
import { RasterTriangulation } from './buffers/triangulation'; import { RasterTriangulation } from './buffers/triangulation';
@ -30,6 +32,9 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
protected texture: ITexture2D; protected texture: ITexture2D;
protected colorTexture: ITexture2D; protected colorTexture: ITexture2D;
public getAnimateUniforms(): IModelUniform {
return {};
}
protected getConfigSchema() { protected getConfigSchema() {
return { return {
properties: { properties: {

View File

@ -4,15 +4,26 @@ uniform sampler2D u_texture;
uniform sampler2D u_colorTexture; uniform sampler2D u_colorTexture;
uniform float u_min; uniform float u_min;
uniform float u_max; 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; varying vec2 v_texCoord;
void main() { void main() {
float value = texture2D(u_texture,vec2(v_texCoord.x,v_texCoord.y)).a; float value = texture2D(u_texture,vec2(v_texCoord.x,v_texCoord.y)).r;
value = clamp(value,u_min,u_max); if (value == u_noDataValue)
float value1 = (value - u_min) / (u_max -u_min); 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( vec2 ramp_pos = vec2(
fract(16.0 * (1.0 - value1)), fract(16.0 * (1.0 - normalisedValue)),
floor(16.0 * (1.0 - value1)) / 16.0); floor(16.0 * (1.0 - normalisedValue)) / 16.0);
gl_FragColor = texture2D(u_colorTexture,ramp_pos);; gl_FragColor = texture2D(u_colorTexture, ramp_pos);
}
} }

View File

@ -229,6 +229,7 @@ export default class AMapService
maxZoom = 18, maxZoom = 18,
token = AMAP_API_KEY, token = AMAP_API_KEY,
mapInstance, mapInstance,
plugin = [],
...rest ...rest
} = this.config; } = this.config;
// 高德地图创建独立的container // 高德地图创建独立的container
@ -273,7 +274,9 @@ export default class AMapService
if (token === AMAP_API_KEY) { if (token === AMAP_API_KEY) {
this.logger.warn(this.configService.getSceneWarninfo('MapToken')); 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'); const $jsapi = document.createElement('script');
$jsapi.id = AMAP_SCRIPT_ID; $jsapi.id = AMAP_SCRIPT_ID;
$jsapi.charset = 'utf-8'; $jsapi.charset = 'utf-8';

View File

@ -52,7 +52,6 @@ export default class ReglRendererService implements IRendererService {
// TODO: use extensions // TODO: use extensions
extensions: [ extensions: [
'OES_element_index_uint', 'OES_element_index_uint',
// 'EXT_shader_texture_lod', // IBL 兼容性问题
'EXT_blend_minmax', 'EXT_blend_minmax',
'OES_standard_derivatives', // wireframe 'OES_standard_derivatives', // wireframe
// 'OES_texture_float', // shadow map 兼容性问题 // 'OES_texture_float', // shadow map 兼容性问题
@ -60,7 +59,7 @@ export default class ReglRendererService implements IRendererService {
'angle_instanced_arrays', 'angle_instanced_arrays',
'EXT_texture_filter_anisotropic', // VSM shadow map 'EXT_texture_filter_anisotropic', // VSM shadow map
], ],
// optionalExtensions: ['oes_texture_float_linear'], optionalExtensions: ['oes_texture_float_linear', 'OES_texture_float'],
profile: true, profile: true,
onDone: (err: Error | null, r?: regl.Regl | undefined): void => { onDone: (err: Error | null, r?: regl.Regl | undefined): void => {
if (err || !r) { if (err || !r) {

View File

@ -15,7 +15,7 @@ export default class ImageLayerDemo extends React.Component {
map: new Mapbox({ map: new Mapbox({
center: [121.268, 30.3628], center: [121.268, 30.3628],
pitch: 0, pitch: 0,
style: 'mapbox://styles/mapbox/streets-v9', style: 'dark',
zoom: 10, zoom: 10,
}), }),
}); });
@ -30,7 +30,6 @@ export default class ImageLayerDemo extends React.Component {
}, },
); );
scene.addLayer(layer); scene.addLayer(layer);
scene.render();
this.scene = scene; this.scene = scene;
} }

View File

@ -1,14 +1,19 @@
import { RasterLayer, Scene } from '@antv/l7'; import { RasterLayer, Scene } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps'; import { Mapbox } from '@antv/l7-maps';
import * as dat from 'dat.gui';
// @ts-ignore // @ts-ignore
import * as GeoTIFF from 'geotiff/dist/geotiff.bundle.js'; import * as GeoTIFF from 'geotiff/dist/geotiff.bundle.js';
import * as React from 'react'; import * as React from 'react';
export default class ImageLayerDemo extends React.Component { export default class ImageLayerDemo extends React.Component {
private scene: Scene; private scene: Scene;
private gui: dat.GUI;
public componentWillUnmount() { public componentWillUnmount() {
this.scene.destroy(); this.scene.destroy();
if (this.gui) {
this.gui.destroy();
}
} }
public async componentDidMount() { public async componentDidMount() {
@ -17,7 +22,7 @@ export default class ImageLayerDemo extends React.Component {
map: new Mapbox({ map: new Mapbox({
center: [121.268, 30.3628], center: [121.268, 30.3628],
pitch: 0, pitch: 0,
style: 'mapbox://styles/mapbox/streets-v9', style: 'dark',
zoom: 2, zoom: 2,
}), }),
}); });
@ -36,6 +41,8 @@ export default class ImageLayerDemo extends React.Component {
}) })
.style({ .style({
opacity: 0.8, opacity: 0.8,
domain: [100, 4000],
clampLow: true,
rampColors: { rampColors: {
colors: [ colors: [
'#002466', '#002466',
@ -53,8 +60,45 @@ export default class ImageLayerDemo extends React.Component {
}, },
}); });
scene.addLayer(layer); scene.addLayer(layer);
scene.render();
this.scene = scene; 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() { public render() {