mirror of https://gitee.com/antv-l7/antv-l7
feat: 图层新增 creatModelData 与 updateModelData 方法 (#1064)
* feat: 支持提前计算 attribute/elements 并更新 models * style: lint style * feat: 支持 lineLayer 的 models 更新 attributes/elements * style: lint style * chore: update version 2.8.30 -> 2.8.31 * feat: 完善 geometry 加载地形的 lod * style: lint style * feat: rename func updateMudelsData to updateModelData * feat: pointLayer simple 支持 initModelData/updateModelData * feat: 增加顶点更新 demo * style: lint style * feat: reset func name => initModelData => createModelData
This commit is contained in:
parent
90f92f069b
commit
aa2e9540de
|
@ -19,3 +19,5 @@ window.react = require('react');
|
|||
window.popmotion = require('popmotion');
|
||||
window.reactDom = require('react-dom');
|
||||
window.antd = require('antd');
|
||||
window.d3Dsv = require('d3-dsv');
|
||||
window.materialUI = require('@material-ui')
|
||||
|
|
|
@ -88,6 +88,8 @@
|
|||
"husky": "^3.0.9",
|
||||
"jest": "^24.9.0",
|
||||
"jest-electron": "^0.1.11",
|
||||
"@material-ui/core": "^4.10.2",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"jest-styled-components": "^6.2.1",
|
||||
"lerna": "^3.16.4",
|
||||
"lint-staged": "^9.2.4",
|
||||
|
|
|
@ -78,6 +78,7 @@ export interface ILayerModel {
|
|||
|
||||
// earth mode
|
||||
setEarthTime?(time: number): void;
|
||||
createModelData?(options?: any): any;
|
||||
}
|
||||
export interface IModelUniform {
|
||||
[key: string]: IUniform;
|
||||
|
@ -110,6 +111,11 @@ export interface ILegendClassificaItem {
|
|||
// 图层图例
|
||||
export type LegendItems = ILegendSegmentItem[] | ILegendClassificaItem[];
|
||||
|
||||
export interface IAttrubuteAndElements {
|
||||
attributes: any;
|
||||
elements: any;
|
||||
}
|
||||
|
||||
export interface ILayer {
|
||||
id: string; // 一个场景中同一类型 Layer 可能存在多个
|
||||
type: string; // 代表 Layer 的类型
|
||||
|
@ -150,6 +156,7 @@ export interface ILayer {
|
|||
// 初始化 layer 的时候指定 layer type 类型()兼容空数据的情况
|
||||
layerType?: string | undefined;
|
||||
isLayerGroup: boolean;
|
||||
triangulation?: Triangulation | undefined;
|
||||
/**
|
||||
* threejs 适配兼容相关的方法
|
||||
* @param lnglat
|
||||
|
@ -161,6 +168,7 @@ export interface ILayer {
|
|||
threeRenderService?: any;
|
||||
|
||||
getShaderPickStat: () => boolean;
|
||||
updateModelData(data: IAttrubuteAndElements): void;
|
||||
|
||||
addMaskLayer(maskLayer: ILayer): void;
|
||||
removeMaskLayer(maskLayer: ILayer): void;
|
||||
|
|
|
@ -244,6 +244,10 @@ export interface IModelDrawOptions {
|
|||
*/
|
||||
export interface IModel {
|
||||
updateAttributes(attributes: { [key: string]: IAttribute }): void;
|
||||
updateAttributesAndElements(
|
||||
attributes: { [key: string]: IAttribute },
|
||||
elements: IElements,
|
||||
): void;
|
||||
addUniforms(uniforms: { [key: string]: IUniform }): void;
|
||||
draw(options: IModelDrawOptions, pick?: boolean): void;
|
||||
destroy(): void;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
AttributeType,
|
||||
gl,
|
||||
IAttrubuteAndElements,
|
||||
IEncodeFeature,
|
||||
IModelUniform,
|
||||
ITexture2D,
|
||||
|
@ -15,9 +16,9 @@ import planeVert from '../shaders/plane_vert.glsl';
|
|||
|
||||
export default class PlaneModel extends BaseModel {
|
||||
protected texture: ITexture2D;
|
||||
protected terrainImage: HTMLImageElement;
|
||||
protected terrainImageLoaded: boolean = false;
|
||||
protected mapTexture: string | undefined;
|
||||
protected positions: number[];
|
||||
protected indices: number[];
|
||||
|
||||
public initPlane(
|
||||
width = 1,
|
||||
|
@ -88,7 +89,6 @@ export default class PlaneModel extends BaseModel {
|
|||
center = [120, 30],
|
||||
terrainTexture,
|
||||
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
|
||||
|
||||
const { indices, positions } = this.initPlane(
|
||||
width,
|
||||
height,
|
||||
|
@ -96,12 +96,9 @@ export default class PlaneModel extends BaseModel {
|
|||
heightSegments,
|
||||
...center,
|
||||
);
|
||||
this.positions = positions;
|
||||
this.indices = indices;
|
||||
|
||||
if (terrainTexture) {
|
||||
// 存在地形贴图的时候会根据地形贴图对顶点进行偏移
|
||||
this.loadTerrainTexture();
|
||||
this.loadTerrainTexture(positions, indices);
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -110,13 +107,6 @@ export default class PlaneModel extends BaseModel {
|
|||
size: 5,
|
||||
};
|
||||
};
|
||||
public planeGeometryUpdateTriangulation = () => {
|
||||
return {
|
||||
vertices: this.positions,
|
||||
indices: this.indices,
|
||||
size: 5,
|
||||
};
|
||||
};
|
||||
|
||||
public getUninforms(): IModelUniform {
|
||||
const {
|
||||
|
@ -135,14 +125,12 @@ export default class PlaneModel extends BaseModel {
|
|||
u_mapFlag: mapTexture ? 1 : 0,
|
||||
u_terrainClipHeight: terrainTexture ? terrainClipHeight : -1,
|
||||
u_texture: this.texture,
|
||||
// u_ModelMatrix: mat4.translate(mat4.create(), mat4.create(), [1, 0, 0])
|
||||
// u_ModelMatrix: mat4.rotateZ(mat4.create(), mat4.create(), 10)
|
||||
// u_ModelMatrix: mat4.rotateZ(mat4.create(), mat4.create(), 10)
|
||||
// u_ModelMatrix: this.rotateZ()
|
||||
};
|
||||
}
|
||||
|
||||
public clearModels(): void {
|
||||
// @ts-ignore
|
||||
this.terrainImage = null;
|
||||
this.texture?.destroy();
|
||||
}
|
||||
|
||||
|
@ -161,7 +149,6 @@ export default class PlaneModel extends BaseModel {
|
|||
});
|
||||
|
||||
this.updateTexture(mapTexture);
|
||||
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'geometry_plane',
|
||||
|
@ -169,6 +156,7 @@ export default class PlaneModel extends BaseModel {
|
|||
fragmentShader: planeFrag,
|
||||
triangulation: this.planeGeometryTriangulation,
|
||||
primitive: gl.TRIANGLES,
|
||||
// primitive: gl.LINES,
|
||||
depth: { enable: true },
|
||||
blend: this.getBlend(),
|
||||
stencil: getMask(mask, maskInside),
|
||||
|
@ -180,90 +168,41 @@ export default class PlaneModel extends BaseModel {
|
|||
];
|
||||
}
|
||||
|
||||
public getImageData(img: HTMLImageElement) {
|
||||
const canvas: HTMLCanvasElement = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
const { width, height } = img;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
const imageData = ctx.getImageData(0, 0, width, height);
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
/**
|
||||
* load terrain texture & offset attribute z
|
||||
*/
|
||||
public loadTerrainTexture(): void {
|
||||
const {
|
||||
mask = false,
|
||||
maskInside = true,
|
||||
widthSegments = 1,
|
||||
heightSegments = 1,
|
||||
terrainTexture,
|
||||
rgb2height = (r: number, g: number, b: number) => r + g + b,
|
||||
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
|
||||
const terrainImage = new Image();
|
||||
terrainImage.crossOrigin = 'anonymous';
|
||||
terrainImage.onload = () => {
|
||||
const imgWidth = terrainImage.width;
|
||||
const imgHeight = terrainImage.height;
|
||||
|
||||
const imageData = this.getImageData(terrainImage).data;
|
||||
|
||||
const gridX = Math.floor(widthSegments);
|
||||
const gridY = Math.floor(heightSegments);
|
||||
|
||||
const gridX1 = gridX + 1;
|
||||
const gridY1 = gridY + 1;
|
||||
|
||||
const widthStep = imgWidth / gridX;
|
||||
const heihgtStep = imgHeight / gridY;
|
||||
|
||||
for (let iy = 0; iy < gridY1; iy++) {
|
||||
const imgIndexY = Math.floor(iy * heihgtStep);
|
||||
const imgLen = imgIndexY * imgWidth;
|
||||
|
||||
for (let ix = 0; ix < gridX1; ix++) {
|
||||
const imgIndexX = Math.floor(ix * widthStep);
|
||||
const imgDataIndex = (imgLen + imgIndexX) * 4;
|
||||
|
||||
const r = imageData[imgDataIndex];
|
||||
const g = imageData[imgDataIndex + 1];
|
||||
const b = imageData[imgDataIndex + 2];
|
||||
|
||||
const z = (iy * gridX1 + ix) * 5 + 2;
|
||||
this.positions[z] = rgb2height(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
this.layer.models = [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'geometry_plane',
|
||||
vertexShader: planeVert,
|
||||
fragmentShader: planeFrag,
|
||||
triangulation: this.planeGeometryUpdateTriangulation,
|
||||
primitive: gl.TRIANGLES,
|
||||
depth: { enable: true },
|
||||
blend: this.getBlend(),
|
||||
stencil: getMask(mask, maskInside),
|
||||
cull: {
|
||||
enable: true,
|
||||
face: gl.BACK,
|
||||
},
|
||||
}),
|
||||
];
|
||||
this.layerService.renderLayers();
|
||||
};
|
||||
terrainImage.src = terrainTexture as string;
|
||||
}
|
||||
|
||||
public buildModels() {
|
||||
return this.initModels();
|
||||
}
|
||||
|
||||
public createModelData(options?: any) {
|
||||
if (options) {
|
||||
const {
|
||||
widthSegments: oldwidthSegments,
|
||||
heightSegments: oldheightSegments,
|
||||
width: oldwidth,
|
||||
height: oldheight,
|
||||
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
|
||||
const {
|
||||
widthSegments,
|
||||
heightSegments,
|
||||
width,
|
||||
height,
|
||||
} = options as IGeometryLayerStyleOptions;
|
||||
this.layer.style({
|
||||
widthSegments:
|
||||
widthSegments !== undefined ? widthSegments : oldwidthSegments,
|
||||
heightSegments:
|
||||
heightSegments !== undefined ? heightSegments : oldheightSegments,
|
||||
width: width !== undefined ? width : oldwidth,
|
||||
height: height !== undefined ? height : oldheight,
|
||||
});
|
||||
}
|
||||
const oldFeatures = this.layer.getEncodedData();
|
||||
const res = this.styleAttributeService.createAttributesAndIndices(
|
||||
oldFeatures,
|
||||
this.planeGeometryTriangulation,
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
public updateTexture(mapTexture: string | undefined): void {
|
||||
const { createTexture2D } = this.rendererService;
|
||||
|
||||
|
@ -290,6 +229,127 @@ export default class PlaneModel extends BaseModel {
|
|||
}
|
||||
}
|
||||
|
||||
protected getImageData(img: HTMLImageElement) {
|
||||
const canvas: HTMLCanvasElement = document.createElement('canvas');
|
||||
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||
const { width, height } = img;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
ctx.drawImage(img, 0, 0, width, height);
|
||||
const imageData = ctx.getImageData(0, 0, width, height);
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
protected translateVertex(
|
||||
positions: number[],
|
||||
indices: number[],
|
||||
image: HTMLImageElement,
|
||||
widthSegments: number,
|
||||
heightSegments: number,
|
||||
rgb2height: (r: number, g: number, b: number) => number,
|
||||
) {
|
||||
const imgWidth = image.width;
|
||||
const imgHeight = image.height;
|
||||
const imageData = this.getImageData(image).data;
|
||||
|
||||
const gridX = Math.floor(widthSegments);
|
||||
const gridY = Math.floor(heightSegments);
|
||||
|
||||
const gridX1 = gridX + 1;
|
||||
const gridY1 = gridY + 1;
|
||||
|
||||
const widthStep = imgWidth / gridX;
|
||||
const heihgtStep = imgHeight / gridY;
|
||||
|
||||
for (let iy = 0; iy < gridY1; iy++) {
|
||||
const imgIndexY = Math.floor(iy * heihgtStep);
|
||||
const imgLen = imgIndexY * imgWidth;
|
||||
|
||||
for (let ix = 0; ix < gridX1; ix++) {
|
||||
const imgIndexX = Math.floor(ix * widthStep);
|
||||
const imgDataIndex = (imgLen + imgIndexX) * 4;
|
||||
|
||||
const r = imageData[imgDataIndex];
|
||||
const g = imageData[imgDataIndex + 1];
|
||||
const b = imageData[imgDataIndex + 2];
|
||||
|
||||
const z = (iy * gridX1 + ix) * 5 + 2;
|
||||
positions[z] = rgb2height(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
const oldFeatures = this.layer.getEncodedData();
|
||||
const modelData = this.styleAttributeService.createAttributesAndIndices(
|
||||
oldFeatures,
|
||||
() => {
|
||||
return {
|
||||
vertices: positions,
|
||||
indices,
|
||||
size: 5,
|
||||
};
|
||||
},
|
||||
);
|
||||
this.layer.updateModelData(modelData as IAttrubuteAndElements);
|
||||
this.layerService.renderLayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* load terrain texture & offset attribute z
|
||||
*/
|
||||
protected loadTerrainTexture(positions: number[], indices: number[]) {
|
||||
const {
|
||||
widthSegments = 1,
|
||||
heightSegments = 1,
|
||||
terrainTexture,
|
||||
rgb2height = (r: number, g: number, b: number) => r + g + b,
|
||||
} = this.layer.getLayerConfig() as IGeometryLayerStyleOptions;
|
||||
if (this.terrainImage) {
|
||||
// 若当前已经存在 image,直接进行偏移计算(LOD)
|
||||
if (this.terrainImageLoaded) {
|
||||
this.translateVertex(
|
||||
positions,
|
||||
indices,
|
||||
this.terrainImage,
|
||||
widthSegments,
|
||||
heightSegments,
|
||||
rgb2height,
|
||||
);
|
||||
} else {
|
||||
this.terrainImage.onload = () => {
|
||||
this.translateVertex(
|
||||
positions,
|
||||
indices,
|
||||
this.terrainImage,
|
||||
widthSegments,
|
||||
heightSegments,
|
||||
rgb2height,
|
||||
);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// 加载地形贴图、根据地形贴图对 planeGeometry 进行偏移
|
||||
const terrainImage = new Image();
|
||||
this.terrainImage = terrainImage;
|
||||
terrainImage.crossOrigin = 'anonymous';
|
||||
terrainImage.onload = () => {
|
||||
this.terrainImageLoaded = true;
|
||||
// 图片加载完,触发事件,可以进行地形图的顶点计算存储
|
||||
setTimeout(() => this.layer.emit('terrainImageLoaded', null));
|
||||
this.translateVertex(
|
||||
positions,
|
||||
indices,
|
||||
terrainImage,
|
||||
widthSegments,
|
||||
heightSegments,
|
||||
rgb2height,
|
||||
);
|
||||
};
|
||||
terrainImage.src = terrainTexture as string;
|
||||
}
|
||||
}
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
gl,
|
||||
IActiveOption,
|
||||
IAnimateOption,
|
||||
IAttrubuteAndElements,
|
||||
ICameraService,
|
||||
ICoordinateSystemService,
|
||||
IDataState,
|
||||
|
@ -44,6 +45,7 @@ import {
|
|||
ScaleTypes,
|
||||
StyleAttributeField,
|
||||
StyleAttributeOption,
|
||||
Triangulation,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import Source from '@antv/l7-source';
|
||||
|
@ -53,6 +55,7 @@ import { Container } from 'inversify';
|
|||
import { isEqual, isFunction, isObject, isUndefined } from 'lodash';
|
||||
import { BlendTypes } from '../utils/blend';
|
||||
import { handleStyleDataMapping } from '../utils/dataMappingStyle';
|
||||
import { calculateData } from '../utils/layerData';
|
||||
import {
|
||||
createMultiPassRenderer,
|
||||
normalizePasses,
|
||||
|
@ -81,6 +84,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
public clusterZoom: number = 0; // 聚合等级标记
|
||||
public layerType?: string | undefined;
|
||||
public isLayerGroup: boolean = false;
|
||||
public triangulation?: Triangulation | undefined;
|
||||
|
||||
public dataState: IDataState = {
|
||||
dataSourceNeedUpdate: false,
|
||||
|
@ -399,8 +403,55 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
target: this,
|
||||
type: 'add',
|
||||
});
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public updateModelData(data: IAttrubuteAndElements) {
|
||||
if (data.attributes && data.elements) {
|
||||
this.models.map((m) => {
|
||||
m.updateAttributesAndElements(data.attributes, data.elements);
|
||||
});
|
||||
} else {
|
||||
console.warn('data error');
|
||||
}
|
||||
}
|
||||
|
||||
public createModelData(data: any, option?: ISourceCFG) {
|
||||
if (this.layerModel.createModelData) {
|
||||
// 在某些特殊图层中单独构建 attribute & elements
|
||||
return this.layerModel.createModelData(option);
|
||||
}
|
||||
const calEncodeData = this.calculateEncodeData(data, option);
|
||||
const triangulation = this.triangulation;
|
||||
if (calEncodeData && triangulation) {
|
||||
return this.styleAttributeService.createAttributesAndIndices(
|
||||
calEncodeData,
|
||||
triangulation,
|
||||
);
|
||||
} else {
|
||||
return {
|
||||
attributes: undefined,
|
||||
elements: undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public calculateEncodeData(data: any, option?: ISourceCFG) {
|
||||
if (this.inited) {
|
||||
return calculateData(
|
||||
this,
|
||||
this.fontService,
|
||||
this.mapService,
|
||||
this.styleAttributeService,
|
||||
data,
|
||||
option,
|
||||
);
|
||||
} else {
|
||||
console.warn('layer not inited!');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Model初始化前需要更新Model样式
|
||||
*/
|
||||
|
|
|
@ -165,6 +165,7 @@ export default class LineModel extends BaseModel {
|
|||
depth = false,
|
||||
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
|
||||
const { frag, vert, type } = this.getShaders();
|
||||
this.layer.triangulation = LineTriangulation;
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'line_' + type,
|
||||
|
|
|
@ -201,6 +201,9 @@ export default class FillModel extends BaseModel {
|
|||
|
||||
// TODO: 判断当前的点图层的模型是普通地图模式还是地球模式
|
||||
const isGlobel = this.mapService.version === 'GLOBEL';
|
||||
this.layer.triangulation = isGlobel
|
||||
? GlobelPointFillTriangulation
|
||||
: PointFillTriangulation;
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'pointfill_' + type,
|
||||
|
|
|
@ -103,6 +103,7 @@ export default class SimplePointModel extends BaseModel {
|
|||
mask = false,
|
||||
maskInside = true,
|
||||
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
|
||||
this.layer.triangulation = PointTriangulation;
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'simplepoint',
|
||||
|
|
|
@ -77,6 +77,9 @@ export default class FillModel extends BaseModel {
|
|||
mask = false,
|
||||
maskInside = true,
|
||||
} = this.layer.getLayerConfig() as IPolygonLayerStyleOptions;
|
||||
this.layer.triangulation = opacityLinear.enable
|
||||
? polygonTriangulationWithCenter
|
||||
: polygonTriangulation;
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
moduleName: 'polygon',
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
import {
|
||||
IEncodeFeature,
|
||||
IFontService,
|
||||
ILayer,
|
||||
IMapService,
|
||||
IParseDataItem,
|
||||
ISourceCFG,
|
||||
IStyleAttribute,
|
||||
IStyleAttributeService,
|
||||
Position,
|
||||
} from '@antv/l7-core';
|
||||
import { Version } from '@antv/l7-maps';
|
||||
import Source from '@antv/l7-source';
|
||||
import { isColor, normalize, rgb2arr } from '@antv/l7-utils';
|
||||
import { ILineLayerStyleOptions } from '../core/interface';
|
||||
|
||||
function getArrowPoints(p1: Position, p2: Position) {
|
||||
const dir = [p2[0] - p1[0], p2[1] - p1[1]];
|
||||
const normalizeDir = normalize(dir);
|
||||
const arrowPoint = [
|
||||
p1[0] + normalizeDir[0] * 0.0001,
|
||||
p1[1] + normalizeDir[1] * 0.0001,
|
||||
];
|
||||
return arrowPoint;
|
||||
}
|
||||
|
||||
function adjustData2Amap2Coordinates(
|
||||
mappedData: IEncodeFeature[],
|
||||
mapService: IMapService,
|
||||
) {
|
||||
// 根据地图的类型判断是否需要对点位数据进行处理, 若是高德2.0则需要对坐标进行相对偏移
|
||||
if (mappedData.length > 0 && mapService.version === Version['GAODE2.x']) {
|
||||
if (typeof mappedData[0].coordinates[0] === 'number') {
|
||||
// 单个的点数据
|
||||
// @ts-ignore
|
||||
mappedData
|
||||
// TODO: 避免经纬度被重复计算导致坐标位置偏移
|
||||
.filter((d) => !d.originCoordinates)
|
||||
.map((d) => {
|
||||
d.version = Version['GAODE2.x'];
|
||||
// @ts-ignore
|
||||
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
|
||||
// @ts-ignore
|
||||
d.coordinates = this.mapService.lngLatToCoord(d.coordinates);
|
||||
});
|
||||
} else {
|
||||
// 连续的线、面数据
|
||||
// @ts-ignore
|
||||
mappedData
|
||||
// TODO: 避免经纬度被重复计算导致坐标位置偏移
|
||||
.filter((d) => !d.originCoordinates)
|
||||
.map((d) => {
|
||||
d.version = Version['GAODE2.x'];
|
||||
// @ts-ignore
|
||||
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
|
||||
// @ts-ignore
|
||||
d.coordinates = this.mapService.lngLatToCoords(d.coordinates);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function adjustData2SimpleCoordinates(
|
||||
mappedData: IEncodeFeature[],
|
||||
mapService: IMapService,
|
||||
) {
|
||||
if (mappedData.length > 0 && mapService.version === Version.SIMPLE) {
|
||||
mappedData.map((d) => {
|
||||
if (!d.simpleCoordinate) {
|
||||
d.coordinates = unProjectCoordinates(d.coordinates, mapService);
|
||||
d.simpleCoordinate = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function unProjectCoordinates(coordinates: any, mapService: IMapService) {
|
||||
if (typeof coordinates[0] === 'number') {
|
||||
return mapService.simpleMapCoord.unproject(coordinates as [number, number]);
|
||||
}
|
||||
|
||||
if (coordinates[0] && coordinates[0][0] instanceof Array) {
|
||||
// @ts-ignore
|
||||
const coords = [];
|
||||
coordinates.map((coord: any) => {
|
||||
// @ts-ignore
|
||||
const c1 = [];
|
||||
coord.map((co: any) => {
|
||||
c1.push(mapService.simpleMapCoord.unproject(co as [number, number]));
|
||||
});
|
||||
// @ts-ignore
|
||||
coords.push(c1);
|
||||
});
|
||||
// @ts-ignore
|
||||
return coords;
|
||||
} else {
|
||||
// @ts-ignore
|
||||
const coords = [];
|
||||
// @ts-ignore
|
||||
coordinates.map((coord) => {
|
||||
coords.push(
|
||||
mapService.simpleMapCoord.unproject(coord as [number, number]),
|
||||
);
|
||||
});
|
||||
// @ts-ignore
|
||||
return coords;
|
||||
}
|
||||
}
|
||||
|
||||
function applyAttributeMapping(
|
||||
attribute: IStyleAttribute,
|
||||
record: { [key: string]: unknown },
|
||||
minimumColor?: string,
|
||||
) {
|
||||
if (!attribute.scale) {
|
||||
return [];
|
||||
}
|
||||
const scalers = attribute?.scale?.scalers || [];
|
||||
const params: unknown[] = [];
|
||||
|
||||
scalers.forEach(({ field }) => {
|
||||
if (record.hasOwnProperty(field) || attribute.scale?.type === 'variable') {
|
||||
// TODO:多字段,常量
|
||||
params.push(record[field]);
|
||||
}
|
||||
});
|
||||
|
||||
const mappingResult = attribute.mapping ? attribute.mapping(params) : [];
|
||||
if (attribute.name === 'color' && !isColor(mappingResult[0])) {
|
||||
return [minimumColor];
|
||||
}
|
||||
return mappingResult;
|
||||
}
|
||||
|
||||
function mapping(
|
||||
attributes: IStyleAttribute[],
|
||||
data: IParseDataItem[],
|
||||
fontService: IFontService,
|
||||
mapService: IMapService,
|
||||
minimumColor?: string,
|
||||
layer?: ILayer,
|
||||
): IEncodeFeature[] {
|
||||
const {
|
||||
arrow = {
|
||||
enable: false,
|
||||
},
|
||||
} = layer?.getLayerConfig() as ILineLayerStyleOptions;
|
||||
const mappedData = data.map((record: IParseDataItem) => {
|
||||
const encodeRecord: IEncodeFeature = {
|
||||
id: record._id,
|
||||
coordinates: record.coordinates,
|
||||
};
|
||||
|
||||
attributes
|
||||
.filter((attribute) => attribute.scale !== undefined)
|
||||
.forEach((attribute: IStyleAttribute) => {
|
||||
let values = applyAttributeMapping(attribute, record, minimumColor);
|
||||
|
||||
attribute.needRemapping = false;
|
||||
|
||||
// TODO: 支持每个属性配置 postprocess
|
||||
if (attribute.name === 'color') {
|
||||
values = values.map((c: unknown) => {
|
||||
return rgb2arr(c as string);
|
||||
});
|
||||
}
|
||||
// @ts-ignore
|
||||
encodeRecord[attribute.name] =
|
||||
Array.isArray(values) && values.length === 1 ? values[0] : values;
|
||||
|
||||
// 增加对 layer/text/iconfont unicode 映射的解析
|
||||
if (attribute.name === 'shape') {
|
||||
encodeRecord.shape = fontService.getIconFontKey(
|
||||
encodeRecord[attribute.name] as string,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (encodeRecord.shape === 'line' && arrow.enable) {
|
||||
// 只有在线图层且支持配置箭头的时候进行插入顶点的处理
|
||||
const coords = encodeRecord.coordinates as Position[];
|
||||
const arrowPoint = getArrowPoints(coords[0], coords[1]);
|
||||
encodeRecord.coordinates.splice(1, 0, arrowPoint, arrowPoint);
|
||||
}
|
||||
return encodeRecord;
|
||||
}) as IEncodeFeature[];
|
||||
// 调整数据兼容 Amap2.0
|
||||
adjustData2Amap2Coordinates(mappedData, mapService);
|
||||
|
||||
// 调整数据兼容 SimpleCoordinates
|
||||
adjustData2SimpleCoordinates(mappedData, mapService);
|
||||
|
||||
return mappedData;
|
||||
}
|
||||
|
||||
export function calculateData(
|
||||
layer: ILayer,
|
||||
fontService: IFontService,
|
||||
mapService: IMapService,
|
||||
styleAttributeService: IStyleAttributeService,
|
||||
data: any,
|
||||
options: ISourceCFG | undefined,
|
||||
): IEncodeFeature[] {
|
||||
const source = new Source(data, options);
|
||||
const bottomColor = layer.getBottomColor();
|
||||
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
|
||||
const { dataArray } = source.data;
|
||||
const filterData = dataArray;
|
||||
|
||||
const mappedEncodeData = mapping(
|
||||
attributes,
|
||||
filterData,
|
||||
fontService,
|
||||
mapService,
|
||||
bottomColor,
|
||||
layer,
|
||||
);
|
||||
source.destroy();
|
||||
return mappedEncodeData;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
gl,
|
||||
IAttribute,
|
||||
IElements,
|
||||
IModel,
|
||||
IModelDrawOptions,
|
||||
IModelInitializationOptions,
|
||||
|
@ -107,6 +108,27 @@ export default class ReglModel implements IModel {
|
|||
this.drawParams = drawParams;
|
||||
}
|
||||
|
||||
public updateAttributesAndElements(
|
||||
attributes: { [key: string]: IAttribute },
|
||||
elements: IElements,
|
||||
) {
|
||||
const reglAttributes: { [key: string]: regl.Attribute } = {};
|
||||
Object.keys(attributes).forEach((name: string) => {
|
||||
reglAttributes[name] = (attributes[name] as ReglAttribute).get();
|
||||
});
|
||||
this.drawParams.attributes = reglAttributes;
|
||||
this.drawParams.elements = (elements as ReglElements).get();
|
||||
|
||||
this.drawCommand = this.reGl(this.drawParams);
|
||||
const pickDrawParams = cloneDeep(this.drawParams);
|
||||
pickDrawParams.blend = {
|
||||
...pickDrawParams.blend,
|
||||
enable: false,
|
||||
};
|
||||
|
||||
this.drawPickCommand = this.reGl(pickDrawParams);
|
||||
}
|
||||
|
||||
public updateAttributes(attributes: { [key: string]: IAttribute }) {
|
||||
const reglAttributes: { [key: string]: regl.Attribute } = {};
|
||||
Object.keys(attributes).forEach((name: string) => {
|
||||
|
|
|
@ -23,6 +23,12 @@ export default function geoJSON(
|
|||
): IParserData {
|
||||
const resultData: IParseDataItem[] = [];
|
||||
const featureKeys: IFeatureKey = {};
|
||||
if (!data.features) {
|
||||
data.features = [];
|
||||
return {
|
||||
dataArray: [],
|
||||
};
|
||||
}
|
||||
data.features = data.features.filter((item: Feature) => {
|
||||
const geometry: Geometry | null = item.geometry as Geometry;
|
||||
return (
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
// @ts-nocheck
|
||||
import { Scene, json } from '@antv/l7';
|
||||
import { PointLayer } from '@antv/l7-layers';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
import { csvParse } from 'd3-dsv';
|
||||
import { styled, withStyles } from '@material-ui/core/styles';
|
||||
import Slider from '@material-ui/core/Slider';
|
||||
|
||||
export default class Demo extends React.Component {
|
||||
private scene: Scene;
|
||||
private layer: any;
|
||||
|
||||
constructor() {
|
||||
this.state = {
|
||||
currentYear: 50,
|
||||
modelDatas: undefined,
|
||||
};
|
||||
}
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public getSortedData(dataList: { DateTime: string }[]) {
|
||||
const res = {},
|
||||
years = [];
|
||||
dataList.map((data) => {
|
||||
const { DateTime } = data;
|
||||
const year = DateTime.slice(0, 4);
|
||||
if (res[year]) {
|
||||
res[year].push({
|
||||
Latitude: Number(data.Latitude),
|
||||
Longitude: Number(data.Longitude),
|
||||
Depth: Number(data.Depth),
|
||||
Magnitude: Number(data.Magnitude),
|
||||
});
|
||||
} else {
|
||||
years.push(year);
|
||||
res[year] = [];
|
||||
res[year].push({
|
||||
Latitude: Number(data.Latitude),
|
||||
Longitude: Number(data.Longitude),
|
||||
Depth: Number(data.Depth),
|
||||
Magnitude: Number(data.Magnitude),
|
||||
});
|
||||
}
|
||||
});
|
||||
return {
|
||||
res,
|
||||
years,
|
||||
};
|
||||
}
|
||||
|
||||
public getModelDatas(layer, sortedData, years, parser) {
|
||||
const modelDatas = {};
|
||||
years.map((year) => {
|
||||
modelDatas[year] = layer.createModelData(sortedData[year], parser);
|
||||
});
|
||||
|
||||
this.setState({
|
||||
modelDatas,
|
||||
});
|
||||
}
|
||||
|
||||
public generateData(size) {
|
||||
let data = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
data.push({
|
||||
lng: Math.random() * 180,
|
||||
lat: Math.random() * 80 - 40,
|
||||
c: Math.random() > 0.5 ? '#f00' : '#ff0',
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [-120, 36],
|
||||
pitch: 0,
|
||||
zoom: 6,
|
||||
}),
|
||||
});
|
||||
this.scene = scene;
|
||||
|
||||
scene.on('loaded', () => {
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/bmw-prod/6b15fe03-9d5b-4779-831d-ec30aa2e4738.csv',
|
||||
)
|
||||
.then((res) => res.text())
|
||||
.then((res) => {
|
||||
const originData = csvParse(res);
|
||||
const { res: sortedData, years } = this.getSortedData(originData);
|
||||
const parser = {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'Longitude',
|
||||
y: 'Latitude',
|
||||
},
|
||||
};
|
||||
|
||||
let layer = new PointLayer()
|
||||
.source(sortedData[years[0]], parser)
|
||||
.shape('simple')
|
||||
.size('Magnitude', (v) => Math.pow(v, 2))
|
||||
.color('Magnitude', [
|
||||
'#ffffb2',
|
||||
'#fed976',
|
||||
'#feb24c',
|
||||
'#fd8d3c',
|
||||
'#f03b20',
|
||||
'#bd0026',
|
||||
])
|
||||
.style({
|
||||
opacity: 0.5,
|
||||
});
|
||||
|
||||
scene.addLayer(layer);
|
||||
this.layer = layer;
|
||||
|
||||
this.getModelDatas(layer, sortedData, years, parser);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public timelinechange(time) {
|
||||
if (time !== this.state.currentYear) {
|
||||
this.layer.updateModelData(this.state.modelDatas[time]);
|
||||
this.scene.render();
|
||||
this.setState({
|
||||
currentYear: time,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
>
|
||||
{this.state.modelDatas !== undefined && (
|
||||
<RangeInput
|
||||
min={1988}
|
||||
max={2018}
|
||||
value={this?.state?.currentYear || 1988}
|
||||
onChange={(e) => this.timelinechange(e)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const PositionContainer = styled('div')({
|
||||
position: 'absolute',
|
||||
zIndex: 1,
|
||||
bottom: '40px',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
});
|
||||
|
||||
const SliderInput = withStyles({
|
||||
root: {
|
||||
marginLeft: 12,
|
||||
width: '40%',
|
||||
},
|
||||
valueLabel: {
|
||||
'& span': {
|
||||
background: 'none',
|
||||
color: '#000',
|
||||
},
|
||||
},
|
||||
})(Slider);
|
||||
|
||||
function RangeInput({ min, max, value, onChange }) {
|
||||
return (
|
||||
<PositionContainer>
|
||||
<SliderInput
|
||||
min={min}
|
||||
max={max}
|
||||
value={value}
|
||||
onChange={(event, newValue) => onChange(newValue)}
|
||||
valueLabelDisplay="auto"
|
||||
valueLabelFormat={(t) => t}
|
||||
/>
|
||||
</PositionContainer>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
// @ts-nocheck
|
||||
// @ts-ignore
|
||||
import { Scene } from '@antv/l7';
|
||||
import { PointLayer } from '@antv/l7-layers';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Demo extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public generateData(size) {
|
||||
let data = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
data.push({
|
||||
lng: Math.random() * 180,
|
||||
lat: Math.random() * 80 - 40,
|
||||
c: Math.random() > 0.5 ? '#f00' : '#ff0',
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [120, 30],
|
||||
pitch: 0,
|
||||
zoom: 2,
|
||||
}),
|
||||
});
|
||||
|
||||
const data1 = this.generateData(1000);
|
||||
const data2 = this.generateData(10000);
|
||||
|
||||
const layer = new PointLayer()
|
||||
.source(data1, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat',
|
||||
},
|
||||
})
|
||||
.size(10)
|
||||
// .color('#f00')
|
||||
.color('c', (v) => v)
|
||||
// .shape('circle')
|
||||
.shape('simple')
|
||||
.active(true);
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
|
||||
let data1cache = layer.createModelData(data1, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat',
|
||||
},
|
||||
});
|
||||
|
||||
console.log(data1cache);
|
||||
|
||||
let data2cache = layer.createModelData(data2, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat',
|
||||
},
|
||||
});
|
||||
|
||||
let c = 0;
|
||||
setInterval(() => {
|
||||
if (c === 0) {
|
||||
c = 1;
|
||||
layer.updateModelData(data2cache);
|
||||
scene.render();
|
||||
} else {
|
||||
c = 0;
|
||||
layer.updateModelData(data1cache);
|
||||
scene.render();
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
// @ts-nocheck
|
||||
// @ts-ignore
|
||||
import { Scene } from '@antv/l7';
|
||||
import { PointLayer, LineLayer } from '@antv/l7-layers';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Demo extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public generateData(size) {
|
||||
let data = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
data.push({
|
||||
lng: Math.random() * 180,
|
||||
lat: Math.random() * 80 - 40,
|
||||
c: Math.random() > 0.5 ? '#f00' : '#ff0',
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [110, 30],
|
||||
pitch: 0,
|
||||
zoom: 4,
|
||||
}),
|
||||
});
|
||||
|
||||
// const data1 = this.generateData(1000);
|
||||
// const data2 = this.generateData(10000);
|
||||
const data1 = {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
c: '#f00',
|
||||
},
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[100.37109375, 32.32427558887655],
|
||||
[101.689453125, 28.844673680771795],
|
||||
[104.853515625, 30.524413269923986],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const data2 = {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
c: '#ff0',
|
||||
},
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[109.6875, 39.90973623453719],
|
||||
[115.75195312499999, 39.90973623453719],
|
||||
[109.3359375, 37.579412513438385],
|
||||
[115.57617187499999, 36.80928470205937],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const layer = new LineLayer()
|
||||
.source(data1)
|
||||
.size(2)
|
||||
.color('c', (v) => v)
|
||||
.shape('line')
|
||||
.active(true);
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
|
||||
// let data1cache = layer.createModelData(data1, {});
|
||||
|
||||
// console.log(data1cache);
|
||||
|
||||
// let data2cache = layer.createModelData(data2, {});
|
||||
// console.log('data2cache', data2cache)
|
||||
|
||||
// let c = 0;
|
||||
// setInterval(() => {
|
||||
// if (c === 0) {
|
||||
// c = 1;
|
||||
// layer.updateModelData(data2cache);
|
||||
// scene.render();
|
||||
// } else {
|
||||
// c = 0;
|
||||
// layer.updateModelData(data1cache);
|
||||
// scene.render();
|
||||
// }
|
||||
// }, 1000);
|
||||
|
||||
setTimeout(() => {
|
||||
let data2cache = layer.createModelData(data2);
|
||||
layer.updateModelData(data2cache);
|
||||
scene.render();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
// @ts-nocheck
|
||||
// @ts-ignore
|
||||
import { Scene } from '@antv/l7';
|
||||
import {
|
||||
PointLayer,
|
||||
LineLayer,
|
||||
PolygonLayer,
|
||||
GeometryLayer,
|
||||
} from '@antv/l7-layers';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Demo extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public generateData(size) {
|
||||
let data = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
data.push({
|
||||
lng: Math.random() * 180,
|
||||
lat: Math.random() * 80 - 40,
|
||||
c: Math.random() > 0.5 ? '#f00' : '#ff0',
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
pitch: 60,
|
||||
center: [120.1025, 30.2594],
|
||||
rotation: 160,
|
||||
zoom: 14,
|
||||
}),
|
||||
});
|
||||
|
||||
const layer = new GeometryLayer()
|
||||
.style({
|
||||
width: 0.074,
|
||||
height: 0.061,
|
||||
center: [120.1025, 30.2594],
|
||||
widthSegments: 100,
|
||||
heightSegments: 100,
|
||||
// widthSegments: 10,
|
||||
// heightSegments: 10,
|
||||
mapTexture:
|
||||
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*gA0NRbuOF5cAAAAAAAAAAAAAARQnAQ',
|
||||
terrainTexture:
|
||||
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*eYFaRYlnnOUAAAAAAAAAAAAAARQnAQ',
|
||||
rgb2height: (r: number, g: number, b: number) => {
|
||||
let h =
|
||||
-10000.0 +
|
||||
(r * 255.0 * 256.0 * 256.0 + g * 255.0 * 256.0 + b * 255.0) * 0.1;
|
||||
h = h / 20 - 127600;
|
||||
h = Math.max(0, h);
|
||||
return h;
|
||||
},
|
||||
})
|
||||
.color('#f00');
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
|
||||
let cache10 = null,
|
||||
cache100 = null;
|
||||
|
||||
layer.on('terrainImageLoaded', () => {
|
||||
console.log('terrainImageLoaded');
|
||||
|
||||
cache10 = layer.createModelData([], {
|
||||
widthSegments: 10,
|
||||
heightSegments: 10,
|
||||
});
|
||||
|
||||
cache100 = layer.createModelData([], {
|
||||
widthSegments: 100,
|
||||
heightSegments: 100,
|
||||
});
|
||||
});
|
||||
|
||||
let currentCache = 'cache100';
|
||||
scene.on('zoom', ({ value }) => {
|
||||
if (!cache10 || !cache100) return;
|
||||
if (value < 14.5) {
|
||||
if (currentCache !== 'cache10') {
|
||||
console.log('set cache10');
|
||||
layer.updateModelData(cache10);
|
||||
currentCache = 'cache10';
|
||||
}
|
||||
} else {
|
||||
if (currentCache !== 'cache100') {
|
||||
console.log('set cache100');
|
||||
layer.updateModelData(cache100);
|
||||
currentCache = 'cache100';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
// @ts-nocheck
|
||||
// @ts-ignore
|
||||
import { Scene } from '@antv/l7';
|
||||
import { PointLayer, LineLayer, PolygonLayer } from '@antv/l7-layers';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Demo extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public generateData(size) {
|
||||
let data = [];
|
||||
for (let i = 0; i < size; i++) {
|
||||
data.push({
|
||||
lng: Math.random() * 180,
|
||||
lat: Math.random() * 80 - 40,
|
||||
c: Math.random() > 0.5 ? '#f00' : '#ff0',
|
||||
});
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [110, 30],
|
||||
pitch: 0,
|
||||
zoom: 4,
|
||||
}),
|
||||
});
|
||||
|
||||
const data1 = {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[98.4375, 35.746512259918504],
|
||||
[98.173828125, 30.14512718337613],
|
||||
[104.94140625, 30.600093873550072],
|
||||
[98.4375, 35.746512259918504],
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const data2 = {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [
|
||||
[
|
||||
[110.390625, 38.06539235133249],
|
||||
[106.435546875, 33.50475906922609],
|
||||
[112.763671875, 32.47269502206151],
|
||||
[109.072265625, 27.21555620902969],
|
||||
[117.24609374999999, 27.605670826465445],
|
||||
[118.037109375, 30.372875188118016],
|
||||
[115.927734375, 34.30714385628804],
|
||||
[111.97265625, 36.87962060502676],
|
||||
[110.390625, 38.06539235133249],
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const layer = new PolygonLayer()
|
||||
.source(data1)
|
||||
.size(2)
|
||||
.color('#f00')
|
||||
.shape('fill')
|
||||
.active(true);
|
||||
|
||||
scene.on('loaded', () => {
|
||||
scene.addLayer(layer);
|
||||
|
||||
setTimeout(() => {
|
||||
let data2cache = layer.createModelData(data2);
|
||||
layer.updateModelData(data2cache);
|
||||
scene.render();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,11 +1,21 @@
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
|
||||
import UpdateAttrAndEle from './components/updateAttrAndEle';
|
||||
import UpdateAttrAndEle_line from './components/updateAttrAndEle_line';
|
||||
import UpdateAttrAndEle_polygon from './components/updateAttrAndEle_polygon';
|
||||
import UpdateAttrAndEle_planeGeometry from './components/updateAttrAndEle_planeGeometry';
|
||||
import UpdateAttrTimeLine from './components/updataPointsTimeLine';
|
||||
import PointTest from './components/Map';
|
||||
import BigLine from './components/BigLine';
|
||||
import DataUpdate from './components/DataUpdate';
|
||||
// @ts-ignore
|
||||
|
||||
storiesOf('地图性能检测', module)
|
||||
.add('更新数据 update point attr&ele', () => <UpdateAttrAndEle />)
|
||||
.add('更新数据 update line attr&ele', () => <UpdateAttrAndEle_line />)
|
||||
.add('更新数据 update polygon attr&ele', () => <UpdateAttrAndEle_polygon />)
|
||||
.add('更新数据 update plane geometry attr&ele', () => <UpdateAttrAndEle_planeGeometry />)
|
||||
.add('更新数据 update updateAttrTimeLine', () => <UpdateAttrTimeLine />)
|
||||
.add('点', () => <PointTest />)
|
||||
.add('BigLine', () => <BigLine />)
|
||||
.add('DataUpdate', () => <DataUpdate />);
|
||||
|
|
|
@ -31,7 +31,7 @@ export default class Demo extends React.Component {
|
|||
center: [120.1025, 30.2594],
|
||||
widthSegments: 200,
|
||||
heightSegments: 200,
|
||||
terrainClipHeight: 1,
|
||||
// terrainClipHeight: 1,
|
||||
mapTexture:
|
||||
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*gA0NRbuOF5cAAAAAAAAAAAAAARQnAQ',
|
||||
terrainTexture:
|
||||
|
|
Loading…
Reference in New Issue