mirror of https://gitee.com/antv-l7/antv-l7
commit
1fb532d0e7
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -187,7 +187,6 @@ layer.source(
|
||||||
parser:{
|
parser:{
|
||||||
type:'json',
|
type:'json',
|
||||||
coordinates: "coord",
|
coordinates: "coord",
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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,
|
||||||
|
|
|
@ -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({
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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之前引入',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,10 @@ export interface IMapConfig<RawMap = {}> {
|
||||||
* 地图实例
|
* 地图实例
|
||||||
*/
|
*/
|
||||||
mapInstance?: RawMap;
|
mapInstance?: RawMap;
|
||||||
|
/**
|
||||||
|
* 高德地图API插件
|
||||||
|
*/
|
||||||
|
plugin?: string[];
|
||||||
/**
|
/**
|
||||||
* 容器 DOM id
|
* 容器 DOM id
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
// 开启动画
|
// 开启动画
|
||||||
|
|
|
@ -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';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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]];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import ImageModel from './image';
|
||||||
|
export type ImageModelType = 'image';
|
||||||
|
|
||||||
|
const ImageModels: { [key in ImageModelType]: any } = {
|
||||||
|
image: ImageModel,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ImageModels;
|
|
@ -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';
|
||||||
|
|
|
@ -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]];
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -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';
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
|
@ -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]];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -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: {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Reference in New Issue