mirror of https://gitee.com/antv-l7/antv-l7
feat(layers): add polygon3d , pointimagelayer
This commit is contained in:
parent
eb9e220ede
commit
a9b406fea1
|
@ -246,7 +246,6 @@ export default class StyleAttributeService implements IStyleAttributeService {
|
|||
const attributes: {
|
||||
[attributeName: string]: IAttribute;
|
||||
} = {};
|
||||
|
||||
descriptors.forEach((descriptor, attributeIdx) => {
|
||||
if (descriptor) {
|
||||
// IAttribute 参数透传
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"@l7/utils": "^0.0.1",
|
||||
"@turf/meta": "^6.0.2",
|
||||
"@types/d3-color": "^1.2.2",
|
||||
"inversify": "^5.0.1",
|
||||
"d3-array": "^2.3.1",
|
||||
"d3-color": "^1.4.0",
|
||||
"d3-scale": "^3.1.0",
|
||||
|
|
|
@ -103,6 +103,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
|
||||
protected layerSource: Source;
|
||||
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
private encodedData: IEncodeFeature[];
|
||||
|
||||
private configSchema: object;
|
||||
|
@ -117,9 +120,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> implements ILayer {
|
|||
@lazyInject(TYPES.IShaderModuleService)
|
||||
private readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
private readonly rendererService: IRendererService;
|
||||
|
||||
@lazyInject(TYPES.IMapService)
|
||||
private readonly map: IMapService;
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
export type IPosition = [number, number, number] | [number, number];
|
||||
export type IPath = IPosition[];
|
||||
export enum ShapeType3D {
|
||||
CYLINDER = 'cylinder',
|
||||
SQUARECOLUMN = 'squareColumn',
|
||||
TRIANGLECOLUMN = 'triangleColumn',
|
||||
HEXAGONCOLUMN = 'hexagonColumn',
|
||||
PENTAGONCOLUMN = 'pentagonColumn',
|
||||
}
|
||||
export enum ShapeType2D {
|
||||
CIRCLE = 'circle',
|
||||
SQUARE = 'square',
|
||||
TRIANGLE = 'triangle',
|
||||
HEXAGON = 'hexagon',
|
||||
PENTAGON = 'pentagon',
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成规则多边形顶点个数
|
||||
* @param pointCount 顶点个数 3 => 三角形
|
||||
* @param start 顶点起始角度 调整图形的方向
|
||||
*/
|
||||
export function polygonPath(pointCount: number, start: number = 0): IPath {
|
||||
const step = (Math.PI * 2) / pointCount;
|
||||
const line = [];
|
||||
for (let i = 0; i < pointCount; i++) {
|
||||
line.push(step * i + (start * Math.PI) / 12);
|
||||
}
|
||||
const path: IPath = line.map((t) => {
|
||||
const x = Math.sin(t + Math.PI / 4);
|
||||
const y = Math.cos(t + Math.PI / 4);
|
||||
return [x, y, 0];
|
||||
});
|
||||
// path.push(path[0]);
|
||||
return path;
|
||||
}
|
||||
|
||||
export function circle(): IPath {
|
||||
return polygonPath(30);
|
||||
}
|
||||
export function square(): IPath {
|
||||
return polygonPath(4);
|
||||
}
|
||||
export function triangle(): IPath {
|
||||
return polygonPath(3);
|
||||
}
|
||||
export function hexagon(): IPath {
|
||||
return polygonPath(6);
|
||||
}
|
||||
export function pentagon(): IPath {
|
||||
return polygonPath(5);
|
||||
}
|
||||
|
||||
export const geometryShape = {
|
||||
[ShapeType2D.CIRCLE]: circle,
|
||||
[ShapeType2D.HEXAGON]: hexagon,
|
||||
[ShapeType2D.TRIANGLE]: triangle,
|
||||
[ShapeType2D.SQUARE]: square,
|
||||
[ShapeType2D.PENTAGON]: pentagon,
|
||||
[ShapeType3D.CYLINDER]: circle,
|
||||
[ShapeType3D.HEXAGONCOLUMN]: hexagon,
|
||||
[ShapeType3D.TRIANGLECOLUMN]: triangle,
|
||||
[ShapeType3D.SQUARECOLUMN]: square,
|
||||
[ShapeType3D.PENTAGONCOLUMN]: pentagon,
|
||||
};
|
|
@ -0,0 +1,83 @@
|
|||
import earcut from 'earcut';
|
||||
import { IPath } from './Path';
|
||||
export interface IExtrudeGeomety {
|
||||
positions: number[];
|
||||
index: number[];
|
||||
}
|
||||
/**
|
||||
* 拉伸多边形顶点,返回拉伸后的顶点信息
|
||||
* @param paths 路径数据组
|
||||
* @param extrude 是否拉伸
|
||||
*/
|
||||
export default function extrudePolygon(path: IPath[]): IExtrudeGeomety {
|
||||
const p1 = path[0][0];
|
||||
const p2 = path[0][path[0].length - 1];
|
||||
if (p1[0] === p2[0] && p1[1] === p2[1]) {
|
||||
path[0] = path[0].slice(0, path[0].length - 1);
|
||||
}
|
||||
|
||||
const n = path[0].length;
|
||||
const flattengeo = earcut.flatten(path);
|
||||
const { vertices, dimensions } = flattengeo;
|
||||
const positions = [];
|
||||
const indexArray = [];
|
||||
// 设置顶部z值
|
||||
for (let j = 0; j < vertices.length / dimensions; j++) {
|
||||
if (dimensions === 2) {
|
||||
positions.push(vertices[j * 2], vertices[j * 2 + 1], 1);
|
||||
} else {
|
||||
positions.push(vertices[j * 3], vertices[j * 3 + 1], 1);
|
||||
}
|
||||
}
|
||||
const triangles = earcut(
|
||||
flattengeo.vertices,
|
||||
flattengeo.holes,
|
||||
flattengeo.dimensions,
|
||||
);
|
||||
indexArray.push(...triangles);
|
||||
for (let i = 0; i < n; i++) {
|
||||
const prePoint = flattengeo.vertices.slice(
|
||||
i * dimensions,
|
||||
(i + 1) * dimensions,
|
||||
);
|
||||
let nextPoint = flattengeo.vertices.slice(
|
||||
(i + 2) * dimensions,
|
||||
(i + 3) * dimensions,
|
||||
);
|
||||
if (nextPoint.length === 0) {
|
||||
nextPoint = flattengeo.vertices.slice(0, dimensions);
|
||||
}
|
||||
const indexOffset = positions.length / 3;
|
||||
positions.push(
|
||||
prePoint[0],
|
||||
prePoint[1],
|
||||
1,
|
||||
nextPoint[0],
|
||||
nextPoint[1],
|
||||
1,
|
||||
prePoint[0],
|
||||
prePoint[1],
|
||||
0,
|
||||
nextPoint[0],
|
||||
nextPoint[1],
|
||||
0,
|
||||
);
|
||||
indexArray.push(...[1, 2, 0, 3, 2, 1].map((v) => v + indexOffset));
|
||||
}
|
||||
return {
|
||||
positions,
|
||||
index: indexArray,
|
||||
};
|
||||
}
|
||||
export function fillPolygon(points: IPath[]) {
|
||||
const flattengeo = earcut.flatten(points);
|
||||
const triangles = earcut(
|
||||
flattengeo.vertices,
|
||||
flattengeo.holes,
|
||||
flattengeo.dimensions,
|
||||
);
|
||||
return {
|
||||
positions: flattengeo.vertices,
|
||||
index: triangles,
|
||||
};
|
||||
}
|
|
@ -1,11 +1,21 @@
|
|||
import { IEncodeFeature } from '@l7/core';
|
||||
import { vec3 } from 'gl-matrix';
|
||||
import getNormals from '../utils/polylineNormal';
|
||||
import extrudePolygon, { IExtrudeGeomety } from './shape/extrude';
|
||||
import { geometryShape, ShapeType2D, ShapeType3D } from './shape/Path';
|
||||
import {
|
||||
geometryShape,
|
||||
IPosition,
|
||||
ShapeType2D,
|
||||
ShapeType3D,
|
||||
} from './shape/Path';
|
||||
interface IGeometryCache {
|
||||
[key: string]: IExtrudeGeomety;
|
||||
}
|
||||
const GeometryCache: IGeometryCache = {};
|
||||
/**
|
||||
* 计算2D 填充点图顶点
|
||||
* @param feature 映射feature
|
||||
*/
|
||||
export function PointFillTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
return {
|
||||
|
@ -15,6 +25,10 @@ export function PointFillTriangulation(feature: IEncodeFeature) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算3D 拉伸点图
|
||||
* @param feature 映射feature
|
||||
*/
|
||||
export function PointExtrudeTriangulation(feature: IEncodeFeature) {
|
||||
const { shape } = feature;
|
||||
const { positions, index } = getGeometry(shape as ShapeType3D);
|
||||
|
@ -26,6 +40,46 @@ export function PointExtrudeTriangulation(feature: IEncodeFeature) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算图片标注
|
||||
* @param feature 映射feature
|
||||
*/
|
||||
export function PointImageTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
return {
|
||||
vertices: [...coordinates],
|
||||
indices: [0],
|
||||
size: coordinates.length,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 线三角化
|
||||
* @param feature 映射feature
|
||||
*/
|
||||
export function LineTriangulation(feature: IEncodeFeature) {
|
||||
const { coordinates } = feature;
|
||||
const line = getNormals(coordinates as number[][], false, 0);
|
||||
return {
|
||||
vertices: line.attrPos, // [ x,y,z, distance, miter ]
|
||||
indices: line.attrIndex,
|
||||
normals: line.normals,
|
||||
size: 5,
|
||||
};
|
||||
}
|
||||
|
||||
export function PolygonExtrudeTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = feature.coordinates as IPosition[][];
|
||||
const { positions, index } = extrudePolygon(coordinates);
|
||||
|
||||
return {
|
||||
vertices: positions, // [ x, y, z ]
|
||||
indices: index,
|
||||
normals: Array.from(computeVertexNormals(positions, index)),
|
||||
size: 3,
|
||||
};
|
||||
}
|
||||
|
||||
function getGeometry(shape: ShapeType3D): IExtrudeGeomety {
|
||||
if (GeometryCache && GeometryCache[shape]) {
|
||||
return GeometryCache[shape];
|
||||
|
@ -37,6 +91,7 @@ function getGeometry(shape: ShapeType3D): IExtrudeGeomety {
|
|||
GeometryCache[shape] = geometry;
|
||||
return geometry;
|
||||
}
|
||||
|
||||
function computeVertexNormals(
|
||||
positions: number[],
|
||||
indexArray: number[],
|
||||
|
@ -75,6 +130,7 @@ function computeVertexNormals(
|
|||
normalizeNormals(normals);
|
||||
return normals;
|
||||
}
|
||||
|
||||
function normalizeNormals(normals: Float32Array) {
|
||||
for (let i = 0, li = normals.length; i < li; i += 3) {
|
||||
const normal = vec3.fromValues(normals[i], normals[i + 1], normals[i + 2]);
|
||||
|
@ -83,3 +139,9 @@ function normalizeNormals(normals: Float32Array) {
|
|||
normals.set(newNormal, i);
|
||||
}
|
||||
}
|
||||
|
||||
function checkIsClosed(points: number[][][]) {
|
||||
const p1 = points[0][0];
|
||||
const p2 = points[0][points[0].length - 1];
|
||||
return p1[0] === p2[0] && p1[1] === p2[1];
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
import { container, ILayerPlugin, TYPES } from '@l7/core';
|
||||
import BaseLayer from './core/BaseLayer';
|
||||
import Point3dLayer from './point/extrude';
|
||||
// import HeatMapLayer from './heatmap';
|
||||
// import Line from './line';
|
||||
import LineLayer from './line/index';
|
||||
import Point3dLayer from './point/extrude';
|
||||
import PointImageLayer from './point/image';
|
||||
import PointLayer from './point/index';
|
||||
// import Point from './point/point';
|
||||
import PolygonLayer from './polygon';
|
||||
import Polygon3DLayer from './polygon/polygon3D';
|
||||
// import ImageLayer from './raster';
|
||||
|
||||
import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin';
|
||||
|
@ -65,7 +67,9 @@ export {
|
|||
PointLayer,
|
||||
PolygonLayer,
|
||||
Point3dLayer,
|
||||
// Point,
|
||||
PointImageLayer,
|
||||
LineLayer,
|
||||
Polygon3DLayer,
|
||||
// Line,
|
||||
// ImageLayer,
|
||||
// HeatMapLayer,
|
||||
|
|
|
@ -1,102 +1,154 @@
|
|||
// import {
|
||||
// gl,
|
||||
// IRendererService,
|
||||
// IShaderModuleService,
|
||||
// lazyInject,
|
||||
// TYPES,
|
||||
// } from '@l7/core';
|
||||
// import BaseLayer from '../core/BaseLayer';
|
||||
// import LineBuffer from './buffers/line';
|
||||
// import line_frag from './shaders/line_frag.glsl';
|
||||
// import line_vert from './shaders/line_vert.glsl';
|
||||
// export default class LineLayer extends BaseLayer {
|
||||
// public name: string = 'LineLayer';
|
||||
// @lazyInject(TYPES.IShaderModuleService)
|
||||
// private readonly shaderModule: IShaderModuleService;
|
||||
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import { LineTriangulation } from '../core/triangulation';
|
||||
import line_frag from './shaders/line_frag.glsl';
|
||||
import line_vert from './shaders/line_vert.glsl';
|
||||
interface IPointLayerStyleOptions {
|
||||
opacity: number;
|
||||
}
|
||||
export default class LineLayer extends BaseLayer<IPointLayerStyleOptions> {
|
||||
public name: string = 'LineLayer';
|
||||
|
||||
// @lazyInject(TYPES.IRendererService)
|
||||
// private readonly renderer: IRendererService;
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// protected renderModels() {
|
||||
// this.models.forEach((model) =>
|
||||
// model.draw({
|
||||
// uniforms: {
|
||||
// u_ModelMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
||||
// },
|
||||
// }),
|
||||
// );
|
||||
// return this;
|
||||
// }
|
||||
// protected buildModels(): void {
|
||||
// this.shaderModule.registerModule('line', {
|
||||
// vs: line_vert,
|
||||
// fs: line_frag,
|
||||
// });
|
||||
protected renderModels() {
|
||||
const { opacity } = this.getStyleOptions();
|
||||
this.models.forEach((model) =>
|
||||
model.draw({
|
||||
uniforms: {
|
||||
u_Opacity: opacity || 0,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
// this.models = [];
|
||||
// const { vs, fs, uniforms } = this.shaderModule.getModule('line');
|
||||
// const buffer = new LineBuffer({
|
||||
// data: this.getEncodedData(),
|
||||
// style: this.styleOption,
|
||||
// });
|
||||
// const {
|
||||
// createAttribute,
|
||||
// createBuffer,
|
||||
// createElements,
|
||||
// createModel,
|
||||
// } = this.renderer;
|
||||
protected buildModels() {
|
||||
this.registerBuiltinAttributes(this);
|
||||
this.models = [
|
||||
this.buildLayerModel({
|
||||
moduleName: 'line',
|
||||
vertexShader: line_vert,
|
||||
fragmentShader: line_frag,
|
||||
triangulation: LineTriangulation,
|
||||
blend: {
|
||||
enable: true,
|
||||
func: {
|
||||
srcRGB: gl.SRC_ALPHA,
|
||||
srcAlpha: 1,
|
||||
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
|
||||
dstAlpha: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
// this.models.push(
|
||||
// createModel({
|
||||
// attributes: {
|
||||
// a_Position: createAttribute({
|
||||
// buffer: createBuffer({
|
||||
// data: buffer.attributes.positions,
|
||||
// type: gl.FLOAT,
|
||||
// }),
|
||||
// size: 3,
|
||||
// }),
|
||||
// a_normal: createAttribute({
|
||||
// buffer: createBuffer({
|
||||
// data: buffer.attributes.normals,
|
||||
// type: gl.FLOAT,
|
||||
// }),
|
||||
// size: 3,
|
||||
// }),
|
||||
// a_color: createAttribute({
|
||||
// buffer: createBuffer({
|
||||
// data: buffer.attributes.colors,
|
||||
// type: gl.FLOAT,
|
||||
// }),
|
||||
// size: 4,
|
||||
// }),
|
||||
// a_size: createAttribute({
|
||||
// buffer: createBuffer({
|
||||
// data: buffer.attributes.sizes,
|
||||
// type: gl.FLOAT,
|
||||
// }),
|
||||
// size: 1,
|
||||
// }),
|
||||
// a_miter: createAttribute({
|
||||
// buffer: createBuffer({
|
||||
// data: buffer.attributes.miters,
|
||||
// type: gl.FLOAT,
|
||||
// }),
|
||||
// size: 1,
|
||||
// }),
|
||||
// },
|
||||
// uniforms: {
|
||||
// ...uniforms,
|
||||
// u_opacity: this.styleOption.opacity as number,
|
||||
// },
|
||||
// fs,
|
||||
// vs,
|
||||
// count: buffer.indexArray.length,
|
||||
// elements: createElements({
|
||||
// data: buffer.indexArray,
|
||||
// type: gl.UNSIGNED_INT,
|
||||
// }),
|
||||
// }),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
private registerBuiltinAttributes(layer: ILayer) {
|
||||
// point layer size;
|
||||
layer.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Size',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.DYNAMIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 1,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
const { size } = feature;
|
||||
return Array.isArray(size) ? [size[0]] : [size as number];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// point layer size;
|
||||
layer.styleAttributeService.registerStyleAttribute({
|
||||
name: 'normal',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Normal',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.STATIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 3,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
normal: number[],
|
||||
) => {
|
||||
return normal;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
layer.styleAttributeService.registerStyleAttribute({
|
||||
name: 'miter',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Miter',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.DYNAMIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 1,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
return [vertex[4]];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
layer.styleAttributeService.registerStyleAttribute({
|
||||
name: 'distance',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Distance',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.DYNAMIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 1,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
return [vertex[3]];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
|
||||
attribute float a_miter;
|
||||
attribute vec4 a_color;
|
||||
attribute float a_size;
|
||||
attribute float a_distance;
|
||||
attribute float a_Miter;
|
||||
attribute vec4 a_Color;
|
||||
attribute float a_Size;
|
||||
attribute float a_Distance;
|
||||
attribute float a_dash_array;
|
||||
attribute float a_total_distance;
|
||||
attribute vec3 a_normal;
|
||||
attribute vec3 a_Normal;
|
||||
attribute vec3 a_Position;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
|
||||
|
@ -14,9 +14,9 @@ varying float v_dash_array;
|
|||
varying vec3 v_normal;
|
||||
#pragma include "projection"
|
||||
void main() {
|
||||
v_normal = a_normal;
|
||||
v_color = a_color;
|
||||
vec3 size = a_miter * a_size * v_normal;
|
||||
v_normal = a_Normal;
|
||||
v_color = a_Color;
|
||||
vec3 size = a_Miter * a_Size * v_normal;
|
||||
vec2 offset = project_pixel(size.xy);
|
||||
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0, 1.0));
|
||||
|
|
|
@ -40,7 +40,9 @@ export default class RegisterStyleAttributePlugin implements ILayerPlugin {
|
|||
featureIdx: number,
|
||||
vertex: number[],
|
||||
) => {
|
||||
return vertex.length === 3 ? vertex : [vertex[0], vertex[1], 0];
|
||||
return vertex.length === 2
|
||||
? [vertex[0], vertex[1], 0]
|
||||
: [vertex[0], vertex[1], vertex[2]];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import { PointExtrudeTriangulation } from '../core/triangulation';
|
||||
import pointExtrudeFrag from './shaders/extrude_frag.glsl';
|
||||
import pointExtrudeVert from './shaders/extrude_vert.glsl';
|
||||
import { PointExtrudeTriangulation } from './triangulation';
|
||||
interface IPointLayerStyleOptions {
|
||||
opacity: number;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
import {
|
||||
AttributeType,
|
||||
gl,
|
||||
IEncodeFeature,
|
||||
ILayer,
|
||||
ILayerPlugin,
|
||||
ILogService,
|
||||
IStyleAttributeService,
|
||||
lazyInject,
|
||||
TYPES,
|
||||
} from '@l7/core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import { PointImageTriangulation } from '../core/triangulation';
|
||||
import pointImageFrag from './shaders/image_frag.glsl';
|
||||
import pointImageVert from './shaders/image_vert.glsl';
|
||||
interface IPointLayerStyleOptions {
|
||||
opacity: number;
|
||||
}
|
||||
export function PointTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
return {
|
||||
vertices: [...coordinates, ...coordinates, ...coordinates, ...coordinates],
|
||||
extrude: [-1, -1, 1, -1, 1, 1, -1, 1],
|
||||
indices: [0, 1, 2, 2, 3, 0],
|
||||
size: coordinates.length,
|
||||
};
|
||||
}
|
||||
export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
|
||||
public name: string = 'PointLayer';
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
const { opacity } = this.getStyleOptions();
|
||||
const { createTexture2D } = this.rendererService;
|
||||
this.models.forEach((model) =>
|
||||
model.draw({
|
||||
uniforms: {
|
||||
u_Opacity: opacity || 0,
|
||||
u_texture: createTexture2D({
|
||||
data: this.iconService.getCanvas(),
|
||||
width: 1024,
|
||||
height: this.iconService.canvasHeight || 64,
|
||||
}),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected buildModels() {
|
||||
this.registerBuiltinAttributes(this);
|
||||
this.iconService.on('imageUpdate', () => {
|
||||
this.renderModels();
|
||||
});
|
||||
this.models = [
|
||||
this.buildLayerModel({
|
||||
moduleName: 'pointImage',
|
||||
vertexShader: pointImageVert,
|
||||
fragmentShader: pointImageFrag,
|
||||
triangulation: PointTriangulation,
|
||||
primitive: gl.POINTS,
|
||||
depth: { enable: false },
|
||||
blend: {
|
||||
enable: true,
|
||||
func: {
|
||||
srcRGB: gl.SRC_ALPHA,
|
||||
srcAlpha: 1,
|
||||
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
|
||||
dstAlpha: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
private registerBuiltinAttributes(layer: ILayer) {
|
||||
// point layer size;
|
||||
layer.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Size',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.DYNAMIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 1,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
const { size } = feature;
|
||||
return Array.isArray(size) ? [size[0]] : [size as number];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// point layer size;
|
||||
layer.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,
|
||||
) => {
|
||||
const iconMap = this.iconService.getIconMap();
|
||||
const { shape } = feature;
|
||||
const { x, y } = iconMap[shape as string] || { x: 0, y: 0 };
|
||||
return [x, y];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,18 +1,17 @@
|
|||
precision highp float;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec4 a_color;
|
||||
attribute vec2 a_uv;
|
||||
attribute float a_size;
|
||||
attribute float a_shape;
|
||||
attribute vec4 a_Color;
|
||||
attribute vec2 a_Uv;
|
||||
attribute float a_Size;
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_uv;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
#pragma include "projection"
|
||||
void main() {
|
||||
v_color = a_color;
|
||||
v_uv = a_uv;
|
||||
v_color = a_Color;
|
||||
v_uv = a_Uv;
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
gl_PointSize = a_size;
|
||||
gl_PointSize = a_Size;
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import { PolygonExtrudeTriangulation } from '../core/triangulation';
|
||||
import pointExtrudeFrag from './shaders/polygon_frag.glsl';
|
||||
import pointExtrudeVert from './shaders/polygon_vert.glsl';
|
||||
interface IPointLayerStyleOptions {
|
||||
opacity: number;
|
||||
}
|
||||
export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
|
||||
public name: string = 'PolygonLayer';
|
||||
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected renderModels() {
|
||||
const { opacity } = this.getStyleOptions();
|
||||
this.models.forEach((model) =>
|
||||
model.draw({
|
||||
uniforms: {
|
||||
u_Opacity: opacity || 0,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected buildModels() {
|
||||
this.registerBuiltinAttributes(this);
|
||||
this.models = [
|
||||
this.buildLayerModel({
|
||||
moduleName: 'polygonExtrude',
|
||||
vertexShader: pointExtrudeVert,
|
||||
fragmentShader: pointExtrudeFrag,
|
||||
triangulation: PolygonExtrudeTriangulation,
|
||||
blend: {
|
||||
enable: true,
|
||||
func: {
|
||||
srcRGB: gl.SRC_ALPHA,
|
||||
srcAlpha: 1,
|
||||
dstRGB: gl.ONE_MINUS_SRC_ALPHA,
|
||||
dstAlpha: 1,
|
||||
},
|
||||
},
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
private registerBuiltinAttributes(layer: ILayer) {
|
||||
// point layer size;
|
||||
layer.styleAttributeService.registerStyleAttribute({
|
||||
name: 'normal',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Normal',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.STATIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 3,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
normal: number[],
|
||||
) => {
|
||||
return normal;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
layer.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Size',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.DYNAMIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 1,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
const { size } = feature;
|
||||
return Array.isArray(size) ? [size[0]] : [size as number];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
attribute vec4 a_Color;
|
||||
attribute vec3 a_Position;
|
||||
// attribute vec3 a_normal;
|
||||
attribute vec3 a_Normal;
|
||||
attribute float a_Size;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
|
||||
varying vec4 v_Color;
|
||||
|
@ -9,8 +10,8 @@ varying vec4 v_Color;
|
|||
#pragma include "picking"
|
||||
|
||||
void main() {
|
||||
v_Color = a_Color;
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
v_Color = vec4(a_Normal,1.0);
|
||||
vec4 project_pos = project_position(vec4(a_Position.xy,a_Position.z * a_Size, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
|
|
|
@ -210,12 +210,20 @@ export default function(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
const pickData = [];
|
||||
for (let i = 0; i < miters.length; i++) {
|
||||
pickData.push(
|
||||
attrPos[i * 3],
|
||||
attrPos[i * 3 + 1],
|
||||
attrPos[i * 3 + 1],
|
||||
attrDistance[i],
|
||||
miters[i],
|
||||
);
|
||||
}
|
||||
return {
|
||||
normals: out,
|
||||
attrIndex,
|
||||
attrPos,
|
||||
attrDistance,
|
||||
miters,
|
||||
attrPos: pickData, // [x,y,z, distance, miter ]
|
||||
};
|
||||
}
|
||||
// [x,y,z, distance, miter ]
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
import LineLayer from './components/Line';
|
||||
import PointDemo from './components/Point';
|
||||
import Point3D from './components/Point3D';
|
||||
import PointImage from './components/pointImage';
|
||||
import Polygon3D from './components/polygon3D';
|
||||
|
||||
// @ts-ignore
|
||||
storiesOf('图层', module)
|
||||
.add('点图层', () => <PointDemo />)
|
||||
.add('3D点', () => <Point3D />);
|
||||
.add('3D点', () => <Point3D />)
|
||||
.add('图片标注', () => <PointImage />)
|
||||
.add('面3d图层', () => <Polygon3D />)
|
||||
.add('线图层', () => <LineLayer />);
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import { LineLayer } from '@l7/layers';
|
||||
import { Scene } from '@l7/scene';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Point3D extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const response = await fetch(
|
||||
'https://gw.alipayobjects.com/os/rmsportal/ZVfOvhVCzwBkISNsuKCc.json',
|
||||
);
|
||||
const testdata = {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [
|
||||
[91.58203125, 34.95799531086792],
|
||||
[96.767578125, 34.379712580462204],
|
||||
[99.228515625, 33.7243396617476],
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const scene = new Scene({
|
||||
center: [102.602992, 23.107329],
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
type: 'mapbox',
|
||||
style: 'mapbox://styles/mapbox/dark-v9',
|
||||
zoom: 13,
|
||||
});
|
||||
const lineLayer = new LineLayer({})
|
||||
.source(await response.json())
|
||||
.size(1)
|
||||
.shape('line')
|
||||
.color(
|
||||
'ELEV',
|
||||
[
|
||||
'#E8FCFF',
|
||||
'#CFF6FF',
|
||||
'#A1E9ff',
|
||||
'#65CEF7',
|
||||
'#3CB1F0',
|
||||
'#2894E0',
|
||||
'#1772c2',
|
||||
'#105CB3',
|
||||
'#0D408C',
|
||||
'#002466',
|
||||
].reverse(),
|
||||
)
|
||||
.render();
|
||||
scene.addLayer(lineLayer);
|
||||
scene.render();
|
||||
this.scene = scene;
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import { PointImageLayer } from '@l7/layers';
|
||||
import { Scene } from '@l7/scene';
|
||||
import * as React from 'react';
|
||||
import data from '../data/data.json';
|
||||
export default class PointImage extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
const scene = new Scene({
|
||||
center: [120.19382669582967, 30.258134],
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
type: 'mapbox',
|
||||
style: 'mapbox://styles/mapbox/streets-v9',
|
||||
zoom: 1,
|
||||
});
|
||||
const pointLayer = new PointImageLayer({});
|
||||
const p1 = {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [83.671875, 44.84029065139799],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
scene.addImage(
|
||||
'00',
|
||||
'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*kzTMQqS2QdUAAAAAAAAAAABkARQnAQ',
|
||||
);
|
||||
pointLayer
|
||||
.source(data)
|
||||
.shape('00')
|
||||
.size(30);
|
||||
scene.addLayer(pointLayer);
|
||||
scene.render();
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
// @ts-ignore
|
||||
import { Polygon3DLayer } from '@l7/layers';
|
||||
// @ts-ignore
|
||||
import { Scene } from '@l7/scene';
|
||||
import * as dat from 'dat.gui';
|
||||
import * as React from 'react';
|
||||
|
||||
function convertRGB2Hex(rgb: number[]) {
|
||||
return (
|
||||
'#' + rgb.map((r) => ('0' + Math.floor(r).toString(16)).slice(-2)).join('')
|
||||
);
|
||||
}
|
||||
|
||||
export default class Polygon3D extends React.Component {
|
||||
private gui: dat.GUI;
|
||||
private $stats: Node;
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (this.gui) {
|
||||
this.gui.destroy();
|
||||
}
|
||||
if (this.$stats) {
|
||||
document.body.removeChild(this.$stats);
|
||||
}
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const response = await fetch(
|
||||
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
|
||||
);
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
type: 'mapbox',
|
||||
style: 'mapbox://styles/mapbox/streets-v9',
|
||||
center: [110.19382669582967, 50.258134],
|
||||
pitch: 0,
|
||||
zoom: 3,
|
||||
});
|
||||
this.scene = scene;
|
||||
const layer = new Polygon3DLayer({});
|
||||
|
||||
// TODO: new GeoJSONSource()
|
||||
layer
|
||||
.source(await response.json())
|
||||
.size('name', [0, 10000, 50000, 30000, 100000])
|
||||
.color('name', [
|
||||
'#2E8AE6',
|
||||
'#69D1AB',
|
||||
'#DAF291',
|
||||
'#FFD591',
|
||||
'#FF7A45',
|
||||
'#CF1D49',
|
||||
])
|
||||
.shape('fill')
|
||||
.style({
|
||||
opacity: 1.0,
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
scene.render();
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div
|
||||
id="map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue