From cf326c047cb80d768043e87c1f7ec73b817821d4 Mon Sep 17 00:00:00 2001
From: YiQianYao <42212176+2912401452@users.noreply.github.com>
Date: Tue, 8 Mar 2022 18:13:22 +0800
Subject: [PATCH] Shihui (#996)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: add keywords
* feat: 升级部分官网 demo,增加 bloom 效果
* feat: 增加 pointLayer fillImage 模式的 demo
* style: lint style
* docs: 补充后处理相关文档
* style: lint style
* docs: 完善图层基础方法
---
docs/api/pass.en.md | 6 +
docs/api/pass.zh.md | 348 ++++++++++++++++++
docs/api/point_layer/symbol.zh.md | 47 +++
docs/common/layer/layer_interaction.md | 52 +++
.../gallery/animate/demo/plane_animate.js | 16 +-
examples/line/animate/demo/trip_animate.js | 2 +-
.../line/animate/demo/trip_animate_dark.js | 13 +-
examples/line/isoline/demo/ele_dark.js | 14 +-
examples/point/image/demo/fillimage.js | 58 +++
examples/point/image/demo/meta.json | 5 +
gatsby-config.js | 9 +
11 files changed, 566 insertions(+), 4 deletions(-)
create mode 100644 docs/api/pass.en.md
create mode 100644 docs/api/pass.zh.md
create mode 100644 examples/point/image/demo/fillimage.js
diff --git a/docs/api/pass.en.md b/docs/api/pass.en.md
new file mode 100644
index 0000000000..fde558c24b
--- /dev/null
+++ b/docs/api/pass.en.md
@@ -0,0 +1,6 @@
+---
+title: MultiPass
+order: 10
+---
+
+`markdown:docs/api/pass.zh.md`
diff --git a/docs/api/pass.zh.md b/docs/api/pass.zh.md
new file mode 100644
index 0000000000..872184e208
--- /dev/null
+++ b/docs/api/pass.zh.md
@@ -0,0 +1,348 @@
+---
+title: 后处理模块
+order: 10
+---
+
+后处理(Post-Process Effect)是 3D 渲染常见的处理效果,是一种对渲染之后的画面进行再加工的技术,一般用于实现各种特效。L7 的后处理模块为用户提供了一些常见的后处理效果,同时也提供了标准规范,允许用户自定义后处理效果。
+
+🌟 需要注意的是,使用后处理通常会产生额外的性能消耗,用户应该根据项目的实际情况合理使用后处理。
+
+## 使用
+
+```jsx
+const layer = new LineLayer({
+ enableMultiPassRenderer: true,
+ passes: [
+ [
+ 'bloom',
+ {
+ bloomBaseRadio: 0.8,
+ bloomRadius: 2,
+ bloomIntensity: 1
+ }
+ ]
+ ]
+}).source(data)
+ .size('ELEV', h => [ h % 50 === 0 ? 1.0 : 0.5, (h - 1300) * 0.2 ])
+ .shape('line')
+ .scale('ELEV', {
+ type: 'quantize'
+ })
+ .color('ELEV', [
+ '#094D4A',
+ ...
+ ]);
+scene.addLayer(layer);
+```
+
+
+
+[在线案例](../../examples/line/isoline#ele_dark)
+
+### 开启后处理
+
+为了开启图层的后处理能力,我们需要在初始化图层的时候配置 enableMultiPassRenderer 为 true,同时传入该图层作用的处理效果配置。
+
+```javascript
+let pointLayer = new PointLayer({
+ zIndex: 1,
+ enableMultiPassRenderer: false,
+ passes: [
+ [
+ 'bloom',
+ {
+ bloomBaseRadio: 0.95,
+ bloomRadius: 4,
+ bloomIntensity: 1.1,
+ },
+ ],
+ ],
+});
+```
+
+- enableMultiPassRenderer 配置该图层是否开始后处理能力
+- passes 后处理配置列表
+ 🌟 passes 需要根据一定的规则配置
+
+### 单图层后处理
+
+传统的后处理渲染往往会对场景中所有的对象做统一的后处理,而许多时候我们只需要对场景中的一部分内容做后处理。L7 的后处理模块天然支持以图层为单位进行后处理,这使的用户对 L7 场景内容的处理有更高的自由度。
+
+### update pass options
+
+用户在初始化完图层对象之后,若想调整后处理效果的参数,可以直接使用 style 方法
+
+```javascript
+layer.style({
+ passes: [
+ [
+ 'colorHalftone',
+ {
+ // 更新 cenrter 的位置
+ center: [newX, newY],
+ },
+ ],
+ ],
+});
+scene.render();
+```
+
+### setMultiPass(enableMultiPassRenderer: boolean, passes?: pass[])
+
+为了方便用户切换后处理的状态(开启、关闭后处理),我们为用户提供了专门的方法
+
+```javascript
+// 当前图层存在 multiPass,我们需要关闭时
+// 直接关闭
+layer.setMultiPass(false);
+// 关闭的同时清除 passes
+layer.setMultiPass(false, []);
+
+// 当前图层不存在 multiPass,我们需要开启时
+// 图层初始化时已经传入 passes
+const layer = new PolygonLayer({
+ zIndex: 0,
+ enableMultiPassRenderer: false,
+ passes: [
+ [
+ 'bloom',
+ {
+ bloomBaseRadio: 0.5,
+ bloomRadius: 20,
+ bloomIntensity: 1,
+ },
+ ],
+ ],
+});
+layer.setMultiPass(true);
+
+// 图层初始化时没有传入 passes
+layer.setMultiPass(true, [
+ [
+ 'bloom',
+ {
+ bloomRadius: 10,
+ bloomIntensity: 1,
+ },
+ ],
+]);
+```
+
+### 后处理链路
+
+passes 可以传入多种后处理,普通渲染的结果是第一个后处理的输入,前一种后处理的输出是后一个后处理的输入,最后的结果输出到屏幕。
+
+### 预制的后处理
+
+L7 的后处理模块预置了几种后处理效果,因此用户可以直接在 passes 中配置使用。
+
+#### bloom
+
+
+
+```javascript
+const bloomPass = [
+ 'bloom',
+ {
+ bloomBaseRadio: 0.5,
+ bloomRadius: 20,
+ bloomIntensity: 1,
+ },
+];
+```
+
+辉光后处理
+
+- bloomBaseRadio
+ 设置保持图形原本样式的比例,值在 0 - 1 之间,值为 1 时完全保存本身的样式
+- bloomRadius
+ 设置 bloom 的半径,值越大,bloom 范围越大
+- bloomIntensity
+ 设置 bloom 的强度,值越大,辉光越强
+
+#### blurV/blurH
+
+
+
+垂直方向模糊/水平方向模糊
+
+```javascript
+const blurVPass = [
+ 'blurV',
+ {
+ blurRadius: 5,
+ },
+];
+const blurHPass = [
+ 'blurH',
+ {
+ blurRadius: 5,
+ },
+];
+```
+
+- blurRadius
+ 设置模糊半径
+
+#### colorHalftone
+
+
+
+colorHalftone
+
+```javascript
+const colorHalftonePass = [
+ 'colorHalftone',
+ {
+ angle: 0,
+ size: 8,
+ centerX: 0.5,
+ centerY: 0.5,
+ },
+];
+```
+
+- angle
+ 设置角度
+- size
+ 设置大小
+- centerX
+ 设置中心点 X
+- centerY
+ 设置中心点 Y
+
+#### hexagonalPixelate
+
+
+
+六边形像素
+
+```javascript
+const hexagonalPixelatePass = [
+ 'hexagonalPixelate',
+ {
+ scale: 10,
+ centerX: 0.5,
+ centerY: 0.5,
+ },
+];
+```
+
+- scale
+ 设置缩放
+- centerX
+ 设置中心点 X
+- centerY
+ 设置中心点 Y
+
+#### ink
+
+
+
+ink
+
+```javascript
+const inkPass = [
+ 'ink',
+ {
+ strength: 1,
+ },
+];
+```
+
+- strength
+ 设置强度
+
+#### noise
+
+
+
+噪声
+
+```javascript
+const noisePass = [
+ 'noise',
+ {
+ amount: 1,
+ },
+];
+```
+
+- amount
+ 设置噪点数量
+
+### 自定义后处理
+
+用户通过 L7 定义的标准可以轻松的自定义后处理效果。
+
+```javascript
+import { BasePostProcessingPass, PolygonLayer, Scene } from '@antv/l7';
+
+interface IDotScreenEffectConfig {
+ center: [number, number]; // pattern 圆心
+ angle: number; // dot 旋转角度
+ size: number; // dot 尺寸
+}
+
+class DotScreenEffect extends BasePostProcessingPass {
+ protected setupShaders() {
+ this.shaderModuleService.registerModule('dotScreenEffect', {
+ vs: this.quad,
+ fs: `
+ varying vec2 v_UV;
+
+ uniform sampler2D u_Texture;
+ uniform vec2 u_ViewportSize : [1.0, 1.0];
+ uniform vec2 u_Center : [0.5, 0.5];
+ uniform float u_Angle : 1;
+ uniform float u_Size : 3;
+
+ float pattern(vec2 texSize, vec2 texCoord) {
+ float scale = 3.1415 / u_Size;
+ float s = sin(u_Angle), c = cos(u_Angle);
+ vec2 tex = texCoord * texSize - u_Center * texSize;
+ vec2 point = vec2(
+ c * tex.x - s * tex.y,
+ s * tex.x + c * tex.y
+ ) * scale;
+ return (sin(point.x) * sin(point.y)) * 4.0;
+ }
+ vec4 dotScreen_filterColor(vec4 color, vec2 texSize, vec2 texCoord) {
+ float average = (color.r + color.g + color.b) / 3.0;
+ return vec4(vec3(average * 10.0 - 5.0 + pattern(texSize, texCoord)), color.a);
+ }
+
+ void main() {
+ gl_FragColor = vec4(texture2D(u_Texture, v_UV));
+ gl_FragColor = dotScreen_filterColor(gl_FragColor, u_ViewportSize, v_UV);
+ }
+ `,
+ });
+ const { vs, fs, uniforms } = this.shaderModuleService.getModule('dotScreenEffect');
+ const { width, height } = this.rendererService.getViewportSize();
+ return {
+ vs,
+ fs,
+ uniforms: {
+ ...uniforms,
+ u_ViewportSize: [width, height],
+ },
+ };
+ }
+}
+
+// 注册自定义后处理效果
+scene.registerPostProcessingPass(DotScreenEffect, 'dotScreenEffect');
+const layer = new PolygonLayer({
+ enableMultiPassRenderer: true,
+ passes: [
+ [
+ 'dotScreenEffect',
+ {
+ size: 8,
+ angle: 1,
+ },
+ ],
+ ],
+});
+```
diff --git a/docs/api/point_layer/symbol.zh.md b/docs/api/point_layer/symbol.zh.md
index 0d9a5f1c9f..43309b7660 100644
--- a/docs/api/point_layer/symbol.zh.md
+++ b/docs/api/point_layer/symbol.zh.md
@@ -54,4 +54,51 @@ const scatter = new PointLayer()
[在线案例](../../../examples/point/image#image)
+### layerType = "fillImage"
+
+🌟 默认通过 PointLayer 实例化的 image 本质上是精灵贴图,因此有始终面向相机的特性,同时贴图的大小也收到设备的限制。
+🌟 由于精灵始终面向相机,因此我们也无法自定义配置 image 的旋转角度
+
+为了解决上述的两个问题(1. 大小受限,2. 无法自定义旋转角度),我们单独提供了 fillimage 的模式。
+只需要在初始化图层的时候提前指定 layerType 为 fillImage,其他使用与普通的 image 完全相同。
+
+```javascript
+const imageLayer = new PointLayer({ layerType: 'fillImage' })
+ .source(data, {
+ parser: {
+ type: 'json',
+ x: 'longitude',
+ y: 'latitude',
+ },
+ })
+ .shape('name', ['00', '01', '02'])
+ .style({
+ rotation: 0,
+ })
+ .active({
+ color: '#0ff',
+ mix: 0.5,
+ })
+ .size(45);
+scene.addLayer(imageLayer);
+
+let r = 0;
+rotate();
+function rotate() {
+ r += 0.2;
+ imageLayer.style({
+ rotation: r,
+ });
+ scene.render();
+ requestAnimationFrame(rotate);
+}
+```
+
+- rotation: number|undefined
+ 我们支持使用 rotation 自定义配置图标的旋转角度(顺时针方向、角度制)
+
+
+
+[在线案例](../../../examples/point/image#fillimage)
+
`markdown:docs/common/layer/base.md`
diff --git a/docs/common/layer/layer_interaction.md b/docs/common/layer/layer_interaction.md
index 39fa4c603a..aa7a81b1f1 100644
--- a/docs/common/layer/layer_interaction.md
+++ b/docs/common/layer/layer_interaction.md
@@ -78,6 +78,58 @@ layer.select(false);
layer.setSelect(featureId);
```
+### setAutoFit(autoFit: boolean)
+让用户可以主动设置图层的 autoFit 参数
+🌟 设置完该方法后会在图层发生更新的时候生效,如在 setData 之后触发
+
+```javascript
+// 使用方法
+layer.setAutoFit(true);
+// 内部实现
+public setAutoFit(autoFit: boolean): ILayer {
+ this.updateLayerConfig({
+ autoFit,
+ });
+ return this;
+ }
+```
+
+### getScale(attr: string)
+支持单独获取某个图形经过 scale 计算后的值, 满足用户获取图层某些 feature 值的需求。
+- attr scale 的属性值
+
+```javascript
+const data = [
+ {lng: 120, lat: 30, name: 'n1'},
+ {lng: 120, lat: 30, name: 'n2'}
+]
+const layer = new PointLayer()
+ .source(data, {
+ parser: {
+ x: 'lng',
+ y: 'lat',
+ type: 'json'
+ }
+ })
+ .shape('circle')
+ .color('name', ['#f00', '#ff0'])
+ .size('name', [20, 40])
+
+scene.addLayer(layer)
+
+
+// 此时在 scene 上绘制两个点
+// 一个颜色为黄色,大小为 40 的点,对应 name 为 n1
+// 一个颜色为红色,大小为 20 的点,对应 name 为 n2
+
+const colorScale = layer.getScale('color'); // 获取 color 方法产生的 scale
+const color1 = colorScale('n1'); // '#ff0'
+const color1 = colorScale('n2'); // '#f00'
+
+const sizeScale = layer.getScale('size'); // 获取 size 方法产生的 scale
+const size1 = sizeScale('n1'); // 40
+const size2 = sizeScale('n2'); // 20
+```
### getLegendItems(type: string)
获取图例配置
diff --git a/examples/gallery/animate/demo/plane_animate.js b/examples/gallery/animate/demo/plane_animate.js
index 8005dd78f2..2cfaeccdd0 100644
--- a/examples/gallery/animate/demo/plane_animate.js
+++ b/examples/gallery/animate/demo/plane_animate.js
@@ -91,7 +91,21 @@ scene.on('loaded', () => {
.style({
opacity: 1.0
});
- const flyLine = new LineLayer({ blend: 'additive', zIndex: 2 })
+ const flyLine = new LineLayer({
+ blend: 'additive',
+ zIndex: 2,
+ enableMultiPassRenderer: true,
+ passes: [
+ [
+ 'bloom',
+ {
+ bloomBaseRadio: 0.8,
+ bloomRadius: 2,
+ bloomIntensity: 1
+ }
+ ]
+ ]
+ })
.source(flydata, {
parser: {
type: 'json',
diff --git a/examples/line/animate/demo/trip_animate.js b/examples/line/animate/demo/trip_animate.js
index aac6323c34..f7c053a6b0 100644
--- a/examples/line/animate/demo/trip_animate.js
+++ b/examples/line/animate/demo/trip_animate.js
@@ -40,7 +40,7 @@ scene.on('loaded', () => {
duration: 5
})
.style({
- opacity: 1
+ opacity: 0.5
});
scene.addLayer(layer);
});
diff --git a/examples/line/animate/demo/trip_animate_dark.js b/examples/line/animate/demo/trip_animate_dark.js
index 10590046ba..f1d329d594 100644
--- a/examples/line/animate/demo/trip_animate_dark.js
+++ b/examples/line/animate/demo/trip_animate_dark.js
@@ -16,7 +16,18 @@ scene.on('loaded', () => {
.then(res => res.text())
.then(data => {
const layer = new LineLayer({
- blend: 'normal'
+ blend: 'normal',
+ enableMultiPassRenderer: true,
+ passes: [
+ [
+ 'bloom',
+ {
+ bloomBaseRadio: 0.8,
+ bloomRadius: 2,
+ bloomIntensity: 1
+ }
+ ]
+ ]
})
.source(data, {
parser: {
diff --git a/examples/line/isoline/demo/ele_dark.js b/examples/line/isoline/demo/ele_dark.js
index cb575b888b..fc7e8a4535 100644
--- a/examples/line/isoline/demo/ele_dark.js
+++ b/examples/line/isoline/demo/ele_dark.js
@@ -16,7 +16,19 @@ scene.on('loaded', () => {
fetch('https://gw.alipayobjects.com/os/rmsportal/ZVfOvhVCzwBkISNsuKCc.json')
.then(res => res.json())
.then(data => {
- const layer = new LineLayer({})
+ const layer = new LineLayer({
+ enableMultiPassRenderer: true,
+ passes: [
+ [
+ 'bloom',
+ {
+ bloomBaseRadio: 0.8,
+ bloomRadius: 2,
+ bloomIntensity: 1
+ }
+ ]
+ ]
+ })
.source(data)
.size('ELEV', h => {
return [ h % 50 === 0 ? 1.0 : 0.5, (h - 1300) * 0.2 ];
diff --git a/examples/point/image/demo/fillimage.js b/examples/point/image/demo/fillimage.js
new file mode 100644
index 0000000000..6797422a7f
--- /dev/null
+++ b/examples/point/image/demo/fillimage.js
@@ -0,0 +1,58 @@
+import { Scene, PointLayer } from '@antv/l7';
+import { GaodeMap } from '@antv/l7-maps';
+
+const scene = new Scene({
+ id: 'map',
+ map: new GaodeMap({
+ pitch: 0,
+ style: 'light',
+ center: [ 121.434765, 31.256735 ],
+ zoom: 14.83
+ })
+});
+scene.on('loaded', () => {
+ fetch(
+ 'https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json'
+ )
+ .then(res => res.json())
+ .then(data => {
+ scene.addImage(
+ '00',
+ 'https://gw.alipayobjects.com/zos/basement_prod/604b5e7f-309e-40db-b95b-4fac746c5153.svg'
+ );
+ scene.addImage(
+ '01',
+ 'https://gw.alipayobjects.com/zos/basement_prod/30580bc9-506f-4438-8c1a-744e082054ec.svg'
+ );
+ scene.addImage(
+ '02',
+ 'https://gw.alipayobjects.com/zos/basement_prod/7aa1f460-9f9f-499f-afdf-13424aa26bbf.svg'
+ );
+ const imageLayer = new PointLayer({ layerType: 'fillImage' })
+ .source(data, {
+ parser: {
+ type: 'json',
+ x: 'longitude',
+ y: 'latitude'
+ }
+ })
+ .shape('name', [ '00', '01', '02' ])
+ .active({
+ color: '#0ff',
+ mix: 0.5
+ })
+ .size(45);
+ scene.addLayer(imageLayer);
+
+ let r = 0;
+ rotate();
+ function rotate() {
+ r += 0.2;
+ imageLayer.style({
+ rotation: r
+ });
+ scene.render();
+ requestAnimationFrame(rotate);
+ }
+ });
+});
diff --git a/examples/point/image/demo/meta.json b/examples/point/image/demo/meta.json
index 73fef08ce3..0109a7343e 100644
--- a/examples/point/image/demo/meta.json
+++ b/examples/point/image/demo/meta.json
@@ -9,6 +9,11 @@
"title": "符号图",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*oVyHT5S3sv0AAAAAAAAAAABkARQnAQ"
},
+ {
+ "filename": "fillimage.js",
+ "title": "贴地符号图",
+ "screenshot": "https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*1kBZTaains4AAAAAAAAAAAAAARQnAQ"
+ },
{
"filename": "locate.js",
"title": "精确符号",
diff --git a/gatsby-config.js b/gatsby-config.js
index 883ebb32b4..4aff7e7b7d 100644
--- a/gatsby-config.js
+++ b/gatsby-config.js
@@ -14,6 +14,7 @@ module.exports = {
'Large-scale WebGL-powered Geospatial data visualization analysis framework',
siteUrl: 'https://l7.antv.vision',
githubUrl: 'https://github.com/antvis/L7',
+ keywords: 'l7, L7, antv/l7, 地理, 空间可视化, Webgl, webgl, 地图, webgis, 3d, GIS, gis, Mapbox, deckgl, g2, g6, antv,',
showChartResize: true, // 是否在demo页展示图表视图切换
showAPIDoc: true, // 是否在demo页展示API文档
navs: [
@@ -229,6 +230,14 @@ module.exports = {
},
order: 9,
},
+ {
+ slug: 'api/pass',
+ title: {
+ zh: '后处理模块',
+ en: 'MultiPass',
+ },
+ order: 10,
+ },
{
slug: 'api/district',
title: {