Shihuidev (#902)

* feat: 增加着色器的拾取计算控制、完善 arcmini

* feat: 完善 enableShaderPick/disableShaderPick 功能

* style: lint style

* feat: 补充调用高德地图公交线路查询 demo

* style: lint style

* feat: 优化弧线的纹理动画

* style: lint style

* feat: 去除greatCircle 的纹理动画优化

* feat: 扩展点图层圆柱效果

* feat: 增加几何体的径向渐变配置

* style: lint style

* fix: 修复bug 图层触发的事件跟图层设置的zIndex无关,只跟插入图层先后顺序有关

* style: lint style

* feat: 补全挤出几何体拾取颜色的光照配置

* style: lint style

* fix: 修复圆柱 cull 问题 mapbox amap 不同

* feat: 图层销毁时的内存泄漏

* style: lint style

* feat: 平面弧线新增弧线偏移量的数据映射能力

* style: lint style

* fix: 修复重复销毁bug

* style: lint style

* feat: 修复 texture 重复销毁问题

* style: lint style

* fix: 修复图层叠加模式下的拾取失效问题

* style: lint style

* fix: 修复纹理贴图在 zoom 大于 12 时存在的问题

* fix: 修复水波点颜色偏暗

* feat: 优化点图层的渲染效果,叠加渲染效果

* style: lint style

* fix: 修复 layer contextmenu 事件丢失

* fix: 修复 map 类型 resize 失效

* style: lint style

* feat: 增加瓦片地图的请求节流

* style: lint style

* feat: 优化热力图在 radius 数值比较大时热力点边缘发生裁剪的现象

* style: lint style

* fix: 修复resize 后 picking shiqu 拾取失败的问题

* feat: 优化 marker/popup 在容器边缘的表现

* feat: 增加 setEnableRender 方法

* style: lint style

* feat: 增加城市图层扫光特效

* style: lint style

* feat: 补全拾取色混合配置

* style: lint style

* feat: 增加高德地图的面积大小点

* style: lint style

* feat: 点优化边缘锯齿

* fix: 修复pointLayer stroke 变暗问题

* fix: 修复混合导致的拾取错误

* feat: add simple point 1.0

* style: lint style

* feat: simple point support stroke

* style: lint style

* feat: 优化 simple point 边缘的锯齿

* style: lint style

* feat: add point cylinder raising animate

* style: lint style

* feat: 优化点图层 icon 在小尺寸下的锯齿问题

* style: lint style

* feat: 修复 layer destroy 报错、未清理、未重绘、补充触发 destroy 事件

* fix: 修复 marker 在 cluster getMakers 失效

* style: lint style

* feat: 清除 marker layer cluster fix

* style: lint style

* fix: 修复 markerLayer hide show 方法缺少 cluster 模式下的控制

* style: lint style

* feat: 取消在 shape 方法执行后的暴力更新

* style: lint style

* feat: 增加图层保底颜色设置

* style: lint style

* feat: 将兜底颜色改为 bottomColor

* fix: color bottom

* style: lint style

* feat: 修改颜色兜底判断逻辑

* style: lint style

* feat: add tnpm dist-tag

* feat: 增加line border 边框

* style: lint style

* feat: 增加 layer 重复销毁过滤

* style: lint style

* feat: 新增 wall 图层

* style: lint style
This commit is contained in:
YiQianYao 2021-12-28 19:36:20 +08:00 committed by GitHub
parent 17dba67a4d
commit 438fd0e9f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 628 additions and 0 deletions

View File

@ -13,6 +13,7 @@ export interface ILineLayerStyleOptions {
forward?: boolean; // 可选参数、是否反向(arcLine)
lineTexture?: boolean; // 可选参数、是否开启纹理贴图功能(all)
iconStep?: number; // 可选参数、纹理贴图步长(all)
iconStepCount?: number; // 可选参数、纹理贴图间隔
textureBlend?: string; // 可选参数、供给纹理贴图使用(all)
sourceColor?: string; // 可选参数、设置渐变色的起始颜色(all)
targetColor?: string; // 可选参数、设置渐变色的终点颜色(all)
@ -23,4 +24,6 @@ export interface ILineLayerStyleOptions {
borderWidth?: number; // 可选参数 线边框宽度
borderColor?: string; // 可选参数 线边框颜色
heightfixed?: boolean; // 可选参数 高度是否固定
}

View File

@ -29,6 +29,7 @@ export default class LineLayer extends BaseLayer<ILineLayerStyleOptions> {
const type = this.getModelType();
const defaultConfig = {
line: {},
wall: {},
arc3d: { blend: 'additive' },
arc: { blend: 'additive' },
arcmini: { blend: 'additive' },

View File

@ -3,12 +3,14 @@ import Arc3DModel from './arc_3d';
import ArcMiniModel from './arcmini';
import GreatCircleModel from './great_circle';
import LineModel from './line';
import LineWallModel from './wall';
export type LineModelType =
| 'arc'
| 'arcmini'
| 'arc3d'
| 'greatcircle'
| 'wall'
| 'line';
const LineModels: { [key in LineModelType]: any } = {
@ -16,6 +18,7 @@ const LineModels: { [key in LineModelType]: any } = {
arcmini: ArcMiniModel,
arc3d: Arc3DModel,
greatcircle: GreatCircleModel,
wall: LineWallModel,
line: LineModel,
};

View File

@ -0,0 +1,303 @@
import {
AttributeType,
gl,
IAnimateOption,
IEncodeFeature,
IImage,
ILayerConfig,
IModel,
IModelUniform,
ITexture2D,
} from '@antv/l7-core';
import { rgb2arr } from '@antv/l7-utils';
import { isNumber } from 'lodash';
import BaseModel from '../../core/BaseModel';
import { ILineLayerStyleOptions, lineStyleType } from '../../core/interface';
import { LineTriangulation } from '../../core/triangulation';
import line_frag from '../shaders/wall_frag.glsl';
import line_vert from '../shaders/wall_vert.glsl';
export default class LineWallModel extends BaseModel {
protected texture: ITexture2D;
public getUninforms(): IModelUniform {
const {
opacity,
sourceColor,
targetColor,
textureBlend = 'normal',
heightfixed = false,
lineTexture = false,
iconStep = 100,
iconStepCount = 1,
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
if (this.rendererService.getDirty()) {
this.texture.bind();
}
// 转化渐变色
let useLinearColor = 0; // 默认不生效
let sourceColorArr = [0, 0, 0, 0];
let targetColorArr = [0, 0, 0, 0];
if (sourceColor && targetColor) {
sourceColorArr = rgb2arr(sourceColor);
targetColorArr = rgb2arr(targetColor);
useLinearColor = 1;
}
if (this.dataTextureTest && this.dataTextureNeedUpdate({ opacity })) {
this.judgeStyleAttributes({ opacity });
const encodeData = this.layer.getEncodedData();
const { data, width, height } = this.calDataFrame(
this.cellLength,
encodeData,
this.cellProperties,
);
this.rowCount = height; // 当前数据纹理有多少行
this.dataTexture =
this.cellLength > 0 && data.length > 0
? this.createTexture2D({
flipY: true,
data,
format: gl.LUMINANCE,
type: gl.FLOAT,
width,
height,
})
: this.createTexture2D({
flipY: true,
data: [1],
format: gl.LUMINANCE,
type: gl.FLOAT,
width: 1,
height: 1,
});
}
return {
u_heightfixed: Number(heightfixed),
u_dataTexture: this.dataTexture, // 数据纹理 - 有数据映射的时候纹理中带数据,若没有任何数据映射时纹理是 [1]
u_cellTypeLayout: this.getCellTypeLayout(),
// u_opacity: opacity === undefined ? 1 : opacity,
u_opacity: isNumber(opacity) ? opacity : 1.0,
u_textureBlend: textureBlend === 'normal' ? 0.0 : 1.0,
// 纹理支持参数
u_texture: this.texture, // 贴图
u_line_texture: lineTexture ? 1.0 : 0.0, // 传入线的标识
u_iconStepCount: iconStepCount,
u_icon_step: iconStep,
u_textSize: [1024, this.iconService.canvasHeight || 128],
// 渐变色支持参数
u_linearColor: useLinearColor,
u_sourceColor: sourceColorArr,
u_targetColor: targetColorArr,
};
}
public getAnimateUniforms(): IModelUniform {
const { animateOption } = this.layer.getLayerConfig() as ILayerConfig;
return {
u_aimate: this.animateOption2Array(animateOption as IAnimateOption),
u_time: this.layer.getLayerAnimateTime(),
};
}
public initModels(): IModel[] {
this.updateTexture();
this.iconService.on('imageUpdate', this.updateTexture);
return this.buildModels();
}
public clearModels() {
this.texture?.destroy();
this.dataTexture?.destroy();
this.iconService.off('imageUpdate', this.updateTexture);
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({
moduleName: 'linewall',
vertexShader: line_vert,
fragmentShader: line_frag,
triangulation: LineTriangulation,
primitive: gl.TRIANGLES,
blend: this.getBlend(),
depth: { enable: false },
}),
];
}
protected registerBuiltinAttributes() {
// const lineType = this
// point layer size;
const {
lineType = 'solid',
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
// if (lineType === 'dash') {
this.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.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return [vertex[3]];
},
},
});
this.styleAttributeService.registerStyleAttribute({
name: 'total_distance',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Total_Distance',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return [vertex[5]];
},
},
});
// }
this.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: 2,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { size = 1 } = feature;
return Array.isArray(size) ? [size[0], size[1]] : [size as number, 0];
},
},
});
// point layer size;
this.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,
// @ts-ignore
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
normal: number[],
) => {
return normal;
},
},
});
this.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.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return [vertex[4]];
},
},
});
this.styleAttributeService.registerStyleAttribute({
name: 'uv',
type: AttributeType.Attribute,
descriptor: {
name: 'a_iconMapUV',
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 { texture } = feature;
const { x, y } = iconMap[texture as string] || { x: 0, y: 0 };
return [x, y];
},
},
});
}
private updateTexture = () => {
const { createTexture2D } = this.rendererService;
if (this.texture) {
this.texture.update({
data: this.iconService.getCanvas(),
});
this.layer.render();
return;
}
this.texture = createTexture2D({
data: this.iconService.getCanvas(),
mag: gl.NEAREST,
min: gl.NEAREST,
premultiplyAlpha: false,
width: 1024,
height: this.iconService.canvasHeight || 128,
});
};
}

View File

@ -0,0 +1,102 @@
#define LineTypeSolid 0.0
#define Animate 0.0
#define LineTexture 1.0
uniform float u_opacity : 1.0;
uniform float u_textureBlend;
uniform float u_iconStepCount;
varying vec4 v_color;
// line texture
uniform float u_line_texture;
uniform sampler2D u_texture;
uniform vec2 u_textSize;
// dash
uniform float u_dash_offset : 0.0;
uniform float u_dash_ratio : 0.1;
varying vec2 v_iconMapUV;
varying float v_blur;
uniform float u_linearColor: 0;
uniform vec4 u_sourceColor;
uniform vec4 u_targetColor;
#pragma include "picking"
uniform float u_time;
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ]; // 控制运动
varying mat4 styleMappingMat;
// [animate, duration, interval, trailLength],
void main() {
float opacity = styleMappingMat[0][0];
float animateSpeed = 0.0; // 运动速度
float d_distance_ratio = styleMappingMat[3].r; // 当前点位距离占线总长的比例
float v = styleMappingMat[3].a;
if(u_linearColor == 1.0) { // 使用渐变颜色
gl_FragColor = mix(u_sourceColor, u_targetColor, v);
} else { // 使用 color 方法传入的颜色
gl_FragColor = v_color;
}
gl_FragColor.a *= opacity; // 全局透明度
if(u_aimate.x == Animate) {
animateSpeed = u_time / u_aimate.y;
float alpha =1.0 - fract( mod(1.0- d_distance_ratio, u_aimate.z)* (1.0/ u_aimate.z) + animateSpeed);
alpha = (alpha + u_aimate.w -1.0) / u_aimate.w;
alpha = smoothstep(0., 1., alpha);
gl_FragColor.a *= alpha;
}
if(u_line_texture == LineTexture) { // while load texture
float aDistance = styleMappingMat[3].g; // 当前顶点的距离
float d_texPixelLen = styleMappingMat[3].b; // 贴图的像素长度,根据地图层级缩放
float u = fract(mod(aDistance, d_texPixelLen)/d_texPixelLen - animateSpeed);
float v = styleMappingMat[3].a; // 线图层贴图部分的 v 坐标值
// 计算纹理间隔 start
float flag = 0.0;
if(u > 1.0/u_iconStepCount) {
flag = 1.0;
}
u = fract(u*u_iconStepCount);
// 计算纹理间隔 end
vec2 uv= v_iconMapUV / u_textSize + vec2(u, v) / u_textSize * 64.;
vec4 pattern = texture2D(u_texture, uv);
// Tip: 判断纹理间隔
if(flag > 0.0) {
pattern = vec4(0.0);
}
if(u_textureBlend == 0.0) { // normal
pattern.a = 0.0;
gl_FragColor = filterColor(gl_FragColor + pattern);
} else { // replace
pattern.a *= opacity;
if(gl_FragColor.a <= 0.0) {
pattern.a = 0.0;
}
gl_FragColor = filterColor(pattern);
}
}
// blur - AA
if(v < v_blur) {
gl_FragColor.a = mix(0.0, gl_FragColor.a, v/v_blur);
} else if(v > 1.0 - v_blur) {
gl_FragColor.a = mix(gl_FragColor.a, 0.0, (v - (1.0 - v_blur))/v_blur);
}
gl_FragColor = filterColor(gl_FragColor);
}

View File

@ -0,0 +1,116 @@
#define LineTypeSolid 0.0
#define LineTypeDash 1.0
#define Animate 0.0
attribute float a_Miter;
attribute vec4 a_Color;
attribute vec2 a_Size;
attribute vec3 a_Normal;
attribute vec3 a_Position;
attribute vec2 a_iconMapUV;
// dash line
attribute float a_Total_Distance;
attribute float a_Distance;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
uniform float u_icon_step: 100;
uniform float u_heightfixed;
#pragma include "projection"
#pragma include "light"
#pragma include "picking"
varying vec4 v_color;
varying float v_blur;
// texV 线图层 - 贴图部分的 v 坐标(线的宽度方向)
varying vec2 v_iconMapUV;
uniform float u_linearColor: 0;
uniform float u_opacity: 1.0;
varying mat4 styleMappingMat; // 用于将在顶点着色器中计算好的样式值传递给片元
#pragma include "styleMapping"
#pragma include "light"
#pragma include "styleMappingCalOpacity"
void main() {
// cal style mapping - 数据纹理映射部分的计算
styleMappingMat = mat4(
0.0, 0.0, 0.0, 0.0, // opacity - strokeOpacity - strokeWidth - empty
0.0, 0.0, 0.0, 0.0, // strokeR - strokeG - strokeB - strokeA
0.0, 0.0, 0.0, 0.0, // offsets[0] - offsets[1]
0.0, 0.0, 0.0, 0.0 // distance_ratio/distance/pixelLen/texV
);
float rowCount = u_cellTypeLayout[0][0]; // 当前的数据纹理有几行
float columnCount = u_cellTypeLayout[0][1]; // 当看到数据纹理有几列
float columnWidth = 1.0/columnCount; // 列宽
float rowHeight = 1.0/rowCount; // 行高
float cellCount = calCellCount(); // opacity - strokeOpacity - strokeWidth - stroke - offsets
float id = a_vertexId; // 第n个顶点
float cellCurrentRow = floor(id * cellCount / columnCount) + 1.0; // 起始点在第几行
float cellCurrentColumn = mod(id * cellCount, columnCount) + 1.0; // 起始点在第几列
// cell 固定顺序 opacity -> strokeOpacity -> strokeWidth -> stroke ...
// 按顺序从 cell 中取值、若没有则自动往下取值
float textureOffset = 0.0; // 在 cell 中取值的偏移量
vec2 opacityAndOffset = calOpacityAndOffset(cellCurrentRow, cellCurrentColumn, columnCount, textureOffset, columnWidth, rowHeight);
styleMappingMat[0][0] = opacityAndOffset.r;
textureOffset = opacityAndOffset.g;
// cal style mapping - 数据纹理映射部分的计算
float d_distance_ratio; // 当前点位距离占线总长的比例
float d_texPixelLen; // 贴图的像素长度,根据地图层级缩放
v_iconMapUV = a_iconMapUV;
if(u_heightfixed < 1.0) { // 高度随 zoom 调整
d_texPixelLen = project_pixel(u_icon_step);
} else {
d_texPixelLen = u_icon_step;
}
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) {
d_texPixelLen *= 10.0;
}
if(u_aimate.x == Animate || u_linearColor == 1.0) {
d_distance_ratio = a_Distance / a_Total_Distance;
}
float miter = (a_Miter + 1.0)/2.0;
// 设置数据集的参数
styleMappingMat[3][0] = d_distance_ratio; // 当前点位距离占线总长的比例
styleMappingMat[3][1] = a_Distance; // 当前顶点的距离
styleMappingMat[3][2] = d_texPixelLen; // 贴图的像素长度,根据地图层级缩放
styleMappingMat[3][3] = miter; // 线图层贴图部分的 v 坐标值 0 - 1
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
float originSize = a_Size.x; // 固定高度
if(u_heightfixed < 1.0) { // 高度随 zoom 调整
originSize = project_pixel(a_Size.x);
}
float wallHeight = originSize * miter;
float lightWeight = calc_lighting(vec4(project_pos.xy, wallHeight, 1.0));
v_blur = min(project_pixel(2.0) / originSize, 0.05);
// v_lightWeight = lightWeight;
v_color = vec4(a_Color.rgb * lightWeight, a_Color.w);
// v_color = a_Color;
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
gl_Position = u_Mvp * (vec4(project_pos.xy, wallHeight, 1.0));
} else {
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy, wallHeight, 1.0));
}
setPickingColor(a_PickingColor);
}

View File

@ -0,0 +1,98 @@
import { LineLayer, Scene } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
import * as React from 'react';
export default class Amap2demo_lineLinear extends React.Component {
// @ts-ignore
private scene: Scene;
public componentWillUnmount() {
this.scene.destroy();
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [115, 30.258134],
pitch: 40,
zoom: 6,
viewMode: '3D',
}),
});
this.scene = scene;
const geoData = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {
testOpacity: 0.8,
},
geometry: {
type: 'Polygon',
coordinates: [
[
[113.8623046875, 30.031055426540206],
[116.3232421875, 30.031055426540206],
[117, 30],
[117, 31],
[116, 30.5],
],
],
},
},
],
};
scene.addImage(
'02',
'https://gw.alipayobjects.com/zos/bmw-prod/ce83fc30-701f-415b-9750-4b146f4b3dd6.svg',
);
scene.on('loaded', () => {
const layer = new LineLayer({})
.source(geoData)
// .size(20000)
.size(20)
.shape('wall')
.texture('02')
.color('#25d8b7')
.animate({
interval: 1, // 间隔
duration: 1, // 持续时间,延时
trailLength: 2, // 流线长度
})
.style({
opacity: 'testOpacity',
lineTexture: true, // 开启线的贴图功能
// iconStep: 40000, // 设置贴图纹理的间距
iconStep: 40, // 设置贴图纹理的间距
iconStepCount: 4,
// heightfixed: true,
// textureBlend: 'replace',
// textureBlend: 'normal',
sourceColor: '#f00',
targetColor: 'rgba(0, 255, 0, 0.2)',
})
.active(true);
scene.addLayer(layer);
});
}
public render() {
return (
<>
<div
id="map"
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
}}
/>
</>
);
}
}

View File

@ -70,6 +70,7 @@ import PlaneLine from './components/planeLine'
import Slider from './components/slider'
import WindMap from './components/amap2demo_wind'
import SimplePoint from './components/simplePoint';
import LineWall from './components/linewall'
// @ts-ignore
storiesOf('地图方法', module)
@ -144,3 +145,4 @@ storiesOf('地图方法', module)
.add('PlaneLine', () => <PlaneLine/>)
.add('Slider', () => <Slider/>)
.add('SimplePoint', () => <SimplePoint/>)
.add('LineWall', () => <LineWall/>)