mirror of https://gitee.com/antv-l7/antv-l7
fix(master): merge master branch fix conflict
This commit is contained in:
commit
ea3e6ca5d5
|
@ -1,400 +0,0 @@
|
|||
.l7-marker-container {
|
||||
width:100%
|
||||
}
|
||||
.l7-marker {
|
||||
position: absolute !important;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
}
|
||||
.l7-popup-anchor-top,
|
||||
.l7-popup-anchor-top-left,
|
||||
.l7-popup-anchor-top-right {
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-bottom,
|
||||
.l7-popup-anchor-bottom-left,
|
||||
.l7-popup-anchor-bottom-right {
|
||||
-webkit-flex-direction: column-reverse;
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-left {
|
||||
-webkit-flex-direction: row;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-right {
|
||||
-webkit-flex-direction: row-reverse;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
.l7-popup {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
will-change: transform;
|
||||
pointer-events: none;
|
||||
z-index: 5;
|
||||
}
|
||||
.l7-popup-tip {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 10px solid transparent;
|
||||
z-index: 1;
|
||||
}
|
||||
.l7-popup-anchor-top .l7-popup-tip {
|
||||
-webkit-align-self: center;
|
||||
align-self: center;
|
||||
border-top: none;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-top-left .l7-popup-tip {
|
||||
-webkit-align-self: flex-start;
|
||||
align-self: flex-start;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-top-right .l7-popup-tip {
|
||||
-webkit-align-self: flex-end;
|
||||
align-self: flex-end;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-bottom .l7-popup-tip {
|
||||
-webkit-align-self: center;
|
||||
align-self: center;
|
||||
border-bottom: none;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-bottom-left .l7-popup-tip {
|
||||
-webkit-align-self: flex-start;
|
||||
align-self: flex-start;
|
||||
border-bottom: none;
|
||||
border-left: none;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-bottom-right .l7-popup-tip {
|
||||
-webkit-align-self: flex-end;
|
||||
align-self: flex-end;
|
||||
border-bottom: none;
|
||||
border-right: none;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-left .l7-popup-tip {
|
||||
-webkit-align-self: center;
|
||||
align-self: center;
|
||||
border-left: none;
|
||||
border-right-color: #fff;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-right .l7-popup-tip {
|
||||
-webkit-align-self: center;
|
||||
align-self: center;
|
||||
border-right: none;
|
||||
border-left-color: #fff;
|
||||
}
|
||||
|
||||
.l7-popup-close-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
font-size: 25px;
|
||||
line-height: 20px;
|
||||
border-radius: 0 3px 0 0;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.l7-popup-close-button:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.l7-popup-content {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
padding: 10px 10px 15px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-top-left .l7-popup-content {
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-top-right .l7-popup-content {
|
||||
border-top-right-radius: 0;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-bottom-left .l7-popup-content {
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.l7-popup-anchor-bottom-right .l7-popup-content {
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.l7-popup-track-pointer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.l7-popup-track-pointer * {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.l7-map:hover .l7-popup-track-pointer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.l7-map:active .l7-popup-track-pointer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.l7-popup-close-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border: 0;
|
||||
border-radius: 0 3px 0 0;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.l7-popup-close-button:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.l7-popup-content {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
padding: 10px 10px 15px;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.l7-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.l7-bar a,
|
||||
.l7-bar a:hover {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.l7-bar a,
|
||||
.l7-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.l7-bar a:hover {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.l7-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.l7-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.l7-bar a.l7-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.l7-control-container {
|
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
.l7-control-hide {
|
||||
display: none;
|
||||
}
|
||||
.l7-control {
|
||||
position: relative;
|
||||
z-index: 800;
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
.l7-top,
|
||||
.l7-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.l7-top {
|
||||
top: 0;
|
||||
}
|
||||
.l7-right {
|
||||
right: 0;
|
||||
}
|
||||
.l7-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.l7-left {
|
||||
left: 0;
|
||||
}
|
||||
.l7-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.l7-right .l7-control {
|
||||
float: right;
|
||||
}
|
||||
.l7-top .l7-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.l7-bottom .l7-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.l7-left .l7-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.l7-right .l7-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.l7-control-container .l7-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
margin: 0;
|
||||
}
|
||||
.l7-control-attribution,
|
||||
.l7-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
.l7-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.l7-control-attribution a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.l7-container .l7-control-attribution,
|
||||
.l7-container .l7-control-scale {
|
||||
font-size: 11px;
|
||||
}
|
||||
.l7-left .l7-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.l7-bottom .l7-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.l7-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.l7-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.l7-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.l7-touch .l7-control-attribution,
|
||||
.l7-touch .l7-control-layers,
|
||||
.l7-touch .l7-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.l7-touch .l7-control-layers,
|
||||
.l7-touch .l7-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.l7-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.l7-control-layers-toggle {
|
||||
background-image: url(../images/layers.svg);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.l7-retina .l7-control-layers-toggle {
|
||||
background-image: url(../images/layers.svg);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.l7-touch .l7-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.l7-control-layers .l7-control-layers-list,
|
||||
.l7-control-layers-expanded .l7-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.l7-control-layers-expanded .l7-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.l7-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.l7-control-layers-scrollbar {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.l7-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.l7-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.l7-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
31
README.md
31
README.md
|
@ -26,41 +26,14 @@ yarn install
|
|||
yarn watch
|
||||
```
|
||||
|
||||
运行 Demo
|
||||
运行 Demo,基于 Storybook:
|
||||
```bash
|
||||
yarn storybook
|
||||
```
|
||||
|
||||
代替 `git commit` 提交:
|
||||
```bash
|
||||
yarn commit
|
||||
```
|
||||
|
||||
## view doc example
|
||||
|
||||
```bash
|
||||
npm start
|
||||
yarn start
|
||||
```
|
||||
visit http://localhost:8000/
|
||||
|
||||
## Add Package
|
||||
|
||||
add new package:
|
||||
```bash
|
||||
lerna create my-pack -y
|
||||
```
|
||||
|
||||
将 ui-lib 作为 my-pack 的依赖:
|
||||
```bash
|
||||
yarn workspace my-pack add ui-lib/1.0.0
|
||||
```
|
||||
|
||||
将 lodash 添加为所有 package 的依赖(不包含root)
|
||||
```bash
|
||||
yarn workspaces run add lodash
|
||||
```
|
||||
|
||||
将 typescript 设置为 root 的开发依赖
|
||||
```bash
|
||||
yarn add -W -D typescript jest
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@ L7 是由蚂蚁金服 AntV 数据可视化团队推出的基于 WebGL 的开源
|
|||
### Installation
|
||||
|
||||
```
|
||||
npm install @antv/l7
|
||||
npm install @antv/l7@beta
|
||||
```
|
||||
|
||||
## 核心特性
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
// @see https://babeljs.io/docs/en/next/config-files#project-wide-configuration
|
||||
module.exports = api => {
|
||||
api.cache(() => process.env.NODE_ENV);
|
||||
|
||||
const isSite = api.env('site');
|
||||
const isCDNBundle = api.env('bundle');
|
||||
const isCommonJS = api.env('cjs');
|
||||
const isESModule = api.env('esm');
|
||||
const isTest = api.env('test');
|
||||
if (process.env.GATSBY === 'true') { //
|
||||
|
||||
if (isSite) {
|
||||
return {
|
||||
presets: [
|
||||
'babel-preset-gatsby'
|
||||
|
@ -54,7 +57,7 @@ module.exports = api => {
|
|||
development: isCommonJS
|
||||
}
|
||||
],
|
||||
'@babel/preset-typescript'
|
||||
'@babel/preset-typescript',
|
||||
],
|
||||
plugins: [
|
||||
'@babel/plugin-proposal-optional-chaining',
|
||||
|
@ -102,7 +105,7 @@ module.exports = api => {
|
|||
// 按需引用 @see https://github.com/lodash/babel-plugin-lodash
|
||||
'lodash'
|
||||
// 内联 WebGL 常量 @see https://www.npmjs.com/package/babel-plugin-inline-webgl-constants
|
||||
// isCDNBundle ? 'inline-webgl-constants' : {}
|
||||
// isCDNBundle ? 'inline-webgl-constants' : {},
|
||||
],
|
||||
ignore: [
|
||||
'node_modules',
|
||||
|
|
|
@ -1,7 +1,2 @@
|
|||
// @ts-ignore
|
||||
export * from '@l7/scene';
|
||||
// @ts-ignore
|
||||
export * from '@l7/layers';
|
||||
|
||||
// @ts-ignore
|
||||
export * from '@l7/component';
|
||||
export * from '@antv/l7';
|
||||
|
|
|
@ -35,9 +35,13 @@ module.exports = [
|
|||
resolve: [ '.tsx', '.ts' ],
|
||||
entries: [
|
||||
{
|
||||
find: /^@l7\/(.*)/,
|
||||
replacement: resolveFile('packages/$1/src')
|
||||
}
|
||||
find: /^@antv\/l7-(.*)/,
|
||||
replacement: resolveFile('packages/$1/src'),
|
||||
},
|
||||
{
|
||||
find: /^@antv\/l7$/,
|
||||
replacement: resolveFile('packages/l7/src'),
|
||||
},
|
||||
]
|
||||
}
|
||||
),
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Scene } from '@l7/scene';
|
||||
import { RasterLayer } from '@l7/layers'
|
||||
import { RasterLayer, Scene } from '@antv/l7';
|
||||
import * as GeoTIFF from 'geotiff';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { Scene } from '@l7/scene';
|
||||
import { PointLayer } from '@l7/layers'
|
||||
import { Scale, Zoom, Layers } from '@l7/component';
|
||||
import { PointLayer, Scale, Scene, Layers, Zoom } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Scene } from '@l7/scene';
|
||||
import { Scale, Zoom } from '@l7/component';
|
||||
import { Scale, Zoom, Scene } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import { Scene } from '@l7/scene';
|
||||
import { PointLayer } from '@l7/layers'
|
||||
import { Scale, Zoom, Layers } from '@l7/component';
|
||||
import { Scale, Zoom, Scene, Layers, PointLayer } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Scene } from '@l7/scene';
|
||||
import { LineLayer } from '@l7/layers'
|
||||
import { LineLayer, Scene } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Scene } from '@l7/scene';
|
||||
import { Scene } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Scene } from '@l7/scene';
|
||||
import { Scene } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
pitch: 0,
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
# IoC 容器、依赖注入与服务说明
|
||||
|
||||
在面向对象编程领域,[SOLID](https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)) 、[“组合优于继承”](https://en.wikipedia.org/wiki/Composition_over_inheritance) 都是经典的设计原则。
|
||||
|
||||
IoC(Inversion of Control) 控制反转这种设计模式将对象的创建销毁、依赖关系交给容器处理,是以上设计原则的一种经典实践。其中它的一种实现 DI(Dependency Injection) 即依赖注入在工程领域应用十分广泛(下图来自 [Dependency-Injection-in-practice-CodeCAMP.pdf](http://www.mono.hr/Pdf/Dependency-Injection-in-practice-CodeCAMP.pdf)),最著名的当属 Spring:
|
||||
|
||||
![](./screenshots/di-containers.png)
|
||||
|
||||
而在 JavaScript 领域,[Angular](https://angular.io/guide/dependency-injection)、[NestJS](https://docs.nestjs.com/fundamentals/custom-providers) 也都实现了自己的 IoC 容器。
|
||||
|
||||
L7 选择了 [InversifyJS](https://github.com/inversify/InversifyJS/blob/master/wiki/oo_design.md) 作为轻量的 IoC 容器,统一管理各类复杂的服务,实现松耦合的代码结构,同时具有以下收益:
|
||||
* 提供高扩展性。
|
||||
* 支持地图底图(高德、Mapbox)切换
|
||||
* 支持渲染引擎替换
|
||||
* 插件化
|
||||
* 便于测试。测试用例中替换渲染引擎服务为基于 headless-gl 的渲染服务。
|
||||
|
||||
下图清晰的展示了切换引擎和底图时均不会影响核心代码:
|
||||
![](./screenshots/packages.png)
|
||||
|
||||
# 多层次容器
|
||||
|
||||
L7 需要支持多场景(Scene),每个场景中又包含了多个图层(Layer)。不同的服务可能隶属全局、Scene 和 Layer,因此对于容器也有层次化的要求。
|
||||
试想如果我们只有一个全局容器,其中绑定的所有服务自然也都成了全局服务,在多场景下(页面中一个高德地图、一个 Mapbox)销毁高德地图的渲染服务,将影响到 Mapbox 的展示。
|
||||
|
||||
下图为 L7 的四个独立场景(两个高德、两个 Mapbox)DEMO 展示效果,它们应该是能互不干扰运行的:
|
||||
![](./screenshots/multi-scene.png)
|
||||
|
||||
在 Angular 中也有[分层容器](https://angular.io/guide/hierarchical-dependency-injection)的应用。L7 使用的是 InversifyJS 提供的[层次化依赖注入功能](https://github.com/inversify/InversifyJS/blob/master/wiki/hierarchical_di.md)。
|
||||
|
||||
容器层次关系及数目如下:
|
||||
```bash
|
||||
RootContainer 1
|
||||
-> SceneContainer 1.*
|
||||
-> LayerContainer 1.*
|
||||
```
|
||||
其中每种容器包含不同类型的服务,这些服务有的是单例,有的是工厂方法。子容器应该能访问父容器中绑定的服务,即如果 RootContainer 已经绑定了全局日志服务,SceneContainer 不需要重复绑定也能注入。
|
||||
|
||||
下面详细介绍下每种容器中的服务及其 API,在自定义图层、自定义插件以及自定义后处理效果中都可以方便地使用这些服务。
|
||||
|
||||
## 全局容器
|
||||
|
||||
一些全局性服务不需要用户手动创建,也无需显式销毁。我们在全局容器中完成一次性的绑定,后续在所有场景、图层中都可以让容器注入这些服务的单例。类似 Angular 中的 [root ModuleInjector](https://angular.io/guide/hierarchical-dependency-injection#moduleinjector)。
|
||||
|
||||
例如日志、Shader 模块化服务应该是全局性的单例,我们在 `RootContainer` 完成依赖声明:
|
||||
```typescript
|
||||
// 在根容器中绑定日志服务为单例
|
||||
rootContainer
|
||||
.bind<ILogService>(TYPES.ILogService)
|
||||
.to(LogService)
|
||||
.inSingletonScope();
|
||||
```
|
||||
|
||||
目前 L7 中全局性服务说明如下:
|
||||
|
||||
| 服务名称 | 类型 | 说明 |
|
||||
| -------- | --- | --------- |
|
||||
| logger | 全局服务 | 在控制台输出信息 |
|
||||
|
||||
* 日志服务。
|
||||
* Shader 模块化服务。提供基本的 GLSL 模块化服务,基于字符串替换实现。
|
||||
* 配置项校验服务。[详见](./ConfigSchemaValidation.md)
|
||||
|
||||
### 日志服务
|
||||
|
||||
基于 `probe.gl` 实现,默认只输出 debug 级别以上的日志信息。开发模式下通过设置日志等级输出 debug 信息,另外 debug 信息会带上时间戳打点,类似这样:
|
||||
```bash
|
||||
L7: 403ms map loaded
|
||||
L7: 405ms add event listeners on canvas
|
||||
L7: 676ms regenerate vertex attributes: color finished
|
||||
```
|
||||
|
||||
通过 `logger` 引用,可使用 API 如下:
|
||||
|
||||
| 方法名 | 参数 | 返回值 | 说明 |
|
||||
| -------- | ------------- | --------- | --------- |
|
||||
| debug | `(message: string)` | 无 | 输出 debug 级别信息,会带上时间戳 |
|
||||
| info | `(message: string)` | 无 | 输出 info 级别信息 |
|
||||
| warn | `(message: string)` | 无 | 输出 warn 级别信息 |
|
||||
| error | `(message: string)` | 无 | 输出 error 级别信息 |
|
||||
|
||||
在自定义图层中使用示例如下:
|
||||
```typescript
|
||||
class PolygonLayer extends BaseLayer<IPolygonLayerStyleOptions> {
|
||||
protected renderModels() {
|
||||
// 输出 debug 级别信息
|
||||
this.logger.debug('start to render...');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Shader 模块化服务
|
||||
|
||||
通过 `shaderModuleService` 引用,可使用 API 如下:
|
||||
|
||||
| 方法名 | 参数 | 返回值 | 说明 |
|
||||
| -------- | ------------- | --------- | --------- |
|
||||
| registerModule | `(moduleName: string, moduleParams: IModuleParams)` | 无 | 使用模块名和参数注册 GLSL 模块,其中 `IModuleParams` 格式见下面 |
|
||||
| getModule | `(moduleName: string)` | `IModuleParams` | 根据模块名获取编译后的 GLSL 模块 |
|
||||
|
||||
GLSL 模块参数如下:
|
||||
```typescript
|
||||
interface IModuleParams {
|
||||
vs: string; // vertex shader 字符串
|
||||
fs: string; // fragment shader 字符串
|
||||
uniforms?: { // 可选,uniforms
|
||||
[key: string]: IUniform;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
我们以自定义后处理效果场景为例,完整教程见[自定义后处理效果](自定义后处理效果.md):
|
||||
```typescript
|
||||
protected setupShaders() {
|
||||
// 使用 Shader 服务注册 GLSL 模块
|
||||
this.shaderModuleService.registerModule('dotScreenEffect', {
|
||||
vs: this.quad, // Vertex Shader 固定
|
||||
fs: ``, // 暂时省略,在下一小节中详细介绍
|
||||
});
|
||||
|
||||
// 使用 Shader 服务获取编译后的 GLSL 模块
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule('dotScreenEffect');
|
||||
// 使用渲染器服务获取视口尺寸
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
||||
return {
|
||||
vs,
|
||||
fs,
|
||||
uniforms: {
|
||||
...uniforms,
|
||||
u_ViewportSize: [width, height],
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 配置项校验服务
|
||||
|
||||
开发者不需要显式调用该服务。
|
||||
|
||||
Layer 子类可以通过重载 `getConfigSchema()` 方法定义自身的特有属性。例如 `PolygonLayer` 需要定义透明度,详见[ConfigSchemaValidation 使用方法](ConfigSchemaValidation.md):
|
||||
```typescript
|
||||
protected getConfigSchema() {
|
||||
return {
|
||||
properties: {
|
||||
opacity: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
以上就是供开发者使用的常见全局服务,下面我们将介绍场景容器及其内部服务。
|
||||
|
||||
## Scene 容器
|
||||
|
||||
场景可以承载多个图层,与地图底图一一对应。每个场景都有自己独立的容器确保多个场景间服务不会互相干扰,同时继承全局容器以便访问全局服务。容器内服务包括:
|
||||
|
||||
* 地图底图服务。每个场景有一个对应的地图底图。
|
||||
* 渲染引擎服务。由于依赖 WebGL 上下文,基于 `regl` 实现。
|
||||
* 图层管理服务。管理场景中所有的图层,负责图层的创建、销毁。
|
||||
* PostProcessingPass。内置常用的后处理效果。
|
||||
|
||||
### 地图底图服务
|
||||
|
||||
兼容 Mapbox 和高德,开发者可以获取当前地图的状态、调用地图相机动作(缩放、平移、旋转)。
|
||||
|
||||
通过 `mapService` 引用。
|
||||
|
||||
常用地图状态获取方法如下:
|
||||
| 方法名 | 参数 | 返回值 | 说明 |
|
||||
| -------- | ------------- | --------- | --------- |
|
||||
| getSize | 无 | `[number, number]` | 获取地图尺寸(像素单位) |
|
||||
| getZoom | 无 | `number` | 获取当前地图缩放等级,以 Mapbox 为准 |
|
||||
| getCenter | 无 | `{lng: number; lat: number}` | 获取当前地图中心点经纬度 |
|
||||
| getPitch | 无 | `number` | 获取当前地图仰角 |
|
||||
| getRotation | 无 | `number` | 获取当前地图逆时针旋转角度 |
|
||||
| getBounds | 无 | `[[number, number], [number, number]]` | 获取当前地图可视区域 `[西南角、东北角]` |
|
||||
|
||||
⚠️对于一些地图属性将采用兼容性处理。
|
||||
|
||||
* 缩放等级,差异表现在:
|
||||
1. 取值范围。高德缩放等级范围 `[3, 18]`,而 Mapbox 为 `[0, 20]`。
|
||||
2. 高德 `3` 缩放等级对应 Mapbox `2` 缩放等级。考虑兼容性,`getZoom()` 将返回 Mapbox 定义等级。
|
||||
* 旋转角度。高德返回地图顺时针旋转角度,Mapbox 返回逆时针旋转角度。考虑兼容性,`getRotation()` 将返回地图逆时针旋转角度。
|
||||
|
||||
除了获取地图状态,还可以控制地图进行一些相机动作。
|
||||
|
||||
### [WIP]渲染引擎服务
|
||||
|
||||
目前 L7 使用 [regl](https://github.com/regl-project/regl),但开发者不需要关心底层 WebGL 渲染引擎实现,即使后续更换了其他引擎,我们也将保持服务接口的稳定。
|
||||
|
||||
通过 `rendererService` 引用。
|
||||
|
||||
|
||||
|
||||
### 图层管理服务
|
||||
|
||||
开发者不需要显式调用。用于管理场景中所有的图层,负责图层的创建、销毁。
|
||||
|
||||
## Layer 容器
|
||||
|
||||
每个图层有独立的容器,同时继承自所属场景容器,自然也可以访问全局服务。
|
||||
|
||||
* 样式管理服务。
|
||||
* MultiPassRenderer 服务。详见[MultiPassRenderer 说明](./MultiPassRenderer.md)
|
||||
|
||||
## 参考资料
|
||||
|
||||
* [动态依赖注入](https://github.com/inversify/InversifyJS/issues/1088)
|
|
@ -35,7 +35,7 @@ export interface IPostProcessingPass extends IPass {
|
|||
}
|
||||
```
|
||||
|
||||
具体实现依赖 `@l7/renderer` 实现,目前使用 regl 实现 IFramebuffer 等接口。
|
||||
具体实现依赖 `@antv/l7-renderer` 实现,目前使用 regl 实现 IFramebuffer 等接口。
|
||||
|
||||
## 内置 Pass
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
After Width: | Height: | Size: 258 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.0 MiB |
Binary file not shown.
After Width: | Height: | Size: 974 KiB |
Binary file not shown.
After Width: | Height: | Size: 192 KiB |
|
@ -4,11 +4,10 @@ L7 提供三种使用方式:CDN、Submodule 以及 React 组件。
|
|||
|
||||
## 通过 CDN 使用
|
||||
|
||||
首先在 `<head>` 中引入 L7 CDN 版本的 JS 和 CSS 文件:
|
||||
首先在 `<head>` 中引入 L7 CDN 版本的 JS 文件:
|
||||
```html
|
||||
<head>
|
||||
<script src='https://api.l7/v2.0.0-beta/l7.js'></script>
|
||||
<link href='https://api.l7/v2.0.0-beta/l7.css' rel='stylesheet' />
|
||||
</head>
|
||||
```
|
||||
|
||||
|
@ -79,8 +78,6 @@ L7 提供三种使用方式:CDN、Submodule 以及 React 组件。
|
|||
|
||||
// 添加图层到场景中
|
||||
scene.addLayer(layer);
|
||||
// 渲染场景
|
||||
scene.render();
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
@ -92,17 +89,16 @@ L7 提供三种使用方式:CDN、Submodule 以及 React 组件。
|
|||
|
||||
## 通过 Submodule 使用
|
||||
|
||||
首先通过 `npm/yarn` 安装 `@l7/scene` 和 `@l7/layers`:
|
||||
首先通过 `npm/yarn` 安装 `@antv/l7`:
|
||||
```bash
|
||||
npm install --save @l7/scene @l7/layers
|
||||
npm install --save @antv/l7
|
||||
// or
|
||||
yarn add @l7/scene @l7/layers
|
||||
yarn add @antv/l7
|
||||
```
|
||||
|
||||
然后就可以使用其中包含的场景和各类图层:
|
||||
```typescript
|
||||
import { Scene } from '@l7/scene';
|
||||
import { PolygonLayer } from '@l7/layers';
|
||||
import { Scene, PolygonLayer } from '@antv/l7';
|
||||
|
||||
(async function() {
|
||||
// 获取数据
|
||||
|
@ -142,19 +138,9 @@ import { PolygonLayer } from '@l7/layers';
|
|||
|
||||
// 添加图层到场景中
|
||||
scene.addLayer(layer);
|
||||
|
||||
// 渲染场景
|
||||
scene.render();
|
||||
})();
|
||||
```
|
||||
|
||||
最后在 `<head>` 中引入 L7 CDN 版本的 CSS 文件:
|
||||
```html
|
||||
<head>
|
||||
<link href='https://api.l7/v2.0.0-beta/l7.css' rel='stylesheet' />
|
||||
</head>
|
||||
```
|
||||
|
||||
L7 目前的文档都通过这种方式使用,可以参考项目中的 stories:
|
||||
* [高德地图](https://github.com/antvis/L7/blob/next/stories/MapAdaptor/components/AMap.tsx)
|
||||
* [Mapbox](https://github.com/antvis/L7/blob/next/stories/MapAdaptor/components/Mapbox.tsx)
|
||||
|
@ -164,8 +150,7 @@ L7 目前的文档都通过这种方式使用,可以参考项目中的 stories
|
|||
|
||||
React 组件待开发,目前可以暂时以 Submodule 方式使用:
|
||||
```tsx
|
||||
import { Scene } from '@l7/scene';
|
||||
import { PolygonLayer } from '@l7/layers';
|
||||
import { Scene, PolygonLayer } from '@antv/l7';
|
||||
import * as React from 'react';
|
||||
|
||||
export default class AMap extends React.Component {
|
||||
|
@ -206,7 +191,6 @@ export default class AMap extends React.Component {
|
|||
opacity: 0.8,
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
scene.render();
|
||||
this.scene = scene;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,19 +11,19 @@
|
|||
|
||||
因此目前和 Mapbox 做法一样,我们使用 Rollup 构建 CDN Bundler。
|
||||
|
||||
打包命令如下,会在 `dist/` 下输出产物:
|
||||
打包命令如下,会在 `packages/l7/dist` 下输出产物:
|
||||
```bash
|
||||
yarn bundle
|
||||
```
|
||||
|
||||
### UMD
|
||||
|
||||
以 L7 为命名空间,让用户可以通过类似 `L7.Scene` 的方式使用。同时以 UMD 为构建目标:
|
||||
以 L7 为命名空间,让用户可以通过类似 `L7.Scene` 的方式使用。同时以 UMD 为构建目标,输出到 `packages/l7/dist` 下:
|
||||
```javascript
|
||||
{
|
||||
input: resolveFile('build/bundle.ts'),
|
||||
output: {
|
||||
file: resolveFile('dist/bundle.js'),
|
||||
file: resolveFile('packages/l7/dist/bundle.js'),
|
||||
format: 'umd',
|
||||
name: 'L7',
|
||||
},
|
||||
|
@ -33,13 +33,12 @@ yarn bundle
|
|||
目前只需要暴露场景以及图层相关的 API,因此 Bundler 非常简单:
|
||||
```typescript
|
||||
// build/bundle.ts
|
||||
export * from '@l7/scene';
|
||||
export * from '@l7/layers';
|
||||
export * from '@antv/l7';
|
||||
```
|
||||
|
||||
### Alias
|
||||
|
||||
为了帮助 resolver 定位 lerna packages,需要重命名类似 `@l7/scene` 这样的依赖路径:
|
||||
为了帮助 resolver 定位 lerna packages,需要重命名类似 `@antv/l7-scene` 这样的依赖路径:
|
||||
```javascript
|
||||
import alias from '@rollup/plugin-alias';
|
||||
|
||||
|
@ -314,9 +313,36 @@ yarn build
|
|||
},
|
||||
```
|
||||
|
||||
### [WIP] 生成 TS 声明文件
|
||||
### 生成 TS 声明文件
|
||||
|
||||
和构建前类型检查不同,此时我们需要 tsc 输出类型声明文件了,当然不需要包含 story 和测试用例。
|
||||
和构建前类型检查不同,此时我们需要 tsc 输出类型声明文件了:
|
||||
```json
|
||||
{
|
||||
"postbuild": "yarn build:declarations",
|
||||
"build:declarations": "lerna exec --stream --no-bail 'tsc --project ./tsconfig.build.json'"
|
||||
}
|
||||
```
|
||||
|
||||
当然不需要包含 story 和测试用例:
|
||||
```json
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": false,
|
||||
"emitDeclarationOnly": true,
|
||||
"declaration": true,
|
||||
"rootDir": "./",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@antv/l7-*": ["packages/*/src"],
|
||||
"@antv/l7": ["packages/l7/src"],
|
||||
"*": ["node_modules", "packages"]
|
||||
}
|
||||
},
|
||||
"exclude": ["**/*.story.*", "**/__tests__/**/*", "**/*.spec.*", "dist"],
|
||||
"include": []
|
||||
}
|
||||
```
|
||||
|
||||
### [WIP] 异步加载 Mapbox
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ module.exports = {
|
|||
|
||||
### 单元测试
|
||||
|
||||
这类测试直接使用 Jest API 就好了,我们以 `@l7/core` 模块的 `ShaderModuleService` 为例,编写一个简单的测试用例:
|
||||
这类测试直接使用 Jest API 就好了,我们以 `@antv/l7-core` 模块的 `ShaderModuleService` 为例,编写一个简单的测试用例:
|
||||
|
||||
```typescript
|
||||
// services/shader/__test__/shader.spec.ts
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
# 自定义后处理效果
|
||||
|
||||
L7 自定义了一套较为灵活的渲染管线,在后处理效果方面提供了最大程度的扩展性。除了直接使用内置的常用效果(例如下图中 ColorHalftone、六边形像素化、噪声、Sepia),开发者还可以自定义任何后处理效果,在场景中完成注册即可应用到任意图层上。
|
||||
|
||||
![](./screenshots/multi-scene.png)
|
||||
|
||||
下面我们以 [glfx.js](http://evanw.github.io/glfx.js/demo/) 中的 Dot Screen 效果(下图)为例,介绍如何在 PolygonLayer 中应用这种效果。完整 DEMO 代码[在此]()。
|
||||
|
||||
![](./screenshots/custom-effect.png)
|
||||
|
||||
我们将分成三步介绍:
|
||||
1. 定义效果
|
||||
* 定义效果参数
|
||||
* 继承后处理效果基类
|
||||
* 编写 Fragment Shader
|
||||
2. 在场景中注册效果
|
||||
3. 在图层中使用效果
|
||||
|
||||
## 定义效果
|
||||
|
||||
### 定义效果参数
|
||||
|
||||
实现任何一种后处理效果,我们都希望提供一些灵活的参数,可以在运行时供使用者修改。以我们需要实现的 Dot Screen 效果为例,参数接口 `IDotScreenEffectConfig` 定义如下:
|
||||
```typescript
|
||||
interface IDotScreenEffectConfig {
|
||||
center: [number, number]; // pattern 圆心
|
||||
angle: number; // dot 旋转角度
|
||||
size: number; // dot 尺寸
|
||||
}
|
||||
```
|
||||
|
||||
### 继承后处理效果基类
|
||||
|
||||
为了最大程度减少样板代码,L7 提供了 `BasePostProcessingPass` 基类供子类继承,同时通过泛型将上一步定义的参数接口传入:
|
||||
```typescript
|
||||
import { BasePostProcessingPass } from '@antv/l7';
|
||||
|
||||
class DotScreenEffect extends BasePostProcessingPass<IDotScreenEffectConfig> {
|
||||
//... 省略重载方法
|
||||
}
|
||||
```
|
||||
|
||||
接下来我们只需要重载基类的一个方法 `setupShaders`。在这个方法中我们可以使用 L7 内置的服务,例如 Shader 服务、渲染服务等,各服务说明及 API 使用方式[详见](./IoC%20容器、依赖注入与服务说明.md)。
|
||||
```typescript
|
||||
protected setupShaders() {
|
||||
// 使用 Shader 服务注册 GLSL 模块
|
||||
this.shaderModuleService.registerModule('dotScreenEffect', {
|
||||
vs: this.quad, // Vertex Shader 固定
|
||||
fs: ``, // 暂时省略,在下一小节中详细介绍
|
||||
});
|
||||
|
||||
// 使用 Shader 服务获取编译后的 GLSL 模块
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule('dotScreenEffect');
|
||||
// 使用渲染器服务获取视口尺寸
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
||||
return {
|
||||
vs,
|
||||
fs,
|
||||
uniforms: {
|
||||
...uniforms,
|
||||
u_ViewportSize: [width, height],
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 编写 Fragment Shader
|
||||
|
||||
在编写 Fragment Shader 时,可以按照如下模版。由于 L7 实现了简单的 GLSL 模块化,可以使用一些特殊的语法,例如:
|
||||
* Uniform 设置默认值
|
||||
* 引入 L7 内置 GLSL 模块
|
||||
|
||||
```glsl
|
||||
varying vec2 v_UV;
|
||||
|
||||
uniform sampler2D u_Texture;
|
||||
uniform vec2 u_ViewportSize : [1.0, 1.0];
|
||||
|
||||
// 自定义效果参数声明
|
||||
|
||||
// 自定义效果函数 myCustomEffect 定义
|
||||
|
||||
void main() {
|
||||
// 纹理采样
|
||||
gl_FragColor = vec4(texture2D(u_Texture, v_UV));
|
||||
// 应用自定义效果函数
|
||||
gl_FragColor = myCustomEffect(gl_FragColor, u_ViewportSize, v_UV);
|
||||
}
|
||||
```
|
||||
|
||||
Dot Screen 效果具体 GLSL 代码可以参考 [luma.gl](https://github.com/uber/luma.gl/blob/master/modules/engine/src/effects/shader-modules/fun-filters/dotscreen.js#L11-L30)。
|
||||
|
||||
完整 Fragment Shader 代码如下。需要注意的是这里 Uniform 名需要和效果配置项属性名统一,即 `size` 对应 `u_Size`、`angle` 对应 `u_Angle`。:
|
||||
```glsl
|
||||
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;
|
||||
|
||||
// 自定义效果实现
|
||||
// @see https://github.com/uber/luma.gl/blob/master/modules/engine/src/effects/shader-modules/fun-filters/dotscreen.js#L11-L30
|
||||
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);
|
||||
}
|
||||
```
|
||||
|
||||
至此我们就完成了效果的定义。
|
||||
|
||||
## 在场景中注册
|
||||
|
||||
一种效果要想生效,必须先在场景中完成注册。`scene.registerPostProcessingPass()` 接受两个参数分别为上一步定义的效果构造函数以及效果名。
|
||||
后续我们在图层中使用时就可以通过效果名引用了:
|
||||
```typescript
|
||||
// 场景定义
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
type: 'mapbox',
|
||||
style: 'mapbox://styles/mapbox/streets-v9',
|
||||
center: [110.19382669582967, 50.258134],
|
||||
pitch: 0,
|
||||
zoom: 3,
|
||||
});
|
||||
// 注册自定义后处理效果
|
||||
scene.registerPostProcessingPass(
|
||||
DotScreenEffect, // 效果构造函数
|
||||
'dotScreenEffect', // 效果名,便于后续在图层中引用
|
||||
);
|
||||
```
|
||||
|
||||
## 在图层中使用效果
|
||||
|
||||
和 L7 内置的后处理效果使用方法一致,通过效果名引用,同时传入定义参数即可:
|
||||
```typescript
|
||||
const layer = new PolygonLayer({
|
||||
enableMultiPassRenderer: true,
|
||||
enablePicking: true,
|
||||
enableHighlight: true,
|
||||
passes: [
|
||||
[
|
||||
'dotScreenEffect', // 引用效果名
|
||||
{
|
||||
size: 8, // 传入参数
|
||||
angle: 1,
|
||||
},
|
||||
],
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
最终效果如下:
|
||||
|
||||
![](./screenshots/dotscreen.png)
|
|
@ -7,7 +7,24 @@ order: 1
|
|||
|
||||
## Scene
|
||||
|
||||
L7 地理可视化 地图,图层,组件,以及可视化所需要的资源,如图片,字体通过Scene统一管理
|
||||
```javascript
|
||||
// Module 引用
|
||||
import { Scene } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
mapStyle: 'dark',
|
||||
center: [ 110.770672, 34.159869 ],
|
||||
pitch: 45,
|
||||
});
|
||||
|
||||
// CDN 使用方法
|
||||
const scene = new L7.Scene({
|
||||
id: 'map',
|
||||
mapStyle: 'dark',
|
||||
center: [ 110.770672, 34.159869 ],
|
||||
pitch: 45,
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Map
|
||||
|
|
|
@ -29,21 +29,29 @@ L7 地理可视化 地图,图层,组件,以及可视化所需要的资源
|
|||
const map = scene.map
|
||||
|
||||
```
|
||||
为了统一不通底图之前的接口差异 L7 在scene层对map的方法做了统一,因此一些地图的操作方法可以通过scene调用这样,切换不同底图时保证表现一致。
|
||||
为了统一不同底图之前的接口差异 L7 在scene层对map的方法做了统一,因此一些地图的操作方法可以通过scene调用这样,切换不同底图时保证表现一致。
|
||||
|
||||
示例代码
|
||||
|
||||
```javascript
|
||||
import {Scene} from '@antv/scene';
|
||||
// Module 引用
|
||||
import { Scene } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
mapStyle: 'dark',
|
||||
center: [ 110.770672, 34.159869 ],
|
||||
pitch: 45,
|
||||
});
|
||||
|
||||
// CDN 使用方法
|
||||
const scene = new L7.Scene({
|
||||
id: 'map',
|
||||
mapStyle: 'dark',
|
||||
center: [ 110.770672, 34.159869 ],
|
||||
pitch:45
|
||||
})
|
||||
pitch: 45,
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### 构造函数
|
||||
|
||||
**Scene**
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import { Scene, PolygonLayer, LineLayer } from '@antv/l7';
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
|
|
|
@ -19,6 +19,3 @@ layer.source(
|
|||
}
|
||||
);
|
||||
scene.addLayer(layer);
|
||||
// scene.on('loaded', () => {
|
||||
// scene.addLayer(layer);
|
||||
// });
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
|
||||
require('./site/css/demo.css');
|
||||
require('./packages/component/src/css/l7.css');
|
||||
// window.geotiff = require('geotiff/dist/geotiff.bundle.min.js');
|
||||
// window.scene = require('./packages/scene/src');
|
||||
// window.layers = require('./packages/layers/src');
|
||||
// window.component = require('./packages/component/src');
|
||||
window.geotiff = require('geotiff/dist/geotiff.bundle.min.js');
|
||||
window.g2 = require('@antv/g2');
|
||||
window.l7 = require('@antv/l7');
|
||||
|
|
|
@ -156,7 +156,10 @@ module.exports = {
|
|||
}
|
||||
],
|
||||
playground: {
|
||||
container: '<div style="min-height: 500px; justify-content: center;position: relative" id="map"/>'
|
||||
container: '<div style="min-height: 500px; justify-content: center;position: relative" id="map"/>',
|
||||
dependencies: {
|
||||
'@antv/l7': 'beta'
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,14 +4,14 @@ exports.onCreateWebpackConfig = ({ getConfig }) => {
|
|||
config.resolve.extensions.push('.glsl');
|
||||
config.resolve.alias = {
|
||||
...config.resolve.alias,
|
||||
'@l7/core': path.resolve(__dirname, 'packages/core/src'),
|
||||
'@l7/component': path.resolve(__dirname, 'packages/component/src'),
|
||||
'@l7/layers': path.resolve(__dirname, 'packages/layers/src'),
|
||||
'@l7/maps': path.resolve(__dirname, 'packages/maps/src'),
|
||||
'@l7/renderer': path.resolve(__dirname, 'packages/renderer/src'),
|
||||
'@l7/scene': path.resolve(__dirname, 'packages/scene/src'),
|
||||
'@l7/source': path.resolve(__dirname, 'packages/source/src'),
|
||||
'@l7/utils': path.resolve(__dirname, 'packages/utils/src'),
|
||||
'@antv/l7': path.resolve(__dirname, 'packages/l7/src')
|
||||
'@antv/l7': path.resolve(__dirname, 'packages/l7/src'),
|
||||
'@antv/l7-core': path.resolve(__dirname, 'packages/core/src'),
|
||||
'@antv/l7-component': path.resolve(__dirname, 'packages/component/src'),
|
||||
'@antv/l7-layers': path.resolve(__dirname, 'packages/layers/src'),
|
||||
'@antv/l7-maps': path.resolve(__dirname, 'packages/maps/src'),
|
||||
'@antv/l7-renderer': path.resolve(__dirname, 'packages/renderer/src'),
|
||||
'@antv/l7-scene': path.resolve(__dirname, 'packages/scene/src'),
|
||||
'@antv/l7-source': path.resolve(__dirname, 'packages/source/src'),
|
||||
'@antv/l7-utils': path.resolve(__dirname, 'packages/utils/src'),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@ module.exports = {
|
|||
moduleFileExtensions: [ 'ts', 'tsx', 'js' ],
|
||||
modulePathIgnorePatterns: [ 'dist' ],
|
||||
moduleNameMapper: {
|
||||
'@l7/(.+)$': '<rootDir>packages/$1/src'
|
||||
'@antv/l7-(.+)$': '<rootDir>packages/$1/src',
|
||||
},
|
||||
notify: true,
|
||||
notifyMode: 'always',
|
||||
|
|
|
@ -4,16 +4,19 @@
|
|||
],
|
||||
"command": {
|
||||
"publish": {
|
||||
"ignoreChanges": ["*.md"],
|
||||
"ignoreChanges": [
|
||||
"*.md"
|
||||
],
|
||||
"allowBranch": [
|
||||
"master",
|
||||
"develop",
|
||||
"next"
|
||||
"next",
|
||||
"dev-container"
|
||||
],
|
||||
"message": "chore: publish"
|
||||
}
|
||||
},
|
||||
"version": "0.0.1",
|
||||
"version": "2.0.0-beta.10",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"publishConfig": {
|
||||
|
|
14
package.json
14
package.json
|
@ -6,7 +6,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@antv/g2": "^3.5.9",
|
||||
"@antv/gatsby-theme-antv": "^0.9.92",
|
||||
"@antv/gatsby-theme-antv": "0.10.1",
|
||||
"@babel/cli": "^7.6.4",
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/plugin-proposal-decorators": "^7.6.0",
|
||||
|
@ -72,6 +72,7 @@
|
|||
"jest-styled-components": "^6.2.1",
|
||||
"lerna": "^3.16.4",
|
||||
"lint-staged": "^9.2.4",
|
||||
"load-styles": "^2.0.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^7.0.18",
|
||||
|
@ -114,8 +115,8 @@
|
|||
},
|
||||
"scripts": {
|
||||
"start": "npm run site:develop",
|
||||
"site:develop": "GATSBY=true gatsby develop --open -H 0.0.0.0",
|
||||
"site:build": "npm run site:clean && GATSBY=true gatsby build --prefix-paths",
|
||||
"site:develop": "BABEL_ENV=site gatsby develop --open -H 0.0.0.0",
|
||||
"site:build": "npm run site:clean && BABEL_ENV=site gatsby build --prefix-paths",
|
||||
"site:clean": "gatsby clean",
|
||||
"site:deploy": "npm run site:build && gh-pages -d public",
|
||||
"site:publish": "gh-pages -d public",
|
||||
|
@ -123,7 +124,8 @@
|
|||
"lint:site": "eslint examples/**/**/*.js --fix",
|
||||
"prebuild": "run-p tsc lint",
|
||||
"build": "yarn clean && lerna run build",
|
||||
"todo:postbuild": "yarn build:declarations",
|
||||
"postbuild": "yarn build:declarations",
|
||||
"build:declarations": "lerna exec --stream --no-bail 'tsc --project ./tsconfig.build.json'",
|
||||
"fix": "run-p -c 'lint:ts-* --fix'",
|
||||
"lint:css": "stylelint 'packages/**/*.js{,x}'",
|
||||
"lint:ts-prod": "tslint --config tslint.prod.json 'packages/**/*.ts{,x}'",
|
||||
|
@ -132,13 +134,13 @@
|
|||
"lint": "run-p -c lint:*",
|
||||
"commit": "git-cz",
|
||||
"version": "lerna version --conventional-commits",
|
||||
"prerelease": "yarn build",
|
||||
"version:prerelease": "lerna version --conventional-prerelease",
|
||||
"prerelease": "yarn build && yarn bundle",
|
||||
"release": "lerna publish from-package --registry https://registry.npmjs.com/",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"test": "BABEL_ENV=test jest",
|
||||
"coveralls": "jest --coverage && cat ./tests/coverage/lcov.info | coveralls",
|
||||
"tsc": "tsc",
|
||||
"build:declarations": "lerna exec --stream --no-bail 'tsc --project ./tsconfig.build.json'",
|
||||
"watch": "yarn clean && lerna exec --parallel 'BABEL_ENV=cjs babel --watch src --root-mode upward --out-dir lib --source-maps --extensions .ts,.tsx --delete-dir-on-start --no-comments'",
|
||||
"bundle": "BABEL_ENV=bundle node_modules/.bin/rollup -c ./build/rollup.config.js",
|
||||
"bundle:watch": "BABEL_ENV=bundle node_modules/.bin/rollup -c ./build/rollup.config.js --watch",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@l7/component",
|
||||
"version": "0.0.1",
|
||||
"name": "@antv/l7-component",
|
||||
"version": "2.0.0-beta.10",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -24,13 +24,14 @@
|
|||
"author": "lzxue",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@l7/core": "0.0.1",
|
||||
"@l7/utils": "0.0.1",
|
||||
"@antv/l7-core": "^2.0.0-beta.10",
|
||||
"@antv/l7-utils": "^2.0.0-beta.10",
|
||||
"@turf/distance": "^6.0.1",
|
||||
"eventemitter3": "^4.0.0",
|
||||
"inversify": "^5.0.1",
|
||||
"inversify-inject-decorators": "^3.1.0",
|
||||
"inversify-logging": "^0.2.1"
|
||||
"inversify-logging": "^0.2.1",
|
||||
"load-styles": "^2.0.0"
|
||||
},
|
||||
"gitHead": "0563f357f3a07c099bf1ffa9350e6fa3c88353ae",
|
||||
"publishConfig": {
|
||||
|
|
|
@ -3,11 +3,11 @@ import {
|
|||
ILayerService,
|
||||
IMapService,
|
||||
IRendererService,
|
||||
lazyInject,
|
||||
TYPES,
|
||||
} from '@l7/core';
|
||||
import { DOM } from '@l7/utils';
|
||||
} from '@antv/l7-core';
|
||||
import { DOM } from '@antv/l7-utils';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { Container } from 'inversify';
|
||||
|
||||
export enum PositionType {
|
||||
'TOPRIGHT' = 'topright',
|
||||
|
@ -26,15 +26,11 @@ export interface IControlOption {
|
|||
}
|
||||
export default class Control extends EventEmitter {
|
||||
public controlOption: IControlOption;
|
||||
protected mapsService: IMapService;
|
||||
protected container: HTMLElement;
|
||||
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly renderService: IRendererService;
|
||||
@lazyInject(TYPES.ILayerService)
|
||||
protected readonly layerService: ILayerService;
|
||||
@lazyInject(TYPES.IControlService)
|
||||
private readonly controlService: IControlService;
|
||||
protected mapsService: IMapService;
|
||||
protected renderService: IRendererService;
|
||||
protected layerService: ILayerService;
|
||||
protected controlService: IControlService;
|
||||
|
||||
private isShow: boolean;
|
||||
|
||||
|
@ -45,27 +41,36 @@ export default class Control extends EventEmitter {
|
|||
...(cfg || {}),
|
||||
};
|
||||
}
|
||||
|
||||
public getDefault() {
|
||||
return {
|
||||
position: PositionType.TOPRIGHT,
|
||||
};
|
||||
}
|
||||
public setPosition(position: PositionName) {
|
||||
const controlService = this.controlService;
|
||||
if (controlService) {
|
||||
controlService.removeControl(this);
|
||||
}
|
||||
this.controlOption.position = position;
|
||||
if (controlService) {
|
||||
controlService.addControl(this, this.mapsService);
|
||||
}
|
||||
// FIXME: 只是改变位置不需要销毁再重建吧
|
||||
// const controlService = this.controlService;
|
||||
// if (controlService) {
|
||||
// controlService.removeControl(this);
|
||||
// }
|
||||
// this.controlOption.position = position;
|
||||
// if (controlService) {
|
||||
// controlService.addControl(this, this.mapsService);
|
||||
// }
|
||||
return this;
|
||||
}
|
||||
public addTo(mapService: IMapService) {
|
||||
this.remove();
|
||||
public addTo(sceneContainer: Container) {
|
||||
this.mapsService = sceneContainer.get<IMapService>(TYPES.IMapService);
|
||||
this.renderService = sceneContainer.get<IRendererService>(
|
||||
TYPES.IRendererService,
|
||||
);
|
||||
this.layerService = sceneContainer.get<ILayerService>(TYPES.ILayerService);
|
||||
this.controlService = sceneContainer.get<IControlService>(
|
||||
TYPES.IControlService,
|
||||
);
|
||||
|
||||
this.isShow = true;
|
||||
this.mapsService = mapService;
|
||||
this.container = this.onAdd(mapService);
|
||||
this.container = this.onAdd();
|
||||
const container = this.container;
|
||||
const pos = this.controlOption.position;
|
||||
const corner = this.controlService.controlCorners[pos];
|
||||
|
@ -78,7 +83,7 @@ export default class Control extends EventEmitter {
|
|||
}
|
||||
return this;
|
||||
}
|
||||
public onAdd(Map: IMapService): HTMLElement {
|
||||
public onAdd(): HTMLElement {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
public hide() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { IMapService } from '@l7/core';
|
||||
import { bindAll, DOM, lnglatDistance } from '@l7/utils';
|
||||
import { IMapService } from '@antv/l7-core';
|
||||
import { bindAll, DOM, lnglatDistance } from '@antv/l7-utils';
|
||||
import Control, {
|
||||
IControlOption,
|
||||
PositionName,
|
||||
|
@ -63,7 +63,7 @@ export default class Layers extends Control {
|
|||
sortLayers: false,
|
||||
};
|
||||
}
|
||||
public onAdd(MapService: IMapService) {
|
||||
public onAdd() {
|
||||
this.initLayout();
|
||||
this.update();
|
||||
this.mapsService.on('zoomend', this.checkDisabledLayers);
|
||||
|
@ -177,7 +177,7 @@ export default class Layers extends Control {
|
|||
input = inputs[i];
|
||||
layer = this.layerService.getLayer(input.layerId);
|
||||
if (layer) {
|
||||
input.disabled = layer.visible && !layer.isVisible();
|
||||
input.disabled = !layer.isVisible();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { IMapService } from '@l7/core';
|
||||
import { bindAll, DOM } from '@l7/utils';
|
||||
import Control, { IControlOption, PositionType } from './BaseControl';
|
||||
import { DOM } from '@antv/l7-utils';
|
||||
import Control, { PositionType } from './BaseControl';
|
||||
export default class Logo extends Control {
|
||||
public getDefault() {
|
||||
return {
|
||||
position: PositionType.BOTTOMLEFT,
|
||||
};
|
||||
}
|
||||
public onAdd(MapService: IMapService) {
|
||||
public onAdd() {
|
||||
const className = 'l7-control-logo';
|
||||
const container = DOM.create('div', className);
|
||||
const anchor: HTMLLinkElement = DOM.create(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { IMapService } from '@l7/core';
|
||||
import { bindAll, DOM, lnglatDistance } from '@l7/utils';
|
||||
import { IMapService } from '@antv/l7-core';
|
||||
import { bindAll, DOM, lnglatDistance } from '@antv/l7-utils';
|
||||
import Control, { IControlOption, PositionType } from './BaseControl';
|
||||
export interface IScaleControlOption extends IControlOption {
|
||||
maxWidth: number;
|
||||
|
@ -25,7 +25,7 @@ export default class Scale extends Control {
|
|||
};
|
||||
}
|
||||
|
||||
public onAdd(MapService: IMapService) {
|
||||
public onAdd() {
|
||||
const className = 'l7-control-scale';
|
||||
const container = DOM.create('div', className);
|
||||
this.addScales(className + '-line', container);
|
||||
|
@ -36,7 +36,7 @@ export default class Scale extends Control {
|
|||
|
||||
return container;
|
||||
}
|
||||
public onRemove(MapService: IMapService) {
|
||||
public onRemove() {
|
||||
const { updateWhenIdle } = this.controlOption;
|
||||
this.mapsService.off(updateWhenIdle ? 'moveend' : 'mapmove', this.update);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { IMapService } from '@l7/core';
|
||||
import { bindAll, DOM } from '@l7/utils';
|
||||
import { bindAll, DOM } from '@antv/l7-utils';
|
||||
import Control, { IControlOption, PositionType } from './BaseControl';
|
||||
export interface IZoomControlOption extends IControlOption {
|
||||
zoomInText: string;
|
||||
|
@ -26,7 +25,7 @@ export default class Zoom extends Control {
|
|||
};
|
||||
}
|
||||
|
||||
public onAdd(MapService: IMapService) {
|
||||
public onAdd() {
|
||||
const zoomName = 'l7-control-zoom';
|
||||
const container = DOM.create('div', zoomName + ' l7-bar');
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ILngLat, IMapService, IMarkerScene, IPopup } from '@l7/core';
|
||||
import { bindAll, DOM } from '@l7/utils';
|
||||
import { ILngLat, IMapService, IMarkerScene, IPopup } from '@antv/l7-core';
|
||||
import { bindAll, DOM } from '@antv/l7-utils';
|
||||
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
|
||||
// marker 支持 dragger 未完成
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { ILngLat, IMapService, IMarkerScene, IPopup } from '@l7/core';
|
||||
import { bindAll, DOM } from '@l7/utils';
|
||||
import { ILngLat, IMapService, IMarkerScene, IPopup } from '@antv/l7-core';
|
||||
import { bindAll, DOM } from '@antv/l7-utils';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { anchorTranslate, anchorType, applyAnchorClass } from './utils/anchor';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@l7/core",
|
||||
"version": "0.0.1",
|
||||
"name": "@antv/l7-core",
|
||||
"version": "2.0.0-beta.10",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
|
@ -22,7 +22,7 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@l7/utils": "0.0.1",
|
||||
"@antv/l7-utils": "^2.0.0-beta.10",
|
||||
"@mapbox/tiny-sdf": "^1.1.1",
|
||||
"ajv": "^6.10.2",
|
||||
"eventemitter3": "^4.0.0",
|
||||
|
@ -39,6 +39,7 @@
|
|||
"viewport-mercator-project": "^6.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/amap-js-api": "^1.4.6",
|
||||
"@types/gl-matrix": "^2.4.5",
|
||||
"@types/hammerjs": "^2.0.36",
|
||||
"@types/lodash": "^4.14.138",
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import container, { lazyInject, lazyMultiInject } from './inversify.config';
|
||||
import ClearPass from './services/renderer/passes/ClearPass';
|
||||
import MultiPassRenderer from './services/renderer/passes/MultiPassRenderer';
|
||||
import PixelPickingPass from './services/renderer/passes/PixelPickingPass';
|
||||
import RenderPass from './services/renderer/passes/RenderPass';
|
||||
import TAAPass from './services/renderer/passes/TAAPass';
|
||||
import container, {
|
||||
createLayerContainer,
|
||||
createSceneContainer,
|
||||
lazyInject,
|
||||
lazyMultiInject,
|
||||
} from './inversify.config';
|
||||
import BasePostProcessingPass from './services/renderer/passes/BasePostProcessingPass';
|
||||
import { TYPES } from './types';
|
||||
import { packCircleVertex } from './utils/vertex-compression';
|
||||
|
||||
|
@ -12,6 +13,8 @@ export {
|
|||
* IoC 容器
|
||||
*/
|
||||
container,
|
||||
createSceneContainer,
|
||||
createLayerContainer,
|
||||
/**
|
||||
* lazy inject,供各个 Layer 使用
|
||||
*/
|
||||
|
@ -22,12 +25,7 @@ export {
|
|||
*/
|
||||
TYPES,
|
||||
packCircleVertex,
|
||||
/** pass */
|
||||
MultiPassRenderer,
|
||||
ClearPass,
|
||||
RenderPass,
|
||||
PixelPickingPass,
|
||||
TAAPass,
|
||||
BasePostProcessingPass,
|
||||
};
|
||||
|
||||
/** 暴露服务接口供其他 packages 实现 */
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* Root Container
|
||||
* @see /dev-docs/IoC 容器、依赖注入与服务说明.md
|
||||
*/
|
||||
import 'reflect-metadata';
|
||||
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
|
@ -34,7 +38,15 @@ import SceneService from './services/scene/SceneService';
|
|||
import ShaderModuleService from './services/shader/ShaderModuleService';
|
||||
|
||||
/** PostProcessing passes */
|
||||
import { IPostProcessingPass } from './services/renderer/IMultiPassRenderer';
|
||||
import {
|
||||
IMultiPassRenderer,
|
||||
IPass,
|
||||
IPostProcessingPass,
|
||||
IPostProcessor,
|
||||
} from './services/renderer/IMultiPassRenderer';
|
||||
import ClearPass from './services/renderer/passes/ClearPass';
|
||||
import MultiPassRenderer from './services/renderer/passes/MultiPassRenderer';
|
||||
import PixelPickingPass from './services/renderer/passes/PixelPickingPass';
|
||||
import BlurHPass from './services/renderer/passes/post-processing/BlurHPass';
|
||||
import BlurVPass from './services/renderer/passes/post-processing/BlurVPass';
|
||||
import ColorHalfTonePass from './services/renderer/passes/post-processing/ColorHalfTonePass';
|
||||
|
@ -43,37 +55,20 @@ import HexagonalPixelatePass from './services/renderer/passes/post-processing/He
|
|||
import InkPass from './services/renderer/passes/post-processing/InkPass';
|
||||
import NoisePass from './services/renderer/passes/post-processing/NoisePass';
|
||||
import SepiaPass from './services/renderer/passes/post-processing/SepiaPass';
|
||||
import PostProcessor from './services/renderer/passes/PostProcessor';
|
||||
import RenderPass from './services/renderer/passes/RenderPass';
|
||||
import TAAPass from './services/renderer/passes/TAAPass';
|
||||
|
||||
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/container_api.md#defaultscope
|
||||
const container = new Container();
|
||||
|
||||
/**
|
||||
* bind services
|
||||
* bind global services in root container
|
||||
*/
|
||||
container
|
||||
.bind<ISceneService>(TYPES.ISceneService)
|
||||
.to(SceneService)
|
||||
.inTransientScope();
|
||||
container
|
||||
.bind<IGlobalConfigService>(TYPES.IGlobalConfigService)
|
||||
.to(GlobalConfigService)
|
||||
.inSingletonScope();
|
||||
container
|
||||
.bind<ILayerService>(TYPES.ILayerService)
|
||||
.to(LayerService)
|
||||
.inSingletonScope();
|
||||
container
|
||||
.bind<IStyleAttributeService>(TYPES.IStyleAttributeService)
|
||||
.to(StyleAttributeService)
|
||||
.inRequestScope();
|
||||
container
|
||||
.bind<ICameraService>(TYPES.ICameraService)
|
||||
.to(CameraService)
|
||||
.inSingletonScope();
|
||||
container
|
||||
.bind<ICoordinateSystemService>(TYPES.ICoordinateSystemService)
|
||||
.to(CoordinateSystemService)
|
||||
.inSingletonScope();
|
||||
container
|
||||
.bind<IIconService>(TYPES.IIconService)
|
||||
.to(IconService)
|
||||
|
@ -86,18 +81,10 @@ container
|
|||
.bind<ILogService>(TYPES.ILogService)
|
||||
.to(LogService)
|
||||
.inSingletonScope();
|
||||
container
|
||||
.bind<IInteractionService>(TYPES.IInteractionService)
|
||||
.to(InteractionService)
|
||||
.inSingletonScope();
|
||||
container
|
||||
.bind<IFontService>(TYPES.IFontService)
|
||||
.to(FontService)
|
||||
.inSingletonScope();
|
||||
container
|
||||
.bind<IControlService>(TYPES.IControlService)
|
||||
.to(ControlService)
|
||||
.inSingletonScope();
|
||||
|
||||
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/inheritance.md#what-can-i-do-when-my-base-class-is-provided-by-a-third-party-module
|
||||
decorate(injectable(), EventEmitter);
|
||||
|
@ -157,49 +144,134 @@ export const lazyMultiInject = (
|
|||
};
|
||||
};
|
||||
|
||||
export default container;
|
||||
|
||||
let sceneIdCounter = 0;
|
||||
export function createSceneContainer() {
|
||||
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/hierarchical_di.md#support-for-hierarchical-di-systems
|
||||
const sceneContainer = new Container();
|
||||
sceneContainer.parent = container;
|
||||
|
||||
// 生成场景 ID 并保存在容器内
|
||||
sceneContainer
|
||||
.bind<string>(TYPES.SceneID)
|
||||
.toConstantValue(`${sceneIdCounter++}`);
|
||||
|
||||
sceneContainer
|
||||
.bind<ILayerService>(TYPES.ILayerService)
|
||||
.to(LayerService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<ISceneService>(TYPES.ISceneService)
|
||||
.to(SceneService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<ICameraService>(TYPES.ICameraService)
|
||||
.to(CameraService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<ICoordinateSystemService>(TYPES.ICoordinateSystemService)
|
||||
.to(CoordinateSystemService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<IInteractionService>(TYPES.IInteractionService)
|
||||
.to(InteractionService)
|
||||
.inSingletonScope();
|
||||
sceneContainer
|
||||
.bind<IControlService>(TYPES.IControlService)
|
||||
.to(ControlService)
|
||||
.inSingletonScope();
|
||||
|
||||
// 绑定常规 passes
|
||||
sceneContainer
|
||||
.bind<IPass<unknown>>(TYPES.INormalPass)
|
||||
.to(ClearPass)
|
||||
.whenTargetNamed('clear');
|
||||
sceneContainer
|
||||
.bind<IPass<unknown>>(TYPES.INormalPass)
|
||||
.to(PixelPickingPass)
|
||||
.whenTargetNamed('pixelPicking');
|
||||
sceneContainer
|
||||
.bind<IPass<unknown>>(TYPES.INormalPass)
|
||||
.to(RenderPass)
|
||||
.whenTargetNamed('render');
|
||||
sceneContainer
|
||||
.bind<IPass<unknown>>(TYPES.INormalPass)
|
||||
.to(TAAPass)
|
||||
.whenTargetNamed('taa');
|
||||
sceneContainer
|
||||
.bind<interfaces.Factory<IPass<unknown>>>(TYPES.IFactoryNormalPass)
|
||||
.toFactory<IPass<unknown>>((context) => (named: string) =>
|
||||
context.container.getNamed<IPass<unknown>>(TYPES.INormalPass, named),
|
||||
);
|
||||
|
||||
// 绑定 post processing passes
|
||||
container
|
||||
sceneContainer
|
||||
.bind<IPostProcessingPass<unknown>>(TYPES.IPostProcessingPass)
|
||||
.to(CopyPass)
|
||||
.whenTargetNamed('copy');
|
||||
container
|
||||
sceneContainer
|
||||
.bind<IPostProcessingPass<unknown>>(TYPES.IPostProcessingPass)
|
||||
.to(BlurHPass)
|
||||
.whenTargetNamed('blurH');
|
||||
container
|
||||
sceneContainer
|
||||
.bind<IPostProcessingPass<unknown>>(TYPES.IPostProcessingPass)
|
||||
.to(BlurVPass)
|
||||
.whenTargetNamed('blurV');
|
||||
container
|
||||
sceneContainer
|
||||
.bind<IPostProcessingPass<unknown>>(TYPES.IPostProcessingPass)
|
||||
.to(NoisePass)
|
||||
.whenTargetNamed('noise');
|
||||
container
|
||||
sceneContainer
|
||||
.bind<IPostProcessingPass<unknown>>(TYPES.IPostProcessingPass)
|
||||
.to(SepiaPass)
|
||||
.whenTargetNamed('sepia');
|
||||
container
|
||||
sceneContainer
|
||||
.bind<IPostProcessingPass<unknown>>(TYPES.IPostProcessingPass)
|
||||
.to(ColorHalfTonePass)
|
||||
.whenTargetNamed('colorHalftone');
|
||||
container
|
||||
sceneContainer
|
||||
.bind<IPostProcessingPass<unknown>>(TYPES.IPostProcessingPass)
|
||||
.to(HexagonalPixelatePass)
|
||||
.whenTargetNamed('hexagonalPixelate');
|
||||
container
|
||||
sceneContainer
|
||||
.bind<IPostProcessingPass<unknown>>(TYPES.IPostProcessingPass)
|
||||
.to(InkPass)
|
||||
.whenTargetNamed('ink');
|
||||
|
||||
container
|
||||
// 绑定工厂方法
|
||||
sceneContainer
|
||||
.bind<interfaces.Factory<IPostProcessingPass<unknown>>>(
|
||||
TYPES.IFactoryPostProcessingPass,
|
||||
)
|
||||
.toFactory<IPostProcessingPass<unknown>>((context) => (named: string) =>
|
||||
context.container.getNamed<IPostProcessingPass<unknown>>(
|
||||
.toFactory<IPostProcessingPass<unknown>>((context) => (named: string) => {
|
||||
const pass = context.container.getNamed<IPostProcessingPass<unknown>>(
|
||||
TYPES.IPostProcessingPass,
|
||||
named,
|
||||
),
|
||||
);
|
||||
pass.setName(named);
|
||||
return pass;
|
||||
});
|
||||
|
||||
export default container;
|
||||
return sceneContainer;
|
||||
}
|
||||
|
||||
export function createLayerContainer(sceneContainer: Container) {
|
||||
const layerContainer = new Container();
|
||||
layerContainer.parent = sceneContainer;
|
||||
|
||||
layerContainer
|
||||
.bind<IStyleAttributeService>(TYPES.IStyleAttributeService)
|
||||
.to(StyleAttributeService)
|
||||
.inSingletonScope();
|
||||
layerContainer
|
||||
.bind<IMultiPassRenderer>(TYPES.IMultiPassRenderer)
|
||||
.to(MultiPassRenderer)
|
||||
.inSingletonScope();
|
||||
layerContainer
|
||||
.bind<IPostProcessor>(TYPES.IPostProcessor)
|
||||
.to(PostProcessor)
|
||||
.inSingletonScope();
|
||||
|
||||
return layerContainer;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { LRUCache } from '@l7/utils';
|
||||
import { LRUCache } from '@antv/l7-utils';
|
||||
// @ts-ignore
|
||||
import TinySDF from '@mapbox/tiny-sdf';
|
||||
import { inject, injectable } from 'inversify';
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { DOM } from '@l7/utils';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { IMapService } from '../map/IMapService';
|
||||
import { DOM } from '@antv/l7-utils';
|
||||
import { Container, injectable } from 'inversify';
|
||||
import {
|
||||
IControl,
|
||||
IControlCorners,
|
||||
|
@ -15,13 +14,12 @@ export default class ControlService implements IControlService {
|
|||
public controlContainer: HTMLElement;
|
||||
private controls: IControl[] = [];
|
||||
public init(cfg: IControlServiceCfg) {
|
||||
this.destroy();
|
||||
this.container = cfg.container;
|
||||
this.initControlPos();
|
||||
}
|
||||
|
||||
public addControl(ctr: IControl, mapService: IMapService): void {
|
||||
ctr.addTo(mapService); // scene对象
|
||||
public addControl(ctr: IControl, sceneContainer: Container): void {
|
||||
ctr.addTo(sceneContainer); // scene对象
|
||||
this.controls.push(ctr);
|
||||
}
|
||||
public removeControl(ctr: IControl): this {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IMapService } from '../map/IMapService';
|
||||
import { Container } from 'inversify';
|
||||
export enum PositionType {
|
||||
'TOPRIGHT' = 'topright',
|
||||
'TOPLEFT' = 'topleft',
|
||||
|
@ -16,8 +16,8 @@ export interface IControlCorners {
|
|||
}
|
||||
export interface IControl {
|
||||
setPosition(pos: PositionType): void;
|
||||
addTo(map: IMapService): void;
|
||||
onAdd(map: IMapService): HTMLElement;
|
||||
addTo(sceneContainer: Container): void;
|
||||
onAdd(): HTMLElement;
|
||||
hide(): void;
|
||||
show(): void;
|
||||
remove(): void;
|
||||
|
@ -27,7 +27,7 @@ export interface IControlService {
|
|||
controlCorners: IControlCorners;
|
||||
controlContainer: HTMLElement;
|
||||
init(cfg: IControlServiceCfg): void;
|
||||
addControl(ctr: IControl, map: IMapService): void;
|
||||
addControl(ctr: IControl, sceneContainer: Container): void;
|
||||
removeControl(ctr: IControl): void;
|
||||
destroy(): void;
|
||||
}
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
import Ajv from 'ajv';
|
||||
import { injectable } from 'inversify';
|
||||
import { IGlobalConfig, IGlobalConfigService } from './IConfigService';
|
||||
import { injectable, postConstruct } from 'inversify';
|
||||
import { ILayerConfig } from '../layer/ILayerService';
|
||||
import { IGlobalConfigService, ISceneConfig } from './IConfigService';
|
||||
import sceneConfigSchema from './sceneConfigSchema';
|
||||
|
||||
const defaultGlobalConfig: Partial<IGlobalConfig> = {
|
||||
/**
|
||||
* 场景默认配置项
|
||||
*/
|
||||
const defaultSceneConfig: Partial<ISceneConfig> = {
|
||||
type: 'amap',
|
||||
zoom: 5,
|
||||
center: [107.622, 39.266],
|
||||
pitch: 0,
|
||||
// minZoom: 3,
|
||||
// maxZoom: 18,
|
||||
};
|
||||
|
||||
/**
|
||||
* 图层基类默认样式属性
|
||||
*/
|
||||
const defaultLayerConfig: Partial<ILayerConfig> = {
|
||||
colors: [
|
||||
'rgb(103,0,31)',
|
||||
'rgb(178,24,43)',
|
||||
|
@ -37,6 +46,17 @@ const defaultGlobalConfig: Partial<IGlobalConfig> = {
|
|||
'vesica',
|
||||
],
|
||||
shape3d: ['cylinder', 'triangleColumn', 'hexagonColumn', 'squareColumn'],
|
||||
minZoom: 0,
|
||||
maxZoom: 20,
|
||||
visible: true,
|
||||
zIndex: 0,
|
||||
enableMultiPassRenderer: true,
|
||||
enablePicking: false,
|
||||
enableHighlight: false,
|
||||
highlightColor: 'red',
|
||||
enableTAA: false,
|
||||
jitterScale: 1,
|
||||
enableLighting: false,
|
||||
};
|
||||
|
||||
// @see https://github.com/epoberezkin/ajv#options
|
||||
|
@ -47,31 +67,65 @@ const ajv = new Ajv({
|
|||
|
||||
@injectable()
|
||||
export default class GlobalConfigService implements IGlobalConfigService {
|
||||
private config: Partial<IGlobalConfig> = defaultGlobalConfig;
|
||||
/**
|
||||
* 全部场景配置项缓存
|
||||
*/
|
||||
private sceneConfigCache: {
|
||||
[sceneId: string]: Partial<ISceneConfig>;
|
||||
} = {};
|
||||
|
||||
/**
|
||||
* 保存每个 Layer 配置项的校验器
|
||||
* 场景配置项校验器
|
||||
*/
|
||||
private sceneConfigValidator: Ajv.ValidateFunction;
|
||||
|
||||
/**
|
||||
* 全部图层配置项缓存
|
||||
*/
|
||||
private layerConfigCache: {
|
||||
[layerId: string]: Partial<ILayerConfig & ISceneConfig>;
|
||||
} = {};
|
||||
|
||||
/**
|
||||
* 保存每一种 Layer 配置项的校验器
|
||||
*/
|
||||
private layerConfigValidatorCache: {
|
||||
[layerName: string]: Ajv.ValidateFunction;
|
||||
} = {};
|
||||
|
||||
public getConfig() {
|
||||
return this.config;
|
||||
public getSceneConfig(sceneId: string) {
|
||||
return this.sceneConfigCache[sceneId];
|
||||
}
|
||||
|
||||
public setAndCheckConfig(config: Partial<IGlobalConfig>) {
|
||||
this.config = {
|
||||
...this.config,
|
||||
public setSceneConfig(sceneId: string, config: Partial<ISceneConfig>) {
|
||||
this.sceneConfigCache[sceneId] = {
|
||||
...defaultSceneConfig,
|
||||
...config,
|
||||
};
|
||||
// TODO: validate config with JSON schema
|
||||
// @see https://github.com/webpack/schema-utils
|
||||
return true;
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this.config = defaultGlobalConfig;
|
||||
public validateSceneConfig(data: object) {
|
||||
return this.validate(this.sceneConfigValidator, data);
|
||||
}
|
||||
|
||||
public getLayerConfig<IChildLayerConfig>(
|
||||
layerId: string,
|
||||
): Partial<ILayerConfig & ISceneConfig & IChildLayerConfig> {
|
||||
// @ts-ignore
|
||||
return this.layerConfigCache[layerId];
|
||||
}
|
||||
|
||||
public setLayerConfig(
|
||||
sceneId: string,
|
||||
layerId: string,
|
||||
config: Partial<ILayerConfig>,
|
||||
) {
|
||||
// @ts-ignore
|
||||
this.layerConfigCache[layerId] = {
|
||||
...this.sceneConfigCache[sceneId],
|
||||
...defaultLayerConfig,
|
||||
...config,
|
||||
};
|
||||
}
|
||||
|
||||
public registerLayerConfigSchemaValidator(layerName: string, schema: object) {
|
||||
|
@ -81,14 +135,30 @@ export default class GlobalConfigService implements IGlobalConfigService {
|
|||
}
|
||||
|
||||
public validateLayerConfig(layerName: string, data: object) {
|
||||
const validate = this.layerConfigValidatorCache[layerName];
|
||||
if (validate) {
|
||||
const valid = validate(data);
|
||||
return this.validate(this.layerConfigValidatorCache[layerName], data);
|
||||
}
|
||||
|
||||
public clean() {
|
||||
this.sceneConfigCache = {};
|
||||
this.layerConfigCache = {};
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
private registerSceneConfigSchemaValidator() {
|
||||
this.sceneConfigValidator = ajv.compile(sceneConfigSchema);
|
||||
}
|
||||
|
||||
private validate(
|
||||
validateFunc: Ajv.ValidateFunction | undefined,
|
||||
data: object,
|
||||
) {
|
||||
if (validateFunc) {
|
||||
const valid = validateFunc(data);
|
||||
if (!valid) {
|
||||
return {
|
||||
valid,
|
||||
errors: validate.errors,
|
||||
errorText: ajv.errorsText(validate.errors),
|
||||
errors: validateFunc.errors,
|
||||
errorText: ajv.errorsText(validateFunc.errors),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,65 @@
|
|||
import Ajv from 'ajv';
|
||||
import { ILayerGlobalConfig } from '../layer/ILayerService';
|
||||
import { ILayerConfig } from '../layer/ILayerService';
|
||||
import { IMapConfig } from '../map/IMapService';
|
||||
import { IRenderConfig } from '../renderer/IRendererService';
|
||||
|
||||
export type IGlobalConfig = IMapConfig & IRenderConfig & ILayerGlobalConfig;
|
||||
export type ISceneConfig = IMapConfig & IRenderConfig;
|
||||
|
||||
export interface IGlobalConfigService {
|
||||
getConfig(): Partial<IGlobalConfig>;
|
||||
setAndCheckConfig(config: Partial<IGlobalConfig>): boolean;
|
||||
reset(): void;
|
||||
registerLayerConfigSchemaValidator(layerName: string, schema: object): void;
|
||||
validateLayerConfig(
|
||||
layerName: string,
|
||||
data: object,
|
||||
): {
|
||||
interface IValidateResult {
|
||||
valid: boolean;
|
||||
errors: Ajv.ErrorObject[] | null | undefined;
|
||||
errorText: string | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IGlobalConfigService {
|
||||
/**
|
||||
* 获取场景配置项
|
||||
* @param sceneId 场景 ID
|
||||
*/
|
||||
getSceneConfig(sceneId: string): Partial<ISceneConfig>;
|
||||
setSceneConfig(sceneId: string, config: Partial<ISceneConfig>): void;
|
||||
|
||||
/**
|
||||
* 校验用户传入的场景配置项
|
||||
* @param data 场景配置项
|
||||
*/
|
||||
validateSceneConfig(data: object): IValidateResult;
|
||||
|
||||
/**
|
||||
* 获取图层配置项
|
||||
* @param layerId 图层 ID
|
||||
*/
|
||||
getLayerConfig<IChildLayerConfig>(
|
||||
layerId: string,
|
||||
): Partial<ILayerConfig & ISceneConfig & IChildLayerConfig>;
|
||||
|
||||
/**
|
||||
* 设置图层配置项,继承所属场景配置项
|
||||
* @param sceneId 场景 ID
|
||||
* @param layerId 图层 ID
|
||||
* @param config 图层配置项
|
||||
*/
|
||||
setLayerConfig(
|
||||
sceneId: string,
|
||||
layerId: string,
|
||||
config: Partial<ILayerConfig>,
|
||||
): void;
|
||||
|
||||
/**
|
||||
* 注册一个图层的配置项校验器
|
||||
* @param layerName 图层名
|
||||
* @param schema 校验规则描述
|
||||
*/
|
||||
registerLayerConfigSchemaValidator(layerName: string, schema: object): void;
|
||||
|
||||
/**
|
||||
* 校验用户传入的图层配置项
|
||||
* @param data 图层配置项
|
||||
*/
|
||||
validateLayerConfig(layerName: string, data: object): IValidateResult;
|
||||
|
||||
/**
|
||||
* 清除场景和图层配置项 Cache,但是需要保留校验器
|
||||
*/
|
||||
clean(): void;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import { MapType } from '../map/IMapService';
|
||||
|
||||
/**
|
||||
* 场景 Schema
|
||||
*/
|
||||
export default {
|
||||
properties: {
|
||||
// 地图容器 ID
|
||||
id: {
|
||||
type: 'string',
|
||||
},
|
||||
// 地图类型,目前支持高德 & Mapbox
|
||||
type: {
|
||||
enum: [MapType.amap, MapType.mapbox],
|
||||
},
|
||||
// 地图缩放等级
|
||||
zoom: {
|
||||
type: 'number',
|
||||
minimum: 0,
|
||||
maximum: 20,
|
||||
},
|
||||
// 地图中心点
|
||||
center: {
|
||||
item: {
|
||||
type: 'number',
|
||||
},
|
||||
maxItems: 2,
|
||||
minItems: 2,
|
||||
},
|
||||
// 仰角
|
||||
pitch: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
};
|
|
@ -23,7 +23,6 @@ export default class InteractionService extends EventEmitter
|
|||
|
||||
public init() {
|
||||
// 注册事件在地图底图上
|
||||
this.clear();
|
||||
this.addEventListenerOnMap();
|
||||
}
|
||||
|
||||
|
@ -55,7 +54,7 @@ export default class InteractionService extends EventEmitter
|
|||
this.hammertime = hammertime;
|
||||
|
||||
// TODO: 根据场景注册事件到 L7 canvas 上
|
||||
this.logger.info('add event listeners on canvas');
|
||||
this.logger.debug('add event listeners on canvas');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,13 +66,12 @@ export default class InteractionService extends EventEmitter
|
|||
}
|
||||
|
||||
private onHover = ({ x, y }: MouseEvent) => {
|
||||
const $containter = this.mapService.getMapContainer();
|
||||
if ($containter) {
|
||||
const { top, left } = $containter.getBoundingClientRect();
|
||||
x -= left;
|
||||
y -= top;
|
||||
}
|
||||
this.emit(InteractionEvent.Hover, { x, y });
|
||||
};
|
||||
private clear() {
|
||||
if (this.hammertime) {
|
||||
this.hammertime.destroy();
|
||||
}
|
||||
this.removeEventListenerOnMap();
|
||||
this.off(InteractionEvent.Hover);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,15 @@
|
|||
import { Container } from 'inversify';
|
||||
import { SyncBailHook, SyncHook } from 'tapable';
|
||||
import Clock from '../../utils/clock';
|
||||
import { IGlobalConfigService } from '../config/IConfigService';
|
||||
import { ISceneConfig } from '../config/IConfigService';
|
||||
import { IMapService } from '../map/IMapService';
|
||||
import { IModel, IModelInitializationOptions } from '../renderer/IModel';
|
||||
import { IMultiPassRenderer } from '../renderer/IMultiPassRenderer';
|
||||
import {
|
||||
IMultiPassRenderer,
|
||||
IPass,
|
||||
IPostProcessingPass,
|
||||
} from '../renderer/IMultiPassRenderer';
|
||||
import { IRendererService } from '../renderer/IRendererService';
|
||||
import { IUniform } from '../renderer/IUniform';
|
||||
import { ISource, ISourceCFG } from '../source/ISourceService';
|
||||
import {
|
||||
|
@ -16,16 +23,6 @@ import {
|
|||
Triangulation,
|
||||
} from './IStyleAttributeService';
|
||||
|
||||
export interface ILayerGlobalConfig {
|
||||
colors: string[];
|
||||
size: number;
|
||||
shape: string;
|
||||
shape2d: string[];
|
||||
shape3d: string[];
|
||||
scales: {
|
||||
[key: string]: IScale;
|
||||
};
|
||||
}
|
||||
export interface ILayerModelInitializationOptions {
|
||||
moduleName: string;
|
||||
vertexShader: string;
|
||||
|
@ -52,11 +49,7 @@ export interface ILayer {
|
|||
id: string; // 一个场景中同一类型 Layer 可能存在多个
|
||||
name: string; // 代表 Layer 的类型
|
||||
inited: boolean; // 是否初始化完成
|
||||
visible: boolean;
|
||||
zIndex: number;
|
||||
minZoom: number;
|
||||
maxZoom: number;
|
||||
configService: IGlobalConfigService;
|
||||
plugins: ILayerPlugin[];
|
||||
hooks: {
|
||||
init: SyncBailHook<void, boolean | void>;
|
||||
|
@ -75,7 +68,9 @@ export interface ILayer {
|
|||
options?: ISourceCFG;
|
||||
};
|
||||
multiPassRenderer: IMultiPassRenderer;
|
||||
styleAttributeService: IStyleAttributeService;
|
||||
getLayerConfig(): Partial<ILayerConfig & ISceneConfig>;
|
||||
getContainer(): Container;
|
||||
setContainer(container: Container): void;
|
||||
buildLayerModel(
|
||||
options: ILayerModelInitializationOptions &
|
||||
Partial<IModelInitializationOptions>,
|
||||
|
@ -100,12 +95,15 @@ export interface ILayer {
|
|||
render(): ILayer;
|
||||
destroy(): void;
|
||||
source(data: any, option?: ISourceCFG): ILayer;
|
||||
/**
|
||||
* 向当前图层注册插件
|
||||
* @param plugin 插件实例
|
||||
*/
|
||||
addPlugin(plugin: ILayerPlugin): ILayer;
|
||||
getSource(): ISource;
|
||||
setSource(source: ISource): void;
|
||||
setEncodedData(encodedData: IEncodeFeature[]): void;
|
||||
getEncodedData(): IEncodeFeature[];
|
||||
getStyleOptions(): Partial<ILayerInitializationOptions>;
|
||||
getScaleOptions(): IScaleOptions;
|
||||
/**
|
||||
* 事件
|
||||
|
@ -128,13 +126,30 @@ export interface ILayer {
|
|||
* Layer 插件
|
||||
*/
|
||||
export interface ILayerPlugin {
|
||||
apply(layer: ILayer): void;
|
||||
apply(
|
||||
layer: ILayer,
|
||||
services: {
|
||||
rendererService: IRendererService;
|
||||
mapService: IMapService;
|
||||
styleAttributeService: IStyleAttributeService;
|
||||
postProcessingPassFactory: (name: string) => IPostProcessingPass<unknown>;
|
||||
normalPassFactory: (name: string) => IPass<unknown>;
|
||||
},
|
||||
): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Layer 初始化参数
|
||||
*/
|
||||
export interface ILayerInitializationOptions {
|
||||
export interface ILayerConfig {
|
||||
colors: string[];
|
||||
size: number;
|
||||
shape: string;
|
||||
shape2d: string[];
|
||||
shape3d: string[];
|
||||
scales: {
|
||||
[key: string]: IScale;
|
||||
};
|
||||
minZoom: number;
|
||||
maxZoom: number;
|
||||
visible: boolean;
|
||||
|
@ -162,6 +177,10 @@ export interface ILayerInitializationOptions {
|
|||
* 相机抖动程度
|
||||
*/
|
||||
jitterScale: number;
|
||||
/**
|
||||
* 开启光照
|
||||
*/
|
||||
enableLighting: boolean;
|
||||
onHover(pickedFeature: IPickedFeature): void;
|
||||
onClick(pickedFeature: IPickedFeature): void;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { container, ILayer } from '../..';
|
||||
import { ILayer } from '../..';
|
||||
import { TYPES } from '../../types';
|
||||
import Clock from '../../utils/clock';
|
||||
import { IGlobalConfigService } from '../config/IConfigService';
|
||||
|
@ -29,10 +29,6 @@ export default class LayerService implements ILayerService {
|
|||
public initLayers() {
|
||||
this.layers.forEach((layer) => {
|
||||
if (!layer.inited) {
|
||||
// register plugins in every layer
|
||||
for (const plugin of layer.plugins) {
|
||||
plugin.apply(layer);
|
||||
}
|
||||
layer.init();
|
||||
}
|
||||
});
|
||||
|
@ -93,16 +89,11 @@ export default class LayerService implements ILayerService {
|
|||
}
|
||||
}
|
||||
|
||||
private initPlugin(layer: ILayer) {
|
||||
for (const plugin of layer.plugins) {
|
||||
plugin.apply(layer);
|
||||
}
|
||||
}
|
||||
|
||||
private clear() {
|
||||
this.renderService.clear({
|
||||
color: [0, 0, 0, 0],
|
||||
depth: 1,
|
||||
stencil: 0,
|
||||
framebuffer: null,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,4 +2,5 @@ export interface ILogService {
|
|||
error(message: string): void;
|
||||
warn(message: string): void;
|
||||
info(message: string): void;
|
||||
debug(message: string): void;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@ import { injectable } from 'inversify';
|
|||
import { Log } from 'probe.gl';
|
||||
import { ILogService } from './ILogService';
|
||||
|
||||
const Logger = new Log({ id: 'L7' }).enable(false);
|
||||
const Logger = new Log({ id: 'L7' }).enable();
|
||||
// 只输出 debug 级别以上的日志信息
|
||||
Logger.priority = 4;
|
||||
|
||||
@injectable()
|
||||
export default class LogService implements ILogService {
|
||||
|
@ -15,6 +17,10 @@ export default class LogService implements ILogService {
|
|||
}
|
||||
|
||||
public info(message: string): void {
|
||||
Logger.info(message)();
|
||||
Logger.info(3, message)();
|
||||
}
|
||||
|
||||
public debug(message: string): void {
|
||||
Logger.probe(4, message)();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/// <reference types="amap-js-api" />
|
||||
import { Map } from 'mapbox-gl';
|
||||
import { IViewport } from '../camera/ICameraService';
|
||||
export type Point = [number, number];
|
||||
|
|
|
@ -13,6 +13,78 @@ type stencilOp =
|
|||
| gl.INCR_WRAP
|
||||
| gl.DECR_WRAP;
|
||||
|
||||
type BlendingFunctionCombined = Partial<{
|
||||
src:
|
||||
| gl.ZERO
|
||||
| gl.ONE
|
||||
| gl.SRC_COLOR
|
||||
| gl.ONE_MINUS_SRC_COLOR
|
||||
| gl.SRC_ALPHA
|
||||
| gl.ONE_MINUS_SRC_ALPHA
|
||||
| gl.DST_COLOR
|
||||
| gl.ONE_MINUS_DST_COLOR
|
||||
| gl.DST_ALPHA
|
||||
| gl.ONE_MINUS_DST_ALPHA
|
||||
| gl.CONSTANT_COLOR
|
||||
| gl.ONE_MINUS_CONSTANT_COLOR
|
||||
| gl.CONSTANT_ALPHA
|
||||
| gl.ONE_MINUS_CONSTANT_ALPHA
|
||||
| gl.SRC_ALPHA_SATURATE;
|
||||
dst:
|
||||
| gl.ZERO
|
||||
| gl.ONE
|
||||
| gl.SRC_COLOR
|
||||
| gl.ONE_MINUS_SRC_COLOR
|
||||
| gl.SRC_ALPHA
|
||||
| gl.ONE_MINUS_SRC_ALPHA
|
||||
| gl.DST_COLOR
|
||||
| gl.ONE_MINUS_DST_COLOR
|
||||
| gl.DST_ALPHA
|
||||
| gl.ONE_MINUS_DST_ALPHA
|
||||
| gl.CONSTANT_COLOR
|
||||
| gl.ONE_MINUS_CONSTANT_COLOR
|
||||
| gl.CONSTANT_ALPHA
|
||||
| gl.ONE_MINUS_CONSTANT_ALPHA
|
||||
| gl.SRC_ALPHA_SATURATE;
|
||||
}>;
|
||||
|
||||
type BlendingFunctionSeparate = Partial<{
|
||||
srcRGB:
|
||||
| gl.ZERO
|
||||
| gl.ONE
|
||||
| gl.SRC_COLOR
|
||||
| gl.ONE_MINUS_SRC_COLOR
|
||||
| gl.SRC_ALPHA
|
||||
| gl.ONE_MINUS_SRC_ALPHA
|
||||
| gl.DST_COLOR
|
||||
| gl.ONE_MINUS_DST_COLOR
|
||||
| gl.DST_ALPHA
|
||||
| gl.ONE_MINUS_DST_ALPHA
|
||||
| gl.CONSTANT_COLOR
|
||||
| gl.ONE_MINUS_CONSTANT_COLOR
|
||||
| gl.CONSTANT_ALPHA
|
||||
| gl.ONE_MINUS_CONSTANT_ALPHA
|
||||
| gl.SRC_ALPHA_SATURATE;
|
||||
srcAlpha: number;
|
||||
dstRGB:
|
||||
| gl.ZERO
|
||||
| gl.ONE
|
||||
| gl.SRC_COLOR
|
||||
| gl.ONE_MINUS_SRC_COLOR
|
||||
| gl.SRC_ALPHA
|
||||
| gl.ONE_MINUS_SRC_ALPHA
|
||||
| gl.DST_COLOR
|
||||
| gl.ONE_MINUS_DST_COLOR
|
||||
| gl.DST_ALPHA
|
||||
| gl.ONE_MINUS_DST_ALPHA
|
||||
| gl.CONSTANT_COLOR
|
||||
| gl.ONE_MINUS_CONSTANT_COLOR
|
||||
| gl.CONSTANT_ALPHA
|
||||
| gl.ONE_MINUS_CONSTANT_ALPHA
|
||||
| gl.SRC_ALPHA_SATURATE;
|
||||
dstAlpha: number;
|
||||
}>;
|
||||
|
||||
export interface IModelInitializationOptions {
|
||||
/**
|
||||
* Shader 字符串,假设此时已经经过 ShaderLib 处理
|
||||
|
@ -85,42 +157,7 @@ export interface IModelInitializationOptions {
|
|||
// gl.enable(gl.BLEND)
|
||||
enable: boolean;
|
||||
// gl.blendFunc
|
||||
func: Partial<{
|
||||
srcRGB:
|
||||
| gl.ZERO
|
||||
| gl.ONE
|
||||
| gl.SRC_COLOR
|
||||
| gl.ONE_MINUS_SRC_COLOR
|
||||
| gl.SRC_ALPHA
|
||||
| gl.ONE_MINUS_SRC_ALPHA
|
||||
| gl.DST_COLOR
|
||||
| gl.ONE_MINUS_DST_COLOR
|
||||
| gl.DST_ALPHA
|
||||
| gl.ONE_MINUS_DST_ALPHA
|
||||
| gl.CONSTANT_COLOR
|
||||
| gl.ONE_MINUS_CONSTANT_COLOR
|
||||
| gl.CONSTANT_ALPHA
|
||||
| gl.ONE_MINUS_CONSTANT_ALPHA
|
||||
| gl.SRC_ALPHA_SATURATE;
|
||||
srcAlpha: number;
|
||||
dstRGB:
|
||||
| gl.ZERO
|
||||
| gl.ONE
|
||||
| gl.SRC_COLOR
|
||||
| gl.ONE_MINUS_SRC_COLOR
|
||||
| gl.SRC_ALPHA
|
||||
| gl.ONE_MINUS_SRC_ALPHA
|
||||
| gl.DST_COLOR
|
||||
| gl.ONE_MINUS_DST_COLOR
|
||||
| gl.DST_ALPHA
|
||||
| gl.ONE_MINUS_DST_ALPHA
|
||||
| gl.CONSTANT_COLOR
|
||||
| gl.ONE_MINUS_CONSTANT_COLOR
|
||||
| gl.CONSTANT_ALPHA
|
||||
| gl.ONE_MINUS_CONSTANT_ALPHA
|
||||
| gl.SRC_ALPHA_SATURATE;
|
||||
dstAlpha: number;
|
||||
}>;
|
||||
func: BlendingFunctionSeparate;
|
||||
// gl.blendEquation
|
||||
equation: {
|
||||
// TODO: EXT_blend_minmax
|
||||
|
@ -134,7 +171,7 @@ export interface IModelInitializationOptions {
|
|||
/**
|
||||
* stencil
|
||||
*/
|
||||
stencil?: {
|
||||
stencil?: Partial<{
|
||||
// gl.enable(gl.STENCIL_TEST)
|
||||
enable: boolean;
|
||||
// gl.stencilMask
|
||||
|
@ -162,7 +199,7 @@ export interface IModelInitializationOptions {
|
|||
zfail: stencilOp;
|
||||
zpass: stencilOp;
|
||||
};
|
||||
};
|
||||
}>;
|
||||
|
||||
/**
|
||||
* cull
|
||||
|
|
|
@ -26,6 +26,7 @@ export interface IPass<InitializationOptions> {
|
|||
export interface IPostProcessingPass<InitializationOptions>
|
||||
extends IPass<InitializationOptions> {
|
||||
setRenderToScreen(renderToScreen: boolean): void;
|
||||
setName(name: string): void;
|
||||
isEnabled(): boolean;
|
||||
setEnabled(enabled: boolean): void;
|
||||
updateOptions(config: Partial<InitializationOptions>): void;
|
||||
|
@ -49,8 +50,12 @@ export interface IPostProcessor {
|
|||
export interface IMultiPassRenderer {
|
||||
getPostProcessor(): IPostProcessor;
|
||||
resize(viewportWidth: number, viewportHeight: number): void;
|
||||
add<InitializationOptions>(pass: IPass<InitializationOptions>): void;
|
||||
add<InitializationOptions>(
|
||||
pass: IPass<InitializationOptions>,
|
||||
config?: Partial<InitializationOptions>,
|
||||
): void;
|
||||
render(): void;
|
||||
getRenderFlag(): boolean;
|
||||
setRenderFlag(enabled: boolean): void;
|
||||
setLayer(layer: ILayer): void;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
import { IFramebuffer } from './IFramebuffer';
|
||||
import { ITexture2D } from './ITexture2D';
|
||||
|
||||
export type IUniform = number | number[] | boolean | IFramebuffer | ITexture2D;
|
||||
interface IStruct {
|
||||
[structPropName: string]: number | number[] | boolean | IStruct | IStruct[];
|
||||
}
|
||||
|
||||
export type IUniform =
|
||||
| number
|
||||
| number[]
|
||||
| ArrayBufferView
|
||||
| boolean
|
||||
| IFramebuffer
|
||||
| ITexture2D
|
||||
| IStruct;
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { IRendererService, IShaderModuleService } from '../../../index';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ICameraService } from '../../camera/ICameraService';
|
||||
import { IInteractionService } from '../../interaction/IInteractionService';
|
||||
import { ILayer, ILayerService } from '../../layer/ILayerService';
|
||||
import { IPass, PassType } from '../IMultiPassRenderer';
|
||||
|
||||
/**
|
||||
* 常规 Pass 基类
|
||||
*/
|
||||
@injectable()
|
||||
export default class BaseNormalPass<InitializationOptions = {}>
|
||||
implements IPass<InitializationOptions> {
|
||||
@inject(TYPES.IShaderModuleService)
|
||||
protected readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
protected rendererService: IRendererService;
|
||||
protected cameraService: ICameraService;
|
||||
protected interactionService: IInteractionService;
|
||||
protected layerService: ILayerService;
|
||||
|
||||
protected config: Partial<InitializationOptions> | undefined;
|
||||
|
||||
public getName() {
|
||||
return '';
|
||||
}
|
||||
|
||||
public getType() {
|
||||
return PassType.Normal;
|
||||
}
|
||||
|
||||
public init(layer: ILayer, config?: Partial<InitializationOptions>) {
|
||||
this.config = config;
|
||||
this.rendererService = layer
|
||||
.getContainer()
|
||||
.get<IRendererService>(TYPES.IRendererService);
|
||||
this.cameraService = layer
|
||||
.getContainer()
|
||||
.get<ICameraService>(TYPES.ICameraService);
|
||||
this.interactionService = layer
|
||||
.getContainer()
|
||||
.get<IInteractionService>(TYPES.IInteractionService);
|
||||
this.layerService = layer
|
||||
.getContainer()
|
||||
.get<ILayerService>(TYPES.ILayerService);
|
||||
}
|
||||
|
||||
public render(layer: ILayer) {
|
||||
//
|
||||
}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { camelCase, isNil, upperFirst } from 'lodash';
|
||||
import {
|
||||
gl,
|
||||
IModel,
|
||||
IRendererService,
|
||||
IShaderModuleService,
|
||||
} from '../../../index';
|
||||
import quad from '../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import { IPostProcessingPass, PassType } from '../IMultiPassRenderer';
|
||||
|
@ -19,13 +21,14 @@ import { IUniform } from '../IUniform';
|
|||
export default class BasePostProcessingPass<InitializationOptions = {}>
|
||||
implements IPostProcessingPass<InitializationOptions> {
|
||||
@inject(TYPES.IShaderModuleService)
|
||||
protected readonly shaderModule: IShaderModuleService;
|
||||
protected readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
@inject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
protected rendererService: IRendererService;
|
||||
|
||||
protected config: Partial<InitializationOptions> | undefined;
|
||||
|
||||
protected quad: string = quad;
|
||||
|
||||
/**
|
||||
* 启用开关
|
||||
*/
|
||||
|
@ -41,10 +44,19 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
|
|||
*/
|
||||
private model: IModel;
|
||||
|
||||
/**
|
||||
* 效果名,便于在图层中引用
|
||||
*/
|
||||
private name: string;
|
||||
|
||||
private optionsToUpdate: Partial<InitializationOptions> = {};
|
||||
|
||||
public getName() {
|
||||
return '';
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public setName(name: string) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public getType() {
|
||||
|
@ -53,6 +65,9 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
|
|||
|
||||
public init(layer: ILayer, config?: Partial<InitializationOptions>) {
|
||||
this.config = config;
|
||||
this.rendererService = layer
|
||||
.getContainer()
|
||||
.get<IRendererService>(TYPES.IRendererService);
|
||||
|
||||
const { createAttribute, createBuffer, createModel } = this.rendererService;
|
||||
const { vs, fs, uniforms } = this.setupShaders();
|
||||
|
@ -80,16 +95,26 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
|
|||
enable: false,
|
||||
},
|
||||
count: 3,
|
||||
blend: {
|
||||
// copy pass 需要混合
|
||||
enable: this.getName() === 'copy',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
public render(layer: ILayer) {
|
||||
const postProcessor = layer.multiPassRenderer.getPostProcessor();
|
||||
const { useFramebuffer, getViewportSize } = this.rendererService;
|
||||
const { useFramebuffer, getViewportSize, clear } = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
useFramebuffer(
|
||||
this.renderToScreen ? null : postProcessor.getWriteFBO(),
|
||||
() => {
|
||||
clear({
|
||||
framebuffer: postProcessor.getWriteFBO(),
|
||||
color: [0, 0, 0, 0],
|
||||
depth: 1,
|
||||
stencil: 0,
|
||||
});
|
||||
this.model.draw({
|
||||
uniforms: {
|
||||
u_Texture: postProcessor.getReadFBO(),
|
||||
|
@ -133,6 +158,19 @@ export default class BasePostProcessingPass<InitializationOptions = {}>
|
|||
): {
|
||||
[uniformName: string]: IUniform;
|
||||
} | void {
|
||||
throw new Error('Method not implemented.');
|
||||
const uniforms: {
|
||||
[key: string]: IUniform;
|
||||
} = {};
|
||||
|
||||
Object.keys(options).forEach((optionName) => {
|
||||
// @ts-ignore
|
||||
if (!isNil(options[optionName])) {
|
||||
uniforms[`u_${upperFirst(camelCase(optionName))}`] =
|
||||
// @ts-ignore
|
||||
options[optionName];
|
||||
}
|
||||
});
|
||||
|
||||
return uniforms;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,20 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { TYPES } from '../../../types';
|
||||
import { IPass, PassType } from '../IMultiPassRenderer';
|
||||
import { IRendererService } from '../IRendererService';
|
||||
import { injectable } from 'inversify';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import BaseNormalPass from './BaseNormalPass';
|
||||
|
||||
/**
|
||||
* ClearPass
|
||||
*/
|
||||
@injectable()
|
||||
export default class ClearPass<InitializationOptions = {}>
|
||||
implements IPass<InitializationOptions> {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public getType() {
|
||||
return PassType.Normal;
|
||||
}
|
||||
|
||||
export default class ClearPass<
|
||||
InitializationOptions = {}
|
||||
> extends BaseNormalPass<InitializationOptions> {
|
||||
public getName() {
|
||||
return 'clear';
|
||||
}
|
||||
|
||||
public init() {
|
||||
//
|
||||
public init(layer: ILayer, config?: Partial<InitializationOptions>) {
|
||||
super.init(layer, config);
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import {
|
||||
IMultiPassRenderer,
|
||||
|
@ -7,7 +8,6 @@ import {
|
|||
IPostProcessor,
|
||||
PassType,
|
||||
} from '../IMultiPassRenderer';
|
||||
import PostProcessor from './PostProcessor';
|
||||
|
||||
/**
|
||||
* ported from Three.js EffectComposer
|
||||
|
@ -31,14 +31,15 @@ import PostProcessor from './PostProcessor';
|
|||
@injectable()
|
||||
export default class MultiPassRenderer implements IMultiPassRenderer {
|
||||
private passes: Array<IPass<unknown>> = [];
|
||||
|
||||
@inject(TYPES.IPostProcessor)
|
||||
private postProcessor: IPostProcessor;
|
||||
|
||||
private layer: ILayer;
|
||||
private renderFlag: boolean;
|
||||
|
||||
constructor(layer: ILayer) {
|
||||
public setLayer(layer: ILayer) {
|
||||
this.layer = layer;
|
||||
this.postProcessor = new PostProcessor();
|
||||
}
|
||||
|
||||
public setRenderFlag(renderFlag: boolean) {
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { TYPES } from '../../../types';
|
||||
import {
|
||||
IInteractionService,
|
||||
InteractionEvent,
|
||||
} from '../../interaction/IInteractionService';
|
||||
import { InteractionEvent } from '../../interaction/IInteractionService';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import { ILogService } from '../../log/ILogService';
|
||||
import { gl } from '../gl';
|
||||
import { IFramebuffer } from '../IFramebuffer';
|
||||
import { IPass, PassType } from '../IMultiPassRenderer';
|
||||
import { IRendererService } from '../IRendererService';
|
||||
import { PassType } from '../IMultiPassRenderer';
|
||||
import BaseNormalPass from './BaseNormalPass';
|
||||
|
||||
function decodePickingColor(color: Uint8Array): number {
|
||||
const [i1, i2, i3] = color;
|
||||
|
@ -24,15 +20,10 @@ function decodePickingColor(color: Uint8Array): number {
|
|||
* @see https://github.com/antvis/L7/blob/next/dev-docs/PixelPickingEngine.md
|
||||
*/
|
||||
@injectable()
|
||||
export default class PixelPickingPass<InitializationOptions = {}>
|
||||
implements IPass<InitializationOptions> {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
@lazyInject(TYPES.IInteractionService)
|
||||
protected readonly interactionService: IInteractionService;
|
||||
|
||||
@lazyInject(TYPES.ILogService)
|
||||
export default class PixelPickingPass<
|
||||
InitializationOptions = {}
|
||||
> extends BaseNormalPass<InitializationOptions> {
|
||||
@inject(TYPES.ILogService)
|
||||
protected readonly logger: ILogService;
|
||||
|
||||
/**
|
||||
|
@ -58,7 +49,8 @@ export default class PixelPickingPass<InitializationOptions = {}>
|
|||
return 'pixelPicking';
|
||||
}
|
||||
|
||||
public init(layer: ILayer) {
|
||||
public init(layer: ILayer, config?: Partial<InitializationOptions>) {
|
||||
super.init(layer, config);
|
||||
this.layer = layer;
|
||||
const { createTexture2D, createFramebuffer } = this.rendererService;
|
||||
|
||||
|
@ -98,8 +90,6 @@ export default class PixelPickingPass<InitializationOptions = {}>
|
|||
depth: 1,
|
||||
});
|
||||
|
||||
// this.logger.info(`picking fbo cleared ${width} ${height}`);
|
||||
|
||||
/**
|
||||
* picking pass 不需要 multipass,原因如下:
|
||||
* 1. 已经 clear,无需 ClearPass
|
||||
|
@ -129,7 +119,7 @@ export default class PixelPickingPass<InitializationOptions = {}>
|
|||
useFramebuffer,
|
||||
} = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
const { enableHighlight } = this.layer.getStyleOptions();
|
||||
const { enableHighlight } = this.layer.getLayerConfig();
|
||||
|
||||
const xInDevicePixel = x * window.devicePixelRatio;
|
||||
const yInDevicePixel = y * window.devicePixelRatio;
|
||||
|
@ -160,15 +150,21 @@ export default class PixelPickingPass<InitializationOptions = {}>
|
|||
pickedColors[1] !== 0 ||
|
||||
pickedColors[2] !== 0
|
||||
) {
|
||||
this.logger.info('picked');
|
||||
this.logger.debug('picked');
|
||||
const pickedFeatureIdx = decodePickingColor(pickedColors);
|
||||
const rawFeature = this.layer.getSource()?.data?.dataArray[
|
||||
pickedFeatureIdx
|
||||
];
|
||||
|
||||
if (!rawFeature) {
|
||||
// this.logger.error(
|
||||
// '未找到颜色编码解码后的原始 feature,请检查 fragment shader 中末尾是否添加了 `gl_FragColor = filterColor(gl_FragColor);`',
|
||||
// );
|
||||
} else {
|
||||
// trigger onHover/Click callback on layer
|
||||
this.triggerHoverOnLayer({ x, y, feature: rawFeature });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (enableHighlight) {
|
||||
|
@ -185,7 +181,7 @@ export default class PixelPickingPass<InitializationOptions = {}>
|
|||
y: number;
|
||||
feature: unknown;
|
||||
}) {
|
||||
const { onHover, onClick } = this.layer.getStyleOptions();
|
||||
const { onHover, onClick } = this.layer.getLayerConfig();
|
||||
if (onHover) {
|
||||
onHover({
|
||||
x,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import { gl } from '../gl';
|
||||
|
@ -13,34 +12,13 @@ import { IRendererService } from '../IRendererService';
|
|||
*/
|
||||
@injectable()
|
||||
export default class PostProcessor implements IPostProcessor {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
@inject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
private passes: Array<IPostProcessingPass<unknown>> = [];
|
||||
private readFBO: IFramebuffer;
|
||||
private writeFBO: IFramebuffer;
|
||||
|
||||
constructor() {
|
||||
const { createFramebuffer, createTexture2D } = this.rendererService;
|
||||
this.readFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width: 1,
|
||||
height: 1,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
wrapT: gl.CLAMP_TO_EDGE,
|
||||
}),
|
||||
});
|
||||
|
||||
this.writeFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width: 1,
|
||||
height: 1,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
wrapT: gl.CLAMP_TO_EDGE,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
public getReadFBO() {
|
||||
return this.readFBO;
|
||||
}
|
||||
|
@ -99,6 +77,28 @@ export default class PostProcessor implements IPostProcessor {
|
|||
return this.passes.find((p) => p.getName() === name);
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
private init() {
|
||||
const { createFramebuffer, createTexture2D } = this.rendererService;
|
||||
this.readFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width: 1,
|
||||
height: 1,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
wrapT: gl.CLAMP_TO_EDGE,
|
||||
}),
|
||||
});
|
||||
|
||||
this.writeFBO = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
width: 1,
|
||||
height: 1,
|
||||
wrapS: gl.CLAMP_TO_EDGE,
|
||||
wrapT: gl.CLAMP_TO_EDGE,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
private isLastEnabledPass(index: number): boolean {
|
||||
for (let i = index + 1; i < this.passes.length; i++) {
|
||||
if (this.passes[i].isEnabled()) {
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import { IPass, PassType } from '../IMultiPassRenderer';
|
||||
import { IRendererService } from '../IRendererService';
|
||||
import { PassType } from '../IMultiPassRenderer';
|
||||
import BaseNormalPass from './BaseNormalPass';
|
||||
|
||||
/**
|
||||
* RenderPass,负责输出到后续 PostProcessor 的 readFBO 中
|
||||
*/
|
||||
@injectable()
|
||||
export default class RenderPass<InitializationOptions = {}>
|
||||
implements IPass<InitializationOptions> {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
export default class RenderPass<
|
||||
InitializationOptions = {}
|
||||
> extends BaseNormalPass<InitializationOptions> {
|
||||
public getType() {
|
||||
return PassType.Normal;
|
||||
}
|
||||
|
@ -22,8 +18,8 @@ export default class RenderPass<InitializationOptions = {}>
|
|||
return 'render';
|
||||
}
|
||||
|
||||
public init(layer: ILayer) {
|
||||
//
|
||||
public init(layer: ILayer, config?: Partial<InitializationOptions>) {
|
||||
super.init(layer, config);
|
||||
}
|
||||
|
||||
public render(layer: ILayer) {
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { lazyInject } from '../../../index';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import blendFS from '../../../shaders/post-processing/blend.glsl';
|
||||
import copyFS from '../../../shaders/post-processing/copy.glsl';
|
||||
import quadVS from '../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../types';
|
||||
import { ICameraService } from '../../camera/ICameraService';
|
||||
import { ILayer } from '../../layer/ILayerService';
|
||||
import { ILogService } from '../../log/ILogService';
|
||||
import { IShaderModuleService } from '../../shader/IShaderModuleService';
|
||||
import { gl } from '../gl';
|
||||
import { IFramebuffer } from '../IFramebuffer';
|
||||
import { IModel, IModelInitializationOptions } from '../IModel';
|
||||
import { IPass, PassType } from '../IMultiPassRenderer';
|
||||
import { IRendererService } from '../IRendererService';
|
||||
import { PassType } from '../IMultiPassRenderer';
|
||||
import BaseNormalPass from './BaseNormalPass';
|
||||
|
||||
// Generate halton sequence
|
||||
// https://en.wikipedia.org/wiki/Halton_sequence
|
||||
|
@ -38,18 +36,13 @@ let accumulatingId = 1;
|
|||
* @see https://yuque.antfin-inc.com/yuqi.pyq/fgetpa/ri52hv
|
||||
*/
|
||||
@injectable()
|
||||
export default class TAAPass<InitializationOptions = {}>
|
||||
implements IPass<InitializationOptions> {
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
export default class TAAPass<InitializationOptions = {}> extends BaseNormalPass<
|
||||
InitializationOptions
|
||||
> {
|
||||
@inject(TYPES.IShaderModuleService)
|
||||
protected readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
@lazyInject(TYPES.IShaderModuleService)
|
||||
protected readonly shaderModule: IShaderModuleService;
|
||||
|
||||
@lazyInject(TYPES.ICameraService)
|
||||
protected readonly cameraService: ICameraService;
|
||||
|
||||
@lazyInject(TYPES.ILogService)
|
||||
@inject(TYPES.ILogService)
|
||||
protected readonly logger: ILogService;
|
||||
|
||||
/**
|
||||
|
@ -89,7 +82,9 @@ export default class TAAPass<InitializationOptions = {}>
|
|||
return 'taa';
|
||||
}
|
||||
|
||||
public init(layer: ILayer) {
|
||||
public init(layer: ILayer, config?: Partial<InitializationOptions>) {
|
||||
super.init(layer, config);
|
||||
|
||||
const { createFramebuffer, createTexture2D } = this.rendererService;
|
||||
this.sampleRenderTarget = createFramebuffer({
|
||||
color: createTexture2D({
|
||||
|
@ -197,11 +192,11 @@ export default class TAAPass<InitializationOptions = {}>
|
|||
}
|
||||
|
||||
private doRender(layer: ILayer) {
|
||||
this.logger.info(`accumulatingId: ${this.accumulatingId}`);
|
||||
this.logger.debug(`accumulatingId: ${this.accumulatingId}`);
|
||||
|
||||
const { clear, getViewportSize, useFramebuffer } = this.rendererService;
|
||||
const { width, height } = getViewportSize();
|
||||
const { jitterScale = 1 } = layer.getStyleOptions();
|
||||
const { jitterScale = 1 } = layer.getLayerConfig();
|
||||
|
||||
// 使用 Halton 序列抖动投影矩阵
|
||||
const offset = this.haltonSequence[this.frame % this.haltonSequence.length];
|
||||
|
@ -227,7 +222,7 @@ export default class TAAPass<InitializationOptions = {}>
|
|||
layer.multiPassRenderer.setRenderFlag(true);
|
||||
|
||||
// 混合
|
||||
const layerStyleOptions = layer.getStyleOptions();
|
||||
const layerStyleOptions = layer.getLayerConfig();
|
||||
useFramebuffer(this.outputRenderTarget, () => {
|
||||
this.blendModel.draw({
|
||||
uniforms: {
|
||||
|
@ -308,12 +303,14 @@ export default class TAAPass<InitializationOptions = {}>
|
|||
fragmentShader: string,
|
||||
options?: Partial<IModelInitializationOptions>,
|
||||
) {
|
||||
this.shaderModule.registerModule(shaderModuleName, {
|
||||
this.shaderModuleService.registerModule(shaderModuleName, {
|
||||
vs: quadVS,
|
||||
fs: fragmentShader,
|
||||
});
|
||||
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule(shaderModuleName);
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule(
|
||||
shaderModuleName,
|
||||
);
|
||||
const { createAttribute, createBuffer, createModel } = this.rendererService;
|
||||
return createModel({
|
||||
vs,
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { injectable } from 'inversify';
|
||||
import { isNil } from 'lodash';
|
||||
import blur from '../../../../shaders/post-processing/blur.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../../types';
|
||||
import { IRendererService } from '../../IRendererService';
|
||||
import { IUniform } from '../../IUniform';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
|
@ -15,20 +13,15 @@ export interface IBlurHPassConfig {
|
|||
export default class BlurHPass extends BasePostProcessingPass<
|
||||
IBlurHPassConfig
|
||||
> {
|
||||
@inject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public getName() {
|
||||
return 'blurH';
|
||||
}
|
||||
|
||||
protected setupShaders() {
|
||||
this.shaderModule.registerModule('blur-pass', {
|
||||
this.shaderModuleService.registerModule('blur-pass', {
|
||||
vs: quad,
|
||||
fs: blur,
|
||||
});
|
||||
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule('blur-pass');
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule(
|
||||
'blur-pass',
|
||||
);
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { injectable } from 'inversify';
|
||||
import { isNil } from 'lodash';
|
||||
import blur from '../../../../shaders/post-processing/blur.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../../types';
|
||||
import { IRendererService } from '../../IRendererService';
|
||||
import { IUniform } from '../../IUniform';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
|
@ -15,20 +13,15 @@ export interface IBlurVPassConfig {
|
|||
export default class BlurVPass extends BasePostProcessingPass<
|
||||
IBlurVPassConfig
|
||||
> {
|
||||
@inject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public getName() {
|
||||
return 'blurV';
|
||||
}
|
||||
|
||||
public setupShaders() {
|
||||
this.shaderModule.registerModule('blur-pass', {
|
||||
this.shaderModuleService.registerModule('blur-pass', {
|
||||
vs: quad,
|
||||
fs: blur,
|
||||
});
|
||||
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule('blur-pass');
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule(
|
||||
'blur-pass',
|
||||
);
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { isNil } from 'lodash';
|
||||
import { injectable } from 'inversify';
|
||||
import colorHalftone from '../../../../shaders/post-processing/colorhalftone.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../../types';
|
||||
import { IRendererService } from '../../IRendererService';
|
||||
import { IUniform } from '../../IUniform';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
export interface IColorHalftonePassConfig {
|
||||
|
@ -17,20 +13,13 @@ export interface IColorHalftonePassConfig {
|
|||
export default class ColorHalftonePass extends BasePostProcessingPass<
|
||||
IColorHalftonePassConfig
|
||||
> {
|
||||
@inject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public getName() {
|
||||
return 'colorHalftone';
|
||||
}
|
||||
|
||||
protected setupShaders() {
|
||||
this.shaderModule.registerModule('colorhalftone-pass', {
|
||||
this.shaderModuleService.registerModule('colorhalftone-pass', {
|
||||
vs: quad,
|
||||
fs: colorHalftone,
|
||||
});
|
||||
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule(
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule(
|
||||
'colorhalftone-pass',
|
||||
);
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
@ -44,28 +33,4 @@ export default class ColorHalftonePass extends BasePostProcessingPass<
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected convertOptionsToUniforms(
|
||||
options: Partial<IColorHalftonePassConfig>,
|
||||
): {
|
||||
[uniformName: string]: IUniform;
|
||||
} | void {
|
||||
const uniforms: {
|
||||
[key: string]: IUniform;
|
||||
} = {};
|
||||
|
||||
if (!isNil(options.center)) {
|
||||
uniforms.u_Center = options.center;
|
||||
}
|
||||
|
||||
if (!isNil(options.angle)) {
|
||||
uniforms.u_Angle = options.angle;
|
||||
}
|
||||
|
||||
if (!isNil(options.size)) {
|
||||
uniforms.u_Size = options.size;
|
||||
}
|
||||
|
||||
return uniforms;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,16 @@
|
|||
import { injectable } from 'inversify';
|
||||
import copy from '../../../../shaders/post-processing/copy.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { IUniform } from '../../IUniform';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
@injectable()
|
||||
export default class CopyPass extends BasePostProcessingPass {
|
||||
public getName() {
|
||||
return 'copy';
|
||||
}
|
||||
|
||||
public setupShaders() {
|
||||
this.shaderModule.registerModule('copy-pass', {
|
||||
this.shaderModuleService.registerModule('copy-pass', {
|
||||
vs: quad,
|
||||
fs: copy,
|
||||
});
|
||||
|
||||
return this.shaderModule.getModule('copy-pass');
|
||||
}
|
||||
|
||||
protected convertOptionsToUniforms(
|
||||
options: Partial<{}>,
|
||||
): {
|
||||
[uniformName: string]: IUniform;
|
||||
} | void {
|
||||
return {};
|
||||
return this.shaderModuleService.getModule('copy-pass');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { isNil } from 'lodash';
|
||||
import { injectable } from 'inversify';
|
||||
import hexagonalPixelate from '../../../../shaders/post-processing/hexagonalpixelate.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../../types';
|
||||
import { IRendererService } from '../../IRendererService';
|
||||
import { IUniform } from '../../IUniform';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
export interface IHexagonalPixelatePassConfig {
|
||||
|
@ -16,20 +12,13 @@ export interface IHexagonalPixelatePassConfig {
|
|||
export default class HexagonalPixelatePass extends BasePostProcessingPass<
|
||||
IHexagonalPixelatePassConfig
|
||||
> {
|
||||
@inject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public getName() {
|
||||
return 'hexagonalPixelate';
|
||||
}
|
||||
|
||||
protected setupShaders() {
|
||||
this.shaderModule.registerModule('hexagonalpixelate-pass', {
|
||||
this.shaderModuleService.registerModule('hexagonalpixelate-pass', {
|
||||
vs: quad,
|
||||
fs: hexagonalPixelate,
|
||||
});
|
||||
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule(
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule(
|
||||
'hexagonalpixelate-pass',
|
||||
);
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
@ -43,24 +32,4 @@ export default class HexagonalPixelatePass extends BasePostProcessingPass<
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected convertOptionsToUniforms(
|
||||
options: Partial<IHexagonalPixelatePassConfig>,
|
||||
): {
|
||||
[uniformName: string]: IUniform;
|
||||
} | void {
|
||||
const uniforms: {
|
||||
[key: string]: IUniform;
|
||||
} = {};
|
||||
|
||||
if (!isNil(options.center)) {
|
||||
uniforms.u_Center = options.center;
|
||||
}
|
||||
|
||||
if (!isNil(options.scale)) {
|
||||
uniforms.u_Scale = options.scale;
|
||||
}
|
||||
|
||||
return uniforms;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { isNil } from 'lodash';
|
||||
import { injectable } from 'inversify';
|
||||
import ink from '../../../../shaders/post-processing/ink.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { TYPES } from '../../../../types';
|
||||
import { IRendererService } from '../../IRendererService';
|
||||
import { IUniform } from '../../IUniform';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
export interface IInkPassConfig {
|
||||
|
@ -13,20 +9,13 @@ export interface IInkPassConfig {
|
|||
|
||||
@injectable()
|
||||
export default class InkPass extends BasePostProcessingPass<IInkPassConfig> {
|
||||
@inject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
public getName() {
|
||||
return 'ink';
|
||||
}
|
||||
|
||||
protected setupShaders() {
|
||||
this.shaderModule.registerModule('ink-pass', {
|
||||
this.shaderModuleService.registerModule('ink-pass', {
|
||||
vs: quad,
|
||||
fs: ink,
|
||||
});
|
||||
|
||||
const { vs, fs, uniforms } = this.shaderModule.getModule('ink-pass');
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule('ink-pass');
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
|
||||
return {
|
||||
|
@ -38,20 +27,4 @@ export default class InkPass extends BasePostProcessingPass<IInkPassConfig> {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected convertOptionsToUniforms(
|
||||
options: Partial<IInkPassConfig>,
|
||||
): {
|
||||
[uniformName: string]: IUniform;
|
||||
} | void {
|
||||
const uniforms: {
|
||||
[key: string]: IUniform;
|
||||
} = {};
|
||||
|
||||
if (!isNil(options.strength)) {
|
||||
uniforms.u_Strength = options.strength;
|
||||
}
|
||||
|
||||
return uniforms;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { isNil } from 'lodash';
|
||||
import noise from '../../../../shaders/post-processing/noise.glsl';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import { IUniform } from '../../IUniform';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
export interface INoisePassConfig {
|
||||
|
@ -13,32 +11,12 @@ export interface INoisePassConfig {
|
|||
export default class NoisePass extends BasePostProcessingPass<
|
||||
INoisePassConfig
|
||||
> {
|
||||
public getName() {
|
||||
return 'noise';
|
||||
}
|
||||
|
||||
public setupShaders() {
|
||||
this.shaderModule.registerModule('noise-pass', {
|
||||
this.shaderModuleService.registerModule('noise-pass', {
|
||||
vs: quad,
|
||||
fs: noise,
|
||||
});
|
||||
|
||||
return this.shaderModule.getModule('noise-pass');
|
||||
}
|
||||
|
||||
protected convertOptionsToUniforms(
|
||||
options: Partial<INoisePassConfig>,
|
||||
): {
|
||||
[uniformName: string]: IUniform;
|
||||
} | void {
|
||||
const uniforms: {
|
||||
[key: string]: IUniform;
|
||||
} = {};
|
||||
|
||||
if (!isNil(options.amount)) {
|
||||
uniforms.u_Amount = options.amount;
|
||||
}
|
||||
|
||||
return uniforms;
|
||||
return this.shaderModuleService.getModule('noise-pass');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { injectable } from 'inversify';
|
||||
import { isNil } from 'lodash';
|
||||
import quad from '../../../../shaders/post-processing/quad.glsl';
|
||||
import sepia from '../../../../shaders/post-processing/sepia.glsl';
|
||||
import { IUniform } from '../../IUniform';
|
||||
import BasePostProcessingPass from '../BasePostProcessingPass';
|
||||
|
||||
export interface ISepiaPassConfig {
|
||||
|
@ -13,32 +11,12 @@ export interface ISepiaPassConfig {
|
|||
export default class SepiaPass extends BasePostProcessingPass<
|
||||
ISepiaPassConfig
|
||||
> {
|
||||
public getName() {
|
||||
return 'sepia';
|
||||
}
|
||||
|
||||
public setupShaders() {
|
||||
this.shaderModule.registerModule('sepia-pass', {
|
||||
this.shaderModuleService.registerModule('sepia-pass', {
|
||||
vs: quad,
|
||||
fs: sepia,
|
||||
});
|
||||
|
||||
return this.shaderModule.getModule('sepia-pass');
|
||||
}
|
||||
|
||||
protected convertOptionsToUniforms(
|
||||
options: Partial<ISepiaPassConfig>,
|
||||
): {
|
||||
[uniformName: string]: IUniform;
|
||||
} | void {
|
||||
const uniforms: {
|
||||
[key: string]: IUniform;
|
||||
} = {};
|
||||
|
||||
if (!isNil(options.amount)) {
|
||||
uniforms.u_Amount = options.amount;
|
||||
}
|
||||
|
||||
return uniforms;
|
||||
return this.shaderModuleService.getModule('sepia-pass');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { EventEmitter } from 'eventemitter3';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { AsyncParallelHook, AsyncSeriesHook } from 'tapable';
|
||||
import { AsyncParallelHook } from 'tapable';
|
||||
import { TYPES } from '../../types';
|
||||
import { createRendererContainer } from '../../utils/dom';
|
||||
import { IFontService } from '../asset/IFontService';
|
||||
import { IIconService, IImage } from '../asset/IIconService';
|
||||
import { IIconService } from '../asset/IIconService';
|
||||
import { ICameraService, IViewport } from '../camera/ICameraService';
|
||||
import { IControlService } from '../component/IControlService';
|
||||
import { IGlobalConfig, IGlobalConfigService } from '../config/IConfigService';
|
||||
import { IGlobalConfigService, ISceneConfig } from '../config/IConfigService';
|
||||
import { IInteractionService } from '../interaction/IInteractionService';
|
||||
import { ILayer, ILayerService } from '../layer/ILayerService';
|
||||
import { ILogService } from '../log/ILogService';
|
||||
|
@ -15,11 +15,14 @@ import { IMapCamera, IMapService } from '../map/IMapService';
|
|||
import { IRendererService } from '../renderer/IRendererService';
|
||||
import { IShaderModuleService } from '../shader/IShaderModuleService';
|
||||
import { ISceneService } from './ISceneService';
|
||||
|
||||
/**
|
||||
* will emit `loaded` `resize` `destroy` event
|
||||
*/
|
||||
@injectable()
|
||||
export default class Scene extends EventEmitter implements ISceneService {
|
||||
@inject(TYPES.SceneID)
|
||||
private readonly id: string;
|
||||
/**
|
||||
* 使用各种 Service
|
||||
*/
|
||||
|
@ -54,7 +57,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
private readonly interactionService: IInteractionService;
|
||||
|
||||
@inject(TYPES.IShaderModuleService)
|
||||
private readonly shaderModule: IShaderModuleService;
|
||||
private readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
/**
|
||||
* 是否首次渲染
|
||||
|
@ -62,6 +65,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
private inited: boolean = false;
|
||||
private initPromise: Promise<void>;
|
||||
|
||||
// TODO: 改成状态机
|
||||
private rendering: boolean = false;
|
||||
|
||||
/**
|
||||
* canvas 容器
|
||||
*/
|
||||
|
@ -85,11 +91,21 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
};
|
||||
}
|
||||
|
||||
public init(globalConfig: IGlobalConfig) {
|
||||
this.initClear();
|
||||
this.configService.setAndCheckConfig(globalConfig);
|
||||
public init(sceneConfig: ISceneConfig) {
|
||||
// 设置场景配置项
|
||||
this.configService.setSceneConfig(this.id, sceneConfig);
|
||||
|
||||
// 校验场景配置项,失败则终止初始化过程
|
||||
const { valid, errorText } = this.configService.validateSceneConfig(
|
||||
this.configService.getSceneConfig(this.id),
|
||||
);
|
||||
if (!valid) {
|
||||
this.logger.error(errorText || '');
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化 ShaderModule
|
||||
this.shaderModule.registerBuiltinModules();
|
||||
this.shaderModuleService.registerBuiltinModules();
|
||||
|
||||
// 初始化资源管理 图片
|
||||
this.iconService.init();
|
||||
|
@ -98,7 +114,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
|
||||
this.controlService.init({
|
||||
container: document.getElementById(
|
||||
this.configService.getConfig().id || 'map',
|
||||
this.configService.getSceneConfig(this.id).id || 'map',
|
||||
) as HTMLElement,
|
||||
});
|
||||
|
||||
|
@ -118,7 +134,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
|
||||
// 重新绑定非首次相机更新事件
|
||||
this.map.onCameraChanged(this.handleMapCameraChanged);
|
||||
this.logger.info('map loaded');
|
||||
this.logger.debug('map loaded');
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -127,7 +143,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.hooks.init.tapPromise('initRenderer', async () => {
|
||||
// 创建底图之上的 container
|
||||
const $container = createRendererContainer(
|
||||
this.configService.getConfig().id || '',
|
||||
this.configService.getSceneConfig(this.id).id || '',
|
||||
);
|
||||
this.$container = $container;
|
||||
if ($container) {
|
||||
|
@ -140,28 +156,35 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
// 初始化 container 上的交互
|
||||
this.interactionService.init();
|
||||
|
||||
this.logger.info('renderer loaded');
|
||||
this.logger.debug(`scene ${this.id} renderer loaded`);
|
||||
});
|
||||
// TODO:init worker, fontAtlas...
|
||||
|
||||
// 执行异步并行初始化任务
|
||||
this.initPromise = this.hooks.init.promise(this.configService.getConfig());
|
||||
this.initPromise = this.hooks.init.promise(
|
||||
this.configService.getSceneConfig(this.id),
|
||||
);
|
||||
}
|
||||
|
||||
public addLayer(layer: ILayer) {
|
||||
this.logger.info(`add layer ${layer.name}`);
|
||||
this.logger.debug(`add layer ${layer.name} to scene ${this.id}`);
|
||||
this.layerService.add(layer);
|
||||
// scene 创建完成自动调用render 方法
|
||||
this.render();
|
||||
}
|
||||
|
||||
public async render() {
|
||||
if (this.rendering) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rendering = true;
|
||||
|
||||
// 首次初始化,或者地图的容器被强制销毁的需要重新初始化
|
||||
if (!this.inited) {
|
||||
// 还未初始化完成需要等待
|
||||
|
||||
await this.initPromise;
|
||||
// 初始化 marker 容器 TODO: 可以放到 map 初始化方法中?
|
||||
// FIXME: 初始化 marker 容器,可以放到 map 初始化方法中?
|
||||
this.map.addMarkerContainer();
|
||||
this.logger.info(' render inited');
|
||||
this.emit('loaded');
|
||||
|
@ -171,14 +194,15 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
// 尝试初始化未初始化的图层
|
||||
this.layerService.initLayers();
|
||||
this.layerService.renderLayers();
|
||||
this.logger.info('render');
|
||||
this.logger.debug(`scene ${this.id} render`);
|
||||
|
||||
this.rendering = false;
|
||||
}
|
||||
|
||||
public destroy() {
|
||||
this.emit('destroy');
|
||||
this.inited = false;
|
||||
this.layerService.destroy();
|
||||
this.configService.reset();
|
||||
this.interactionService.destroy();
|
||||
this.controlService.destroy();
|
||||
this.removeAllListeners();
|
||||
|
@ -186,6 +210,7 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.map.destroy();
|
||||
window.removeEventListener('resize', this.handleWindowResized, false);
|
||||
}
|
||||
|
||||
private handleWindowResized = () => {
|
||||
this.emit('resize');
|
||||
if (this.$container) {
|
||||
|
@ -209,18 +234,9 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
this.render();
|
||||
}
|
||||
};
|
||||
|
||||
private handleMapCameraChanged = (viewport: IViewport) => {
|
||||
this.cameraService.update(viewport);
|
||||
this.render();
|
||||
};
|
||||
private initClear() {
|
||||
this.inited = false;
|
||||
this.layerService.destroy();
|
||||
this.configService.reset();
|
||||
this.interactionService.destroy();
|
||||
this.controlService.destroy();
|
||||
this.removeAllListeners();
|
||||
this.map.destroy();
|
||||
window.removeEventListener('resize', this.handleWindowResized, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
declare module '*.glsl' {
|
||||
const value: string;
|
||||
// @ts-ignore
|
||||
export default value;
|
||||
}
|
|
@ -17,9 +17,15 @@ const TYPES = {
|
|||
IInteractionService: Symbol.for('IInteractionService'),
|
||||
IControlService: Symbol.for('IControlService'),
|
||||
IStyleAttributeService: Symbol.for('IStyleAttributeService'),
|
||||
ILayer: Symbol.for('ILayer'),
|
||||
ILayerPlugin: Symbol.for('ILayerPlugin'),
|
||||
INormalPass: Symbol.for('INormalPass'),
|
||||
IPostProcessor: Symbol.for('IPostProcessor'),
|
||||
IPostProcessingPass: Symbol.for('IPostProcessingPass'),
|
||||
IFactoryPostProcessingPass: Symbol.for('Factory<IPostProcessingPass>'),
|
||||
IFactoryNormalPass: Symbol.for('Factory<IFactoryNormalPass>'),
|
||||
IMultiPassRenderer: Symbol.for('IMultiPassRenderer'),
|
||||
SceneID: Symbol.for('SceneID'),
|
||||
};
|
||||
|
||||
export { TYPES };
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const docStyle = window.document.documentElement.style;
|
||||
type ELType = HTMLElement | SVGElement;
|
||||
let containerCounter = 0;
|
||||
export function createRendererContainer(
|
||||
domId: string | HTMLDivElement,
|
||||
): HTMLDivElement | null {
|
||||
|
@ -17,7 +18,8 @@ export function createRendererContainer(
|
|||
width: 100%;
|
||||
pointer-events: none;
|
||||
`;
|
||||
$container.id = 'l7_canvaslayer';
|
||||
$container.id = `l7-scene-${containerCounter++}`;
|
||||
$container.classList.add('l7-scene');
|
||||
$wrapper.appendChild($container);
|
||||
return $container;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
"compilerOptions": {
|
||||
"declarationDir": "./es",
|
||||
"rootDir": "./src",
|
||||
"baseUrl": "./"
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"*": ["node_modules", "typings/*"]
|
||||
}
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
|
@ -1,13 +1,14 @@
|
|||
|
||||
declare module 'probe.gl' {
|
||||
class Log {
|
||||
constructor(options: { id: string });
|
||||
|
||||
priority: number;
|
||||
enable(enabled?: boolean): Log;
|
||||
|
||||
debug(priority: number, message: string): () => any;
|
||||
info(priority: number, message: string): () => any;
|
||||
warn(message: string): () => any;
|
||||
info(message: string): () => any;
|
||||
error(message: string): () => any;
|
||||
probe(priority: number, message: string): () => any;
|
||||
}
|
||||
}
|
||||
/// <reference path="../../../node_modules/eventemitter3/index.d.ts" />
|
|
@ -1,8 +1,10 @@
|
|||
{
|
||||
"name": "@antv/l7",
|
||||
"version": "2.0.0-beta.9",
|
||||
"version": "2.0.0-beta.10",
|
||||
"description": "A Large-scale WebGL-powered Geospatial Data Visualization",
|
||||
"main": "dist/l7.js",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"types": "es/index.d.ts",
|
||||
"sideEffects": true,
|
||||
"files": [
|
||||
"dist",
|
||||
|
@ -20,17 +22,14 @@
|
|||
},
|
||||
"author": "antv",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@antv/l7-component": "^2.0.0-beta.10",
|
||||
"@antv/l7-core": "^2.0.0-beta.10",
|
||||
"@antv/l7-layers": "^2.0.0-beta.10",
|
||||
"@antv/l7-scene": "^2.0.0-beta.10"
|
||||
},
|
||||
"gitHead": "0563f357f3a07c099bf1ffa9350e6fa3c88353ae",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"@l7/core": "0.0.1",
|
||||
"@l7/scene": "0.0.1",
|
||||
"@l7/layers": "0.0.1",
|
||||
"@l7/component": "0.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"mapbox-gl": "^1.5.0"
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
// @ts-ignore
|
||||
export * from '@l7/core';
|
||||
// @ts-ignore
|
||||
export * from '@l7/scene';
|
||||
// @ts-ignore
|
||||
export * from '@l7/layers';
|
||||
// @ts-ignore
|
||||
export * from '@l7/component';
|
||||
export * from '@antv/l7-core';
|
||||
export * from '@antv/l7-scene';
|
||||
export * from '@antv/l7-layers';
|
||||
export * from '@antv/l7-component';
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"extends": "../../tsconfig.build.json",
|
||||
"compilerOptions": {
|
||||
"declarationDir": "./es",
|
||||
"rootDir": "./src",
|
||||
"baseUrl": "./"
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
# L7's Collection of Layers
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
yarn add @antv/l7-layers
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
Use built-in layers directly:
|
||||
```typescript
|
||||
import { PointLayer } from '@antv/l7-layers';
|
||||
|
||||
const layer = new PointLayer({
|
||||
// ...initialization options
|
||||
});
|
||||
```
|
||||
|
||||
Create a custom layer with the help of `BaseLayer`:
|
||||
```typescript
|
||||
import { BaseLayer } from '@antv/l7-layers';
|
||||
|
||||
class MyCustomLayer extends BaseLayer {
|
||||
// ...override methods
|
||||
}
|
||||
|
||||
const layer = new MyCustomLayer({
|
||||
// ...initialization options
|
||||
});
|
||||
```
|
||||
|
||||
## Current Built-in Layers
|
||||
|
||||
* PointLayer
|
||||
* PolygonLayer
|
||||
* LineLayer
|
||||
* HeatmapLayer
|
||||
* RasterLayer
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@l7/layers",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"name": "@antv/l7-layers",
|
||||
"version": "2.0.0-beta.10",
|
||||
"description": "L7's collection of built-in layers",
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"types": "es/index.d.ts",
|
||||
|
@ -22,9 +22,9 @@
|
|||
"author": "xiaoiver",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@l7/core": "^0.0.1",
|
||||
"@l7/source": "^0.0.1",
|
||||
"@l7/utils": "^0.0.1",
|
||||
"@antv/l7-core": "^2.0.0-beta.10",
|
||||
"@antv/l7-source": "^2.0.0-beta.10",
|
||||
"@antv/l7-utils": "^2.0.0-beta.10",
|
||||
"@mapbox/martini": "^0.1.0",
|
||||
"@turf/meta": "^6.0.2",
|
||||
"@types/d3-color": "^1.2.2",
|
||||
|
|
|
@ -1,38 +1,40 @@
|
|||
import {
|
||||
gl,
|
||||
IAnimateOption,
|
||||
ICameraService,
|
||||
IEncodeFeature,
|
||||
IFontService,
|
||||
IGlobalConfigService,
|
||||
IIconService,
|
||||
IInteractionService,
|
||||
ILayer,
|
||||
ILayerInitializationOptions,
|
||||
ILayerConfig,
|
||||
ILayerModel,
|
||||
ILayerModelInitializationOptions,
|
||||
ILayerPlugin,
|
||||
ILayerService,
|
||||
ILogService,
|
||||
IMapService,
|
||||
IModel,
|
||||
IModelInitializationOptions,
|
||||
IMultiPassRenderer,
|
||||
IPass,
|
||||
IPostProcessingPass,
|
||||
IRendererService,
|
||||
IScale,
|
||||
IScaleOptions,
|
||||
IShaderModuleService,
|
||||
ISourceCFG,
|
||||
IStyleAttributeInitializationOptions,
|
||||
IStyleAttributeService,
|
||||
IStyleAttributeUpdateOptions,
|
||||
lazyInject,
|
||||
lazyMultiInject,
|
||||
StyleAttributeField,
|
||||
StyleAttributeOption,
|
||||
Triangulation,
|
||||
TYPES,
|
||||
} from '@l7/core';
|
||||
import Source from '@l7/source';
|
||||
} from '@antv/l7-core';
|
||||
import Source from '@antv/l7-source';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { Container } from 'inversify';
|
||||
import { isFunction, isObject } from 'lodash';
|
||||
// @ts-ignore
|
||||
import mergeJsonSchemas from 'merge-json-schemas';
|
||||
|
@ -45,22 +47,6 @@ import baseLayerSchema from './schema';
|
|||
*/
|
||||
let layerIdCounter = 0;
|
||||
|
||||
/**
|
||||
* Layer 基类默认样式属性
|
||||
*/
|
||||
const defaultLayerInitializationOptions: Partial<ILayerInitializationOptions> = {
|
||||
minZoom: 0,
|
||||
maxZoom: 20,
|
||||
visible: true,
|
||||
zIndex: 0,
|
||||
enableMultiPassRenderer: false,
|
||||
enablePicking: false,
|
||||
enableHighlight: false,
|
||||
highlightColor: 'red',
|
||||
enableTAA: false,
|
||||
jitterScale: 1,
|
||||
};
|
||||
|
||||
export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||
implements ILayer {
|
||||
public id: string = `${layerIdCounter++}`;
|
||||
|
@ -91,7 +77,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
public multiPassRenderer: IMultiPassRenderer;
|
||||
|
||||
// 注入插件集
|
||||
@lazyMultiInject(TYPES.ILayerPlugin)
|
||||
public plugins: ILayerPlugin[];
|
||||
|
||||
public sourceOption: {
|
||||
|
@ -99,72 +84,95 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
options?: ISourceCFG;
|
||||
};
|
||||
|
||||
@lazyInject(TYPES.IStyleAttributeService)
|
||||
public styleAttributeService: IStyleAttributeService;
|
||||
@lazyInject(TYPES.ILogService)
|
||||
protected readonly logger: ILogService;
|
||||
|
||||
@lazyInject(TYPES.IGlobalConfigService)
|
||||
public readonly configService: IGlobalConfigService;
|
||||
|
||||
@lazyInject(TYPES.IIconService)
|
||||
public readonly iconService: IIconService;
|
||||
|
||||
@lazyInject(TYPES.IFontService)
|
||||
public readonly fontService: IFontService;
|
||||
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
public readonly rendererService: IRendererService;
|
||||
|
||||
protected layerSource: Source;
|
||||
protected readonly configService: IGlobalConfigService;
|
||||
|
||||
@lazyInject(TYPES.IShaderModuleService)
|
||||
protected readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
@lazyInject(TYPES.IMapService)
|
||||
protected readonly map: IMapService;
|
||||
protected iconService: IIconService;
|
||||
|
||||
@lazyInject(TYPES.ILayerService)
|
||||
protected readonly layerService: ILayerService;
|
||||
protected fontService: IFontService;
|
||||
|
||||
protected rendererService: IRendererService;
|
||||
|
||||
protected layerService: ILayerService;
|
||||
|
||||
protected interactionService: IInteractionService;
|
||||
|
||||
protected mapService: IMapService;
|
||||
|
||||
protected styleAttributeService: IStyleAttributeService;
|
||||
|
||||
protected layerSource: Source;
|
||||
|
||||
protected postProcessingPassFactory: (
|
||||
name: string,
|
||||
) => IPostProcessingPass<unknown>;
|
||||
protected normalPassFactory: (name: string) => IPass<unknown>;
|
||||
|
||||
protected layerModel: ILayerModel;
|
||||
|
||||
protected enodeOptions: {
|
||||
[type: string]: {
|
||||
field: StyleAttributeField;
|
||||
values?: StyleAttributeOption;
|
||||
};
|
||||
} = {};
|
||||
|
||||
protected animateOptions: IAnimateOption = { enable: false };
|
||||
|
||||
/**
|
||||
* 图层容器
|
||||
*/
|
||||
private container: Container;
|
||||
|
||||
private encodedData: IEncodeFeature[];
|
||||
|
||||
private configSchema: object;
|
||||
|
||||
private rawConfig: Partial<ILayerConfig & ChildLayerStyleOptions>;
|
||||
|
||||
/**
|
||||
* 保存样式属性
|
||||
* 待更新样式属性,在初始化阶段完成注册
|
||||
*/
|
||||
private styleOptions: Partial<
|
||||
ILayerInitializationOptions & ChildLayerStyleOptions
|
||||
>;
|
||||
private pendingStyleAttributes: Array<{
|
||||
attributeName: string;
|
||||
attributeField: StyleAttributeField;
|
||||
attributeValues?: StyleAttributeOption;
|
||||
defaultName?: string;
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>;
|
||||
}> = [];
|
||||
|
||||
private scaleOptions: IScaleOptions = {};
|
||||
|
||||
@lazyInject(TYPES.IInteractionService)
|
||||
private readonly interactionService: IInteractionService;
|
||||
|
||||
constructor(
|
||||
styleOptions: Partial<ILayerInitializationOptions & ChildLayerStyleOptions>,
|
||||
) {
|
||||
constructor(config: Partial<ILayerConfig & ChildLayerStyleOptions>) {
|
||||
super();
|
||||
this.styleOptions = {
|
||||
...defaultLayerInitializationOptions,
|
||||
...styleOptions,
|
||||
};
|
||||
const { minZoom, maxZoom, zIndex, visible } = this
|
||||
.styleOptions as ILayerInitializationOptions;
|
||||
this.visible = visible;
|
||||
this.zIndex = zIndex;
|
||||
this.minZoom = minZoom;
|
||||
this.maxZoom = maxZoom;
|
||||
this.rawConfig = config;
|
||||
}
|
||||
|
||||
public getLayerConfig() {
|
||||
return this.configService.getLayerConfig<ChildLayerStyleOptions>(this.id);
|
||||
}
|
||||
|
||||
public updateLayerConfig(
|
||||
configToUpdate: Partial<ILayerConfig | ChildLayerStyleOptions>,
|
||||
) {
|
||||
const sceneId = this.container.get<string>(TYPES.SceneID);
|
||||
this.configService.setLayerConfig(sceneId, this.id, {
|
||||
...this.configService.getLayerConfig(this.id),
|
||||
...configToUpdate,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入图层容器,父容器为场景容器
|
||||
* RootContainer 1
|
||||
* -> SceneContainer 1.*
|
||||
* -> LayerContainer 1.*
|
||||
*/
|
||||
public setContainer(container: Container) {
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
public getContainer() {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
public addPlugin(plugin: ILayerPlugin) {
|
||||
|
@ -178,6 +186,81 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
|
||||
public init() {
|
||||
// 设置配置项
|
||||
const sceneId = this.container.get<string>(TYPES.SceneID);
|
||||
this.configService.setLayerConfig(sceneId, this.id, this.rawConfig);
|
||||
|
||||
// 全局容器服务
|
||||
this.iconService = this.container.get<IIconService>(TYPES.IIconService);
|
||||
this.fontService = this.container.get<IFontService>(TYPES.IFontService);
|
||||
|
||||
// 场景容器服务
|
||||
this.rendererService = this.container.get<IRendererService>(
|
||||
TYPES.IRendererService,
|
||||
);
|
||||
this.layerService = this.container.get<ILayerService>(TYPES.ILayerService);
|
||||
this.interactionService = this.container.get<IInteractionService>(
|
||||
TYPES.IInteractionService,
|
||||
);
|
||||
this.mapService = this.container.get<IMapService>(TYPES.IMapService);
|
||||
this.postProcessingPassFactory = this.container.get(
|
||||
TYPES.IFactoryPostProcessingPass,
|
||||
);
|
||||
this.normalPassFactory = this.container.get(TYPES.IFactoryNormalPass);
|
||||
|
||||
// 图层容器服务
|
||||
this.styleAttributeService = this.container.get<IStyleAttributeService>(
|
||||
TYPES.IStyleAttributeService,
|
||||
);
|
||||
this.multiPassRenderer = this.container.get<IMultiPassRenderer>(
|
||||
TYPES.IMultiPassRenderer,
|
||||
);
|
||||
this.multiPassRenderer.setLayer(this);
|
||||
|
||||
// 完成样式服务注册完成前添加的属性
|
||||
this.pendingStyleAttributes.forEach(
|
||||
({
|
||||
attributeName,
|
||||
attributeField,
|
||||
attributeValues,
|
||||
defaultName,
|
||||
updateOptions,
|
||||
}) => {
|
||||
this.styleAttributeService.updateStyleAttribute(
|
||||
attributeName,
|
||||
{
|
||||
// @ts-ignore
|
||||
scale: {
|
||||
field: attributeField,
|
||||
...this.splitValuesAndCallbackInAttribute(
|
||||
// @ts-ignore
|
||||
attributeValues,
|
||||
// @ts-ignore
|
||||
this.getLayerConfig()[defaultName || attributeName],
|
||||
),
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
updateOptions,
|
||||
);
|
||||
},
|
||||
);
|
||||
this.pendingStyleAttributes = [];
|
||||
|
||||
// 获取插件集
|
||||
this.plugins = this.container.getAll<ILayerPlugin>(TYPES.ILayerPlugin);
|
||||
// 完成插件注册,传入场景和图层容器内的服务
|
||||
for (const plugin of this.plugins) {
|
||||
plugin.apply(this, {
|
||||
rendererService: this.rendererService,
|
||||
mapService: this.mapService,
|
||||
styleAttributeService: this.styleAttributeService,
|
||||
normalPassFactory: this.normalPassFactory,
|
||||
postProcessingPassFactory: this.postProcessingPassFactory,
|
||||
});
|
||||
}
|
||||
|
||||
// 触发 init 生命周期插件
|
||||
this.hooks.init.call();
|
||||
this.buildModels();
|
||||
|
||||
|
@ -190,22 +273,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
this.styleAttributeService.updateStyleAttribute(
|
||||
'color',
|
||||
{
|
||||
// @ts-ignore
|
||||
scale: {
|
||||
field,
|
||||
...this.splitValuesAndCallbackInAttribute(
|
||||
// @ts-ignore
|
||||
values,
|
||||
this.configService.getConfig().colors,
|
||||
),
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
// 设置 color、size、shape、style 时由于场景服务尚未完成(并没有调用 scene.addLayer),因此暂时加入待更新属性列表
|
||||
this.pendingStyleAttributes.push({
|
||||
attributeName: 'color',
|
||||
attributeField: field,
|
||||
attributeValues: values,
|
||||
defaultName: 'colors',
|
||||
updateOptions,
|
||||
);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -214,22 +289,12 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
this.styleAttributeService.updateStyleAttribute(
|
||||
'size',
|
||||
{
|
||||
// @ts-ignore
|
||||
scale: {
|
||||
field,
|
||||
...this.splitValuesAndCallbackInAttribute(
|
||||
// @ts-ignore
|
||||
values,
|
||||
this.configService.getConfig().size,
|
||||
),
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
this.pendingStyleAttributes.push({
|
||||
attributeName: 'size',
|
||||
attributeField: field,
|
||||
attributeValues: values,
|
||||
updateOptions,
|
||||
);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -238,26 +303,12 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
this.enodeOptions.shape = {
|
||||
field,
|
||||
values,
|
||||
};
|
||||
this.styleAttributeService.updateStyleAttribute(
|
||||
'shape',
|
||||
{
|
||||
// @ts-ignore
|
||||
scale: {
|
||||
field,
|
||||
...this.splitValuesAndCallbackInAttribute(
|
||||
// @ts-ignore
|
||||
values,
|
||||
this.configService.getConfig().shape,
|
||||
),
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
this.pendingStyleAttributes.push({
|
||||
attributeName: 'shape',
|
||||
attributeField: field,
|
||||
attributeValues: values,
|
||||
updateOptions,
|
||||
);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
public label(
|
||||
|
@ -265,22 +316,12 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
this.styleAttributeService.updateStyleAttribute(
|
||||
'label',
|
||||
{
|
||||
// @ts-ignore
|
||||
scale: {
|
||||
field,
|
||||
...this.splitValuesAndCallbackInAttribute(
|
||||
// @ts-ignore
|
||||
values,
|
||||
null,
|
||||
),
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
this.pendingStyleAttributes.push({
|
||||
attributeName: 'label',
|
||||
attributeField: field,
|
||||
attributeValues: values,
|
||||
updateOptions,
|
||||
);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
public animate(options: IAnimateOption) {
|
||||
|
@ -295,7 +336,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
};
|
||||
return this;
|
||||
}
|
||||
public style(options: object & Partial<ILayerInitializationOptions>): ILayer {
|
||||
public style(options: object & Partial<ILayerConfig>): ILayer {
|
||||
const { passes, ...rest } = options;
|
||||
|
||||
// passes 特殊处理
|
||||
|
@ -312,10 +353,14 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
);
|
||||
}
|
||||
|
||||
this.styleOptions = {
|
||||
...this.styleOptions,
|
||||
this.rawConfig = {
|
||||
...this.rawConfig,
|
||||
...rest,
|
||||
};
|
||||
|
||||
if (this.container) {
|
||||
this.updateLayerConfig(this.rawConfig);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public scale(field: string | IScaleOptions, cfg: IScale) {
|
||||
|
@ -339,13 +384,17 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
|
||||
public show(): ILayer {
|
||||
this.visible = true;
|
||||
this.updateLayerConfig({
|
||||
visible: true,
|
||||
});
|
||||
this.layerService.renderLayers();
|
||||
return this;
|
||||
}
|
||||
|
||||
public hide(): ILayer {
|
||||
this.visible = false;
|
||||
this.updateLayerConfig({
|
||||
visible: false,
|
||||
});
|
||||
this.layerService.renderLayers();
|
||||
return this;
|
||||
}
|
||||
|
@ -357,17 +406,27 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
|
||||
public isVisible(): boolean {
|
||||
const zoom = this.map.getZoom();
|
||||
return this.visible && zoom >= this.minZoom && zoom <= this.maxZoom;
|
||||
const zoom = this.mapService.getZoom();
|
||||
|
||||
const {
|
||||
visible,
|
||||
minZoom = -Infinity,
|
||||
maxZoom = Infinity,
|
||||
} = this.getLayerConfig();
|
||||
return !!visible && zoom >= minZoom && zoom <= maxZoom;
|
||||
}
|
||||
|
||||
public setMinZoom(min: number): ILayer {
|
||||
this.minZoom = min;
|
||||
public setMinZoom(minZoom: number): ILayer {
|
||||
this.updateLayerConfig({
|
||||
minZoom,
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public setMaxZoom(max: number): ILayer {
|
||||
this.maxZoom = max;
|
||||
public setMaxZoom(maxZoom: number): ILayer {
|
||||
this.updateLayerConfig({
|
||||
maxZoom,
|
||||
});
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
|
@ -376,7 +435,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
public fitBounds(): void {
|
||||
const source = this.getSource();
|
||||
const extent = source.extent;
|
||||
this.map.fitBounds([
|
||||
this.mapService.fitBounds([
|
||||
[extent[0], extent[1]],
|
||||
[extent[2], extent[3]],
|
||||
]);
|
||||
|
@ -391,6 +450,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
this.models.forEach((model) => model.destroy());
|
||||
|
||||
this.hooks.afterDestroy.call();
|
||||
|
||||
// 解绑图层容器中的服务
|
||||
// this.container.unbind(TYPES.IStyleAttributeService);
|
||||
}
|
||||
|
||||
public isDirty() {
|
||||
|
@ -411,9 +473,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
return this.layerSource;
|
||||
}
|
||||
|
||||
public getStyleOptions() {
|
||||
return this.styleOptions;
|
||||
}
|
||||
public getScaleOptions() {
|
||||
return this.scaleOptions;
|
||||
}
|
||||
|
@ -458,7 +517,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
});
|
||||
const { vs, fs, uniforms } = this.shaderModuleService.getModule(moduleName);
|
||||
const { createModel } = this.rendererService;
|
||||
const parserData = this.getSource().data.dataArray;
|
||||
|
||||
const {
|
||||
attributes,
|
||||
elements,
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
import {
|
||||
AttributeType,
|
||||
gl,
|
||||
ICameraService,
|
||||
IEncodeFeature,
|
||||
IFontService,
|
||||
IGlobalConfigService,
|
||||
IIconService,
|
||||
ILayer,
|
||||
ILayerModel,
|
||||
ILayerPlugin,
|
||||
ILogService,
|
||||
IMapService,
|
||||
IModel,
|
||||
IModelUniform,
|
||||
|
@ -18,11 +13,9 @@ import {
|
|||
IStyleAttributeService,
|
||||
lazyInject,
|
||||
TYPES,
|
||||
} from '@l7/core';
|
||||
} from '@antv/l7-core';
|
||||
|
||||
export default class BaseModel implements ILayerModel {
|
||||
@lazyInject(TYPES.IStyleAttributeService)
|
||||
public styleAttributeService: IStyleAttributeService;
|
||||
protected layer: ILayer;
|
||||
|
||||
@lazyInject(TYPES.IGlobalConfigService)
|
||||
|
@ -34,20 +27,26 @@ export default class BaseModel implements ILayerModel {
|
|||
@lazyInject(TYPES.IFontService)
|
||||
protected readonly fontService: IFontService;
|
||||
|
||||
@lazyInject(TYPES.IRendererService)
|
||||
protected readonly rendererService: IRendererService;
|
||||
|
||||
@lazyInject(TYPES.IShaderModuleService)
|
||||
protected readonly shaderModuleService: IShaderModuleService;
|
||||
|
||||
@lazyInject(TYPES.IMapService)
|
||||
protected readonly map: IMapService;
|
||||
|
||||
@lazyInject(TYPES.ICameraService)
|
||||
protected readonly camera: ICameraService;
|
||||
protected rendererService: IRendererService;
|
||||
protected styleAttributeService: IStyleAttributeService;
|
||||
protected mapService: IMapService;
|
||||
protected cameraService: ICameraService;
|
||||
|
||||
constructor(layer: ILayer) {
|
||||
this.layer = layer;
|
||||
this.rendererService = layer
|
||||
.getContainer()
|
||||
.get<IRendererService>(TYPES.IRendererService);
|
||||
this.styleAttributeService = layer
|
||||
.getContainer()
|
||||
.get<IStyleAttributeService>(TYPES.IStyleAttributeService);
|
||||
this.mapService = layer.getContainer().get<IMapService>(TYPES.IMapService);
|
||||
this.cameraService = layer
|
||||
.getContainer()
|
||||
.get<ICameraService>(TYPES.ICameraService);
|
||||
this.registerBuiltinAttributes();
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { lngLatToMeters } from '@l7/utils';
|
||||
import { lngLatToMeters } from '@antv/l7-utils';
|
||||
import earcut from 'earcut';
|
||||
import { vec3 } from 'gl-matrix';
|
||||
import { IPath } from './Path';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { IEncodeFeature } from '@l7/core';
|
||||
import { aProjectFlat, lngLatToMeters } from '@l7/utils';
|
||||
import { IEncodeFeature } from '@antv/l7-core';
|
||||
import { aProjectFlat, lngLatToMeters } from '@antv/l7-utils';
|
||||
import earcut from 'earcut';
|
||||
import { vec3 } from 'gl-matrix';
|
||||
import getNormals from '../utils/polylineNormal';
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
declare module '*.glsl' {
|
||||
const content: string;
|
||||
// @ts-ignore
|
||||
export default content;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { AttributeType, gl, IEncodeFeature, ILayer } from '@l7/core';
|
||||
import { AttributeType, gl, IEncodeFeature, ILayer } from '@antv/l7-core';
|
||||
import BaseLayer from '../core/BaseLayer';
|
||||
import HeatMapModels, { HeatMapModelType } from './models';
|
||||
interface IPointLayerStyleOptions {
|
||||
|
@ -41,7 +41,7 @@ export default class HeatMapLayer extends BaseLayer<IPointLayerStyleOptions> {
|
|||
const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute(
|
||||
'shape',
|
||||
);
|
||||
const { shape3d } = this.configService.getConfig();
|
||||
const { shape3d } = this.getLayerConfig();
|
||||
const source = this.getSource();
|
||||
const sourceType = source.data.type;
|
||||
const shape =
|
||||
|
|
|
@ -2,12 +2,10 @@ import {
|
|||
AttributeType,
|
||||
gl,
|
||||
IEncodeFeature,
|
||||
ILayer,
|
||||
ILayerModel,
|
||||
IModel,
|
||||
IModelUniform,
|
||||
} from '@l7/core';
|
||||
import BaseModel from '../../core/baseModel';
|
||||
} from '@antv/l7-core';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import { HeatmapGridTriangulation } from '../../core/triangulation';
|
||||
import heatmapGridVert from '../shaders/grid_vert.glsl';
|
||||
import heatmapGridFrag from '../shaders/hexagon_frag.glsl';
|
||||
|
@ -20,7 +18,7 @@ export default class GridModel extends BaseModel {
|
|||
const {
|
||||
opacity,
|
||||
coverage,
|
||||
} = this.layer.getStyleOptions() as IHeatMapLayerStyleOptions;
|
||||
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
|
||||
return {
|
||||
u_opacity: opacity || 1.0,
|
||||
u_coverage: coverage || 0.9,
|
||||
|
@ -45,7 +43,7 @@ export default class GridModel extends BaseModel {
|
|||
}
|
||||
protected registerBuiltinAttributes() {
|
||||
// point layer size;
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
@ -70,7 +68,7 @@ export default class GridModel extends BaseModel {
|
|||
});
|
||||
|
||||
// point layer size;
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'pos', // 顶点经纬度位置
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
|
|
@ -2,12 +2,10 @@ import {
|
|||
AttributeType,
|
||||
gl,
|
||||
IEncodeFeature,
|
||||
ILayer,
|
||||
ILayerModel,
|
||||
IModel,
|
||||
IModelUniform,
|
||||
} from '@l7/core';
|
||||
import BaseModel from '../../core/baseModel';
|
||||
} from '@antv/l7-core';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import { PointExtrudeTriangulation } from '../../core/triangulation';
|
||||
import heatmapGrid3dVert from '../shaders/hexagon_3d_vert.glsl';
|
||||
import heatmapGridFrag from '../shaders/hexagon_frag.glsl';
|
||||
|
@ -21,7 +19,7 @@ export default class Grid3DModel extends BaseModel {
|
|||
const {
|
||||
opacity,
|
||||
coverage,
|
||||
} = this.layer.getStyleOptions() as IHeatMapLayerStyleOptions;
|
||||
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
|
||||
return {
|
||||
u_opacity: opacity || 1.0,
|
||||
u_coverage: coverage || 1.0,
|
||||
|
@ -45,7 +43,7 @@ export default class Grid3DModel extends BaseModel {
|
|||
}
|
||||
protected registerBuiltinAttributes() {
|
||||
// point layer size;
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
@ -70,7 +68,7 @@ export default class Grid3DModel extends BaseModel {
|
|||
});
|
||||
|
||||
// point layer size;
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'normal',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
@ -93,7 +91,7 @@ export default class Grid3DModel extends BaseModel {
|
|||
},
|
||||
},
|
||||
});
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'pos', // 顶点经纬度位置
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
import {
|
||||
AttributeType,
|
||||
gl,
|
||||
ICameraService,
|
||||
IEncodeFeature,
|
||||
IFramebuffer,
|
||||
ILayer,
|
||||
ILayerModel,
|
||||
IModel,
|
||||
IModelUniform,
|
||||
ITexture2D,
|
||||
lazyInject,
|
||||
TYPES,
|
||||
} from '@l7/core';
|
||||
} from '@antv/l7-core';
|
||||
import { mat4 } from 'gl-matrix';
|
||||
import BaseModel from '../../core/baseModel';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import { HeatmapTriangulation } from '../../core/triangulation';
|
||||
import { generateColorRamp, IColorRamp } from '../../utils/color';
|
||||
import heatmap3DFrag from '../shaders/heatmap_3d_frag.glsl';
|
||||
|
@ -64,7 +59,7 @@ export default class HeatMapModel extends BaseModel {
|
|||
createTexture2D,
|
||||
useFramebuffer,
|
||||
} = this.rendererService;
|
||||
const shapeAttr = this.layer.styleAttributeService.getLayerStyleAttribute(
|
||||
const shapeAttr = this.styleAttributeService.getLayerStyleAttribute(
|
||||
'shape',
|
||||
);
|
||||
const shapeType = shapeAttr?.scale?.field || 'heatmap';
|
||||
|
@ -79,7 +74,7 @@ export default class HeatMapModel extends BaseModel {
|
|||
|
||||
const {
|
||||
rampColors,
|
||||
} = this.layer.getStyleOptions() as IHeatMapLayerStyleOptions;
|
||||
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
|
||||
const imageData = generateColorRamp(rampColors as IColorRamp);
|
||||
const { width, height } = getViewportSize();
|
||||
|
||||
|
@ -111,7 +106,7 @@ export default class HeatMapModel extends BaseModel {
|
|||
return [this.intensityModel, this.colorModel];
|
||||
}
|
||||
protected registerBuiltinAttributes() {
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'dir',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
@ -135,7 +130,7 @@ export default class HeatMapModel extends BaseModel {
|
|||
});
|
||||
|
||||
// point layer size;
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
@ -243,7 +238,7 @@ export default class HeatMapModel extends BaseModel {
|
|||
opacity,
|
||||
intensity = 10,
|
||||
radius = 5,
|
||||
} = this.layer.getStyleOptions() as IHeatMapLayerStyleOptions;
|
||||
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
|
||||
this.intensityModel.draw({
|
||||
uniforms: {
|
||||
u_opacity: opacity || 1.0,
|
||||
|
@ -256,7 +251,7 @@ export default class HeatMapModel extends BaseModel {
|
|||
private drawColorMode() {
|
||||
const {
|
||||
opacity,
|
||||
} = this.layer.getStyleOptions() as IHeatMapLayerStyleOptions;
|
||||
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
|
||||
this.colorModel.draw({
|
||||
uniforms: {
|
||||
u_opacity: opacity || 1.0,
|
||||
|
@ -269,11 +264,11 @@ export default class HeatMapModel extends BaseModel {
|
|||
private draw3DHeatMap() {
|
||||
const {
|
||||
opacity,
|
||||
} = this.layer.getStyleOptions() as IHeatMapLayerStyleOptions;
|
||||
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
|
||||
const invert = mat4.invert(
|
||||
mat4.create(),
|
||||
// @ts-ignore
|
||||
mat4.fromValues(...this.camera.getViewProjectionMatrix()),
|
||||
mat4.fromValues(...this.cameraService.getViewProjectionMatrix()),
|
||||
) as mat4;
|
||||
this.colorModel.draw({
|
||||
uniforms: {
|
||||
|
|
|
@ -4,8 +4,8 @@ import {
|
|||
IEncodeFeature,
|
||||
IModel,
|
||||
IModelUniform,
|
||||
} from '@l7/core';
|
||||
import BaseModel from '../../core/baseModel';
|
||||
} from '@antv/l7-core';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import { HeatmapGridTriangulation } from '../../core/triangulation';
|
||||
import heatmapGridFrag from '../shaders/hexagon_frag.glsl';
|
||||
import heatmapGridVert from '../shaders/hexagon_vert.glsl';
|
||||
|
@ -20,7 +20,7 @@ export default class HexagonModel extends BaseModel {
|
|||
const {
|
||||
opacity,
|
||||
coverage,
|
||||
} = this.layer.getStyleOptions() as IHeatMapLayerStyleOptions;
|
||||
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
|
||||
return {
|
||||
u_opacity: opacity || 1.0,
|
||||
u_coverage: coverage || 0.9,
|
||||
|
@ -45,7 +45,7 @@ export default class HexagonModel extends BaseModel {
|
|||
}
|
||||
protected registerBuiltinAttributes() {
|
||||
// point layer size;
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'size',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
@ -70,7 +70,7 @@ export default class HexagonModel extends BaseModel {
|
|||
});
|
||||
|
||||
// point layer size;
|
||||
this.layer.styleAttributeService.registerStyleAttribute({
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'pos', // 顶点经纬度位置
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
|
|
|
@ -13,6 +13,8 @@ varying vec4 v_color;
|
|||
|
||||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "picking"
|
||||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
|
||||
|
@ -21,4 +23,6 @@ void main() {
|
|||
// vec2 lnglat = unProjectFlat(a_Pos.xy);
|
||||
vec4 project_pos = project_position(vec4(a_Pos.xy + offset, 0, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(project_pos);
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -16,14 +16,16 @@ varying vec4 v_color;
|
|||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "light"
|
||||
void main() {
|
||||
#pragma include "picking"
|
||||
|
||||
void main() {
|
||||
mat2 rotationMatrix = mat2(cos(u_angle), sin(u_angle), -sin(u_angle), cos(u_angle));
|
||||
vec2 offset =(vec2(a_Position.xy * u_radius * rotationMatrix * u_coverage));
|
||||
vec2 lnglat = unProjectFlat(a_Pos.xy + offset);
|
||||
vec4 project_pos = project_position(vec4(lnglat, a_Position.z * project_pixel(a_Size), 1.0));
|
||||
vec4 project_pos = project_position(vec4(lnglat, a_Position.z * a_Size, 1.0));
|
||||
float lightWeight = calc_lighting(project_pos);
|
||||
v_color =vec4(a_Color.rgb*lightWeight, a_Color.w);
|
||||
|
||||
gl_Position = project_common_position_to_clipspace(project_pos);
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
precision highp float;
|
||||
varying vec4 v_color;
|
||||
uniform float u_opacity: 1;
|
||||
|
||||
#pragma include "picking"
|
||||
|
||||
void main() {
|
||||
gl_FragColor = v_color;
|
||||
gl_FragColor.a *= u_opacity;
|
||||
|
||||
gl_FragColor = filterColor(gl_FragColor);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue