feat(layers): add arclayer

This commit is contained in:
thinkinggis 2019-10-30 14:53:18 +08:00
parent 861c0bba41
commit fe894bc660
9 changed files with 283 additions and 2 deletions

View File

@ -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形状

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() {