mirror of https://gitee.com/antv-l7/antv-l7
feat(layers): add arclayer
This commit is contained in:
parent
861c0bba41
commit
fe894bc660
|
@ -137,6 +137,44 @@ export function RasterImageTriangulation(feature: IEncodeFeature) {
|
|||
};
|
||||
}
|
||||
|
||||
export function LineArcTriangulation(feature: IEncodeFeature, segNum = 30) {
|
||||
const coordinates = feature.coordinates as IPosition[];
|
||||
const positions = [];
|
||||
const indexArray = [];
|
||||
for (let i = 0; i < segNum; i++) {
|
||||
// 上线两个顶点
|
||||
// [ x, y, z, sx,sy, tx,ty]
|
||||
positions.push(
|
||||
i,
|
||||
1,
|
||||
i,
|
||||
coordinates[0][0],
|
||||
coordinates[0][1],
|
||||
coordinates[1][0],
|
||||
coordinates[1][1],
|
||||
i,
|
||||
-1,
|
||||
i,
|
||||
coordinates[0][0],
|
||||
coordinates[0][1],
|
||||
coordinates[1][0],
|
||||
coordinates[1][1],
|
||||
);
|
||||
if (i !== segNum - 1) {
|
||||
indexArray.push(
|
||||
...[0, 1, 2, 1, 3, 2].map((v) => {
|
||||
return i * 2 + v;
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
return {
|
||||
vertices: positions,
|
||||
indices: indexArray,
|
||||
size: 7,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 点图层3d geomerty
|
||||
* @param shape 3D形状
|
||||
|
|
|
@ -2,6 +2,7 @@ import { container, ILayerPlugin, TYPES } from '@l7/core';
|
|||
import BaseLayer from './core/BaseLayer';
|
||||
import HeatMapGridLayer from './heatmap/grid';
|
||||
import LineLayer from './line/index';
|
||||
import ArcLineLayer from './line/arc';
|
||||
import Point3dLayer from './point/extrude';
|
||||
import PointImageLayer from './point/image';
|
||||
import PointLayer from './point/index';
|
||||
|
@ -72,6 +73,7 @@ export {
|
|||
Polygon3DLayer,
|
||||
ImageLayer,
|
||||
HeatMapGridLayer,
|
||||
ArcLineLayer,
|
||||
// Line,
|
||||
// ImageLayer,
|
||||
// HeatMapLayer,
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import { LineArcTriangulation } from '../core/triangulation';
|
||||
import line_arc_frag from './shaders/line_arc_frag.glsl';
|
||||
import line_arc_vert from './shaders/line_arc_vert.glsl';
|
||||
interface IArcLayerStyleOptions {
|
||||
opacity: number;
|
||||
segmentNumber: number;
|
||||
}
|
||||
export default class ArcLineLayer extends BaseLayer<IArcLayerStyleOptions> {
|
||||
public name: string = 'LineLayer';
|
||||
|
||||
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 || 1,
|
||||
segmentNumber: 30,
|
||||
},
|
||||
}),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
protected buildModels() {
|
||||
this.registerBuiltinAttributes(this);
|
||||
this.models = [
|
||||
this.buildLayerModel({
|
||||
moduleName: 'arcline',
|
||||
vertexShader: line_arc_vert,
|
||||
fragmentShader: line_arc_frag,
|
||||
triangulation: LineArcTriangulation,
|
||||
blend: {
|
||||
enable: true,
|
||||
func: {
|
||||
srcRGB: gl.ONE,
|
||||
srcAlpha: 1,
|
||||
dstRGB: gl.ONE,
|
||||
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];
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
layer.styleAttributeService.registerStyleAttribute({
|
||||
name: 'instance', // 弧线起始点信息
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_Instance',
|
||||
buffer: {
|
||||
usage: gl.STATIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 4,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
return [vertex[3], vertex[4], vertex[5], vertex[6]];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
precision mediump float;
|
||||
uniform float u_Opacity;
|
||||
varying vec4 v_color;
|
||||
|
||||
void main() {
|
||||
|
||||
gl_FragColor = v_color;
|
||||
gl_FragColor.a = v_color.a * u_Opacity;
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
precision mediump float;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec4 a_Instance;
|
||||
attribute vec4 a_Color;
|
||||
attribute float a_Size;
|
||||
|
||||
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform float segmentNumber;
|
||||
varying vec4 v_color;
|
||||
#pragma include "projection"
|
||||
|
||||
float maps (float value, float start1, float stop1, float start2, float stop2) {
|
||||
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1));
|
||||
}
|
||||
|
||||
float getSegmentRatio(float index) {
|
||||
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.0));
|
||||
}
|
||||
|
||||
float paraboloid(vec2 source, vec2 target, float ratio) {
|
||||
vec2 x = mix(source, target, ratio);
|
||||
vec2 center = mix(source, target, 0.5);
|
||||
float dSourceCenter = distance(source, center);
|
||||
float dXCenter = distance(x, center);
|
||||
return (dSourceCenter + dXCenter) * (dSourceCenter - dXCenter);
|
||||
}
|
||||
|
||||
vec3 getPos(vec2 source, vec2 target, float segmentRatio) {
|
||||
float vertex_height = paraboloid(source, target, segmentRatio);
|
||||
|
||||
return vec3(
|
||||
mix(source, target, segmentRatio),
|
||||
sqrt(max(0.0, vertex_height))
|
||||
);
|
||||
}
|
||||
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
|
||||
// normalized direction of the line
|
||||
vec2 dir_screenspace = normalize(line_clipspace);
|
||||
// rotate by 90 degrees
|
||||
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
|
||||
|
||||
vec2 offset = dir_screenspace * offset_direction * a_Size / 2.0;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
vec2 source = project_position(vec4(a_Instance.rg, 0, 0)).xy;
|
||||
vec2 target = project_position(vec4(a_Instance.ba, 0, 0)).xy;
|
||||
float segmentIndex = a_Position.x;
|
||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
||||
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
||||
|
||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||
vec3 curr = getPos(source, target, segmentRatio);
|
||||
vec3 next = getPos(source, target, nextSegmentRatio);
|
||||
vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
|
||||
// vec4 project_pos = project_position(vec4(curr, 1.0));
|
||||
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + project_pixel(offset), curr.z, 1.0));
|
||||
|
||||
}
|
|
@ -11,7 +11,7 @@ varying vec4 v_Color;
|
|||
|
||||
void main() {
|
||||
v_Color =a_Color;
|
||||
vec4 project_pos = project_position(vec4(a_Position 1.0));
|
||||
vec4 project_pos = project_position(vec4(a_Position,1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
import ArcLineDemo from './components/Arcline';
|
||||
import GridHeatMap from './components/heatMapgrid';
|
||||
import LineLayer from './components/Line';
|
||||
import PointDemo from './components/Point';
|
||||
|
@ -15,5 +16,6 @@ storiesOf('图层', module)
|
|||
.add('图片标注', () => <PointImage />)
|
||||
.add('面3d图层', () => <Polygon3D />)
|
||||
.add('线图层', () => <LineLayer />)
|
||||
.add('弧线', () => <ArcLineDemo />)
|
||||
.add('网格热力图', () => <GridHeatMap />)
|
||||
.add('图片', () => <ImageLayerDemo />);
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import { ArcLineLayer } from '@l7/layers';
|
||||
import { Scene } from '@l7/scene';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class ArxLineDemo extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
this.scene.destroy();
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const response = await fetch(
|
||||
'https://gw.alipayobjects.com/os/rmsportal/UEXQMifxtkQlYfChpPwT.txt',
|
||||
);
|
||||
const scene = new Scene({
|
||||
center: [116.2825, 39.9],
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
type: 'mapbox',
|
||||
style: 'mapbox://styles/mapbox/dark-v9',
|
||||
zoom: 2,
|
||||
});
|
||||
const lineLayer = new ArcLineLayer({})
|
||||
.source(await response.text(), {
|
||||
parser: {
|
||||
type: 'csv',
|
||||
x: 'lng1',
|
||||
y: 'lat1',
|
||||
x1: 'lng2',
|
||||
y1: 'lat2',
|
||||
},
|
||||
})
|
||||
.size(0.5)
|
||||
.shape('arc')
|
||||
.color('rgb(13,64,140)');
|
||||
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,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ import { LineLayer } from '@l7/layers';
|
|||
import { Scene } from '@l7/scene';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class Point3D extends React.Component {
|
||||
export default class LineDemo extends React.Component {
|
||||
private scene: Scene;
|
||||
|
||||
public componentWillUnmount() {
|
||||
|
|
Loading…
Reference in New Issue