mirror of https://gitee.com/antv-l7/antv-l7
commit
cf7bd082fe
|
@ -78,3 +78,4 @@ git_log.sh
|
||||||
node_modules/
|
node_modules/
|
||||||
packages/l7/package_bak.json
|
packages/l7/package_bak.json
|
||||||
|
|
||||||
|
stories/Test
|
||||||
|
|
|
@ -25,6 +25,14 @@ shape 支持
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## source
|
||||||
|
|
||||||
|
点数据类型,根据经纬点绘制图形,目前支持三种数据结构
|
||||||
|
|
||||||
|
- [GeoJOSN]('../source/geojson/#point')
|
||||||
|
- [CSV]()
|
||||||
|
- [JSON](../source/json/#点数据)
|
||||||
|
|
||||||
**图片标注**
|
**图片标注**
|
||||||
|
|
||||||
通过 `Scene.addImage()` 可以添加图片资源,
|
通过 `Scene.addImage()` 可以添加图片资源,
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
title: CSV
|
||||||
|
order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
L7 支持 CSV 以逗号分隔的 CSV 数据加载。
|
||||||
|
|
||||||
|
CSV 是文本数据结构,很难表达复杂的地理数据结构,因此 CSV 仅支持两种数据结构
|
||||||
|
|
||||||
|
- 点数据 需要指定经度,纬度坐标
|
||||||
|
- 线段,弧线数据 需要指定 起始点的 经度,纬度坐标
|
||||||
|
|
||||||
|
## parser
|
||||||
|
|
||||||
|
- type string 必选 json
|
||||||
|
- x string 点数据表示 经度
|
||||||
|
- y string 点数据表示 纬度
|
||||||
|
- x1 string 经度
|
||||||
|
- x2 string 纬度
|
||||||
|
|
||||||
|
### 点数据通过 CSV 加载
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
layer.source(data, {
|
||||||
|
parser: {
|
||||||
|
type: 'csv',
|
||||||
|
x: 'lng',
|
||||||
|
y: 'lat',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
[CSV 数据 demo 示例](../../../examples/point/bubble#scatter)
|
||||||
|
|
||||||
|
### 线段弧线数据通过 CSV 加载
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
layer.source(
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
parser:{
|
||||||
|
type:'csv',
|
||||||
|
x:'lng1',
|
||||||
|
y:'lat1' ,
|
||||||
|
x1:'lng1',
|
||||||
|
y1:'lat2' ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
[CSV 线段数据 demo 示例](../../../examples/gallery/basic#arcCircle)
|
|
@ -0,0 +1,53 @@
|
||||||
|
---
|
||||||
|
title: CSV
|
||||||
|
order: 3
|
||||||
|
---
|
||||||
|
|
||||||
|
L7 支持 CSV 以逗号分隔的 CSV 数据加载。
|
||||||
|
|
||||||
|
CSV 是文本数据结构,很难表达复杂的地理数据结构,因此 CSV 仅支持两种数据结构
|
||||||
|
|
||||||
|
- 点数据 需要指定经度,纬度坐标
|
||||||
|
- 线段,弧线数据 需要指定 起始点的 经度,纬度坐标
|
||||||
|
|
||||||
|
## parser
|
||||||
|
|
||||||
|
- type string 必选 json
|
||||||
|
- x string 点数据表示 经度
|
||||||
|
- y string 点数据表示 纬度
|
||||||
|
- x1 string 经度
|
||||||
|
- x2 string 纬度
|
||||||
|
|
||||||
|
### 点数据通过 CSV 加载
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
layer.source(data, {
|
||||||
|
parser: {
|
||||||
|
type: 'csv',
|
||||||
|
x: 'lng',
|
||||||
|
y: 'lat',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
[CSV 数据 demo 示例](../../../examples/point/bubble#scatter)
|
||||||
|
|
||||||
|
### 线段弧线数据通过 CSV 加载
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
layer.source(
|
||||||
|
data,
|
||||||
|
{
|
||||||
|
parser:{
|
||||||
|
type:'csv',
|
||||||
|
x:'lng1',
|
||||||
|
y:'lat1' ,
|
||||||
|
x1:'lng1',
|
||||||
|
y1:'lat2' ,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
[CSV 线段数据 demo 示例](../../../examples/gallery/basic#arcCircle)
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
title: Image
|
||||||
|
order: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
Image 数据主要用于在地图根据经纬度范围添加图图片,不如一幅纸制地图扫描版你要放在地图显示。
|
||||||
|
|
||||||
|
## parser
|
||||||
|
|
||||||
|
- type: image
|
||||||
|
- extent: 图像的经纬度范围 [minlng, minlat,maxLng, maxLat]
|
||||||
|
|
||||||
|
根据图片的经纬度范围,将图片添加到地图上。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
layer.source(
|
||||||
|
'https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg',
|
||||||
|
{
|
||||||
|
parser: {
|
||||||
|
type: 'image',
|
||||||
|
extent: [121.168, 30.2828, 121.384, 30.4219],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
```
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
title: Image
|
||||||
|
order: 4
|
||||||
|
---
|
||||||
|
|
||||||
|
Image 数据主要用于在地图根据经纬度范围添加图图片,不如一幅纸制地图扫描版你要放在地图显示。
|
||||||
|
|
||||||
|
## parser
|
||||||
|
|
||||||
|
- type: image
|
||||||
|
- extent: 图像的经纬度范围 [minlng, minlat,maxLng, maxLat]
|
||||||
|
|
||||||
|
根据图片的经纬度范围,将图片添加到地图上。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
layer.source(
|
||||||
|
'https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg',
|
||||||
|
{
|
||||||
|
parser: {
|
||||||
|
type: 'image',
|
||||||
|
extent: [121.168, 30.2828, 121.384, 30.4219],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
```
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
title: JSON
|
title: JSON
|
||||||
order: 1
|
order: 2
|
||||||
---
|
---
|
||||||
|
|
||||||
GeoJSON 虽然是通用的的地理数据格式,在具体使用场景中,数据服务人员可能并不熟悉 GeoJON,或者没有生成 GeoJON 的工具, 因此 L7 对数据定义了 Parser 的概念,你的数据可以是任何格式,使用指定数据对应的地理信息字段即可。
|
GeoJSON 虽然是通用的的地理数据格式,在具体使用场景中,数据服务人员可能并不熟悉 GeoJON,或者没有生成 GeoJON 的工具, 因此 L7 对数据定义了 Parser 的概念,你的数据可以是任何格式,使用指定数据对应的地理信息字段即可。
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
title: JSON
|
title: JSON
|
||||||
order: 1
|
order: 2
|
||||||
---
|
---
|
||||||
|
|
||||||
GeoJSON 虽然是通用的的地理数据格式,在具体使用场景中,数据服务人员可能并不熟悉 GeoJON,或者没有生成 GeoJON 的工具, 因此 L7 对数据定义了 Parser 的概念,你的数据可以是任何格式,使用指定数据对应的地理信息字段即可。
|
GeoJSON 虽然是通用的的地理数据格式,在具体使用场景中,数据服务人员可能并不熟悉 GeoJON,或者没有生成 GeoJON 的工具, 因此 L7 对数据定义了 Parser 的概念,你的数据可以是任何格式,使用指定数据对应的地理信息字段即可。
|
||||||
|
@ -39,6 +39,8 @@ layer.source(data, {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[JOSN 数据 demo 示例](../../../examples/gallery/basic)
|
||||||
|
|
||||||
### 通用解析方式
|
### 通用解析方式
|
||||||
|
|
||||||
可也解析任意复杂的点,线面
|
可也解析任意复杂的点,线面
|
||||||
|
|
|
@ -40,100 +40,25 @@ layer.source(data);
|
||||||
|
|
||||||
#### JSON
|
#### JSON
|
||||||
|
|
||||||
[JSON 数据格式解析](../json)
|
[JSON 数据格式解析](./json)
|
||||||
|
|
||||||
#### csv
|
#### csv
|
||||||
|
|
||||||
点,线数据配置项同 json 数据类型
|
[CSV 数据格式解析](./csv)
|
||||||
|
|
||||||
```javascript
|
栅格数据类型
|
||||||
layer.source(data, {
|
|
||||||
parser: {
|
|
||||||
type: 'csv',
|
|
||||||
x: 'lng1',
|
|
||||||
y: 'lat1',
|
|
||||||
x1: 'lng1',
|
|
||||||
y1: 'lat2',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
**栅格数据类型 **
|
|
||||||
|
|
||||||
#### image
|
#### image
|
||||||
|
|
||||||
根据图片的经纬度范围,将图片添加到地图上。 配置项
|
[Image 数据格式解析](./image)
|
||||||
|
|
||||||
- type: image
|
|
||||||
- extent: 图像的经纬度范围 []
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
layer.source(
|
|
||||||
'https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg',
|
|
||||||
{
|
|
||||||
parser: {
|
|
||||||
type: 'image',
|
|
||||||
extent: [121.168, 30.2828, 121.384, 30.4219],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### raster
|
|
||||||
|
|
||||||
栅格数据类型,主要表示遥感数据类型 data 栅格数据的二维矩阵数据 parser 配置项
|
|
||||||
|
|
||||||
- type raster
|
|
||||||
- width 数据宽度二维矩阵 columns
|
|
||||||
- height 数据高度
|
|
||||||
- min 数据最大值
|
|
||||||
- max 数据最小值
|
|
||||||
- extent 经纬度范围
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
source(values, {
|
|
||||||
parser: {
|
|
||||||
type: 'raster',
|
|
||||||
width: n,
|
|
||||||
height: m,
|
|
||||||
min: 0,
|
|
||||||
max: 8000,
|
|
||||||
extent: [73.482190241, 3.82501784112, 135.106618732, 57.6300459963],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### transforms
|
### transforms
|
||||||
|
|
||||||
目前支持三种数据处理方法 map,grid,hexagon transform 配置项
|
目前支持两种热力图使用的数据处理方法 grid,hexagon transform 配置项
|
||||||
|
|
||||||
- type 数据处理类型
|
- type 数据处理类型
|
||||||
- tansform cfg 数据处理配置项
|
- tansform cfg 数据处理配置项
|
||||||
|
|
||||||
#### map
|
|
||||||
|
|
||||||
数据处理,支持自定义 callback 函数
|
|
||||||
|
|
||||||
- callback:function 回调函数
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
layer.source(data, {
|
|
||||||
transforms: [
|
|
||||||
{
|
|
||||||
type: 'map',
|
|
||||||
callback: function(item) {
|
|
||||||
const [x, y] = item.coordinates;
|
|
||||||
item.lat = item.lat * 1;
|
|
||||||
item.lng = item.lng * 1;
|
|
||||||
item.v = item.v * 1;
|
|
||||||
item.coordinates = [x * 1, y * 1];
|
|
||||||
return item;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### grid
|
#### grid
|
||||||
|
|
||||||
生成方格网布局,根据数据字段统计,主要在网格热力图中使用
|
生成方格网布局,根据数据字段统计,主要在网格热力图中使用
|
||||||
|
@ -163,4 +88,4 @@ layer.source(data, {
|
||||||
- type: 'hexagon',
|
- type: 'hexagon',
|
||||||
- size: 网格半径
|
- size: 网格半径
|
||||||
- field: 数据统计字段
|
- field: 数据统计字段
|
||||||
- method:聚合方法 count,max,min,sum,mean5 个统计维度
|
- method:聚合方法 count,max,min,sum,mean 5 个统计维度
|
||||||
|
|
|
@ -7,6 +7,13 @@ order: 0
|
||||||
|
|
||||||
source 地理数据处理模块,主要包含数据解析(parser),和数据处理(transform);
|
source 地理数据处理模块,主要包含数据解析(parser),和数据处理(transform);
|
||||||
|
|
||||||
|
- data
|
||||||
|
- option
|
||||||
|
- cluster **boolean** 是否聚合
|
||||||
|
- clusterOption 聚合配置项
|
||||||
|
- parser 数据解析配置
|
||||||
|
- transforms 数据处理配置
|
||||||
|
|
||||||
### parser
|
### parser
|
||||||
|
|
||||||
不同数据类型处理成统一数据格式。矢量数据包括 GeoJON, CSV,Json 等不同数据格式,栅格数据,包括 Raster,Image 数据。将来还会支持瓦片格式数据。
|
不同数据类型处理成统一数据格式。矢量数据包括 GeoJON, CSV,Json 等不同数据格式,栅格数据,包括 Raster,Image 数据。将来还会支持瓦片格式数据。
|
||||||
|
@ -23,6 +30,14 @@ source 地理数据处理模块,主要包含数据解析(parser),和数据
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|
||||||
|
### cluster 可选 可以只设置 cluster
|
||||||
|
|
||||||
|
### clusterOption 可选
|
||||||
|
|
||||||
|
- radius 聚合半径 **number** default 40
|
||||||
|
- minZoom: 最小聚合缩放等级 **number** default 0
|
||||||
|
- maxZoom: 最大聚合缩放等级 **number** default 16
|
||||||
|
|
||||||
### parser
|
### parser
|
||||||
|
|
||||||
**配置项**
|
**配置项**
|
||||||
|
@ -40,100 +55,25 @@ layer.source(data);
|
||||||
|
|
||||||
#### JSON
|
#### JSON
|
||||||
|
|
||||||
[JSON 数据格式解析](../json)
|
[JSON 数据格式解析](./json)
|
||||||
|
|
||||||
#### csv
|
#### csv
|
||||||
|
|
||||||
点,线数据配置项同 json 数据类型
|
[CSV 数据格式解析](./csv)
|
||||||
|
|
||||||
```javascript
|
栅格数据类型
|
||||||
layer.source(data, {
|
|
||||||
parser: {
|
|
||||||
type: 'csv',
|
|
||||||
x: 'lng1',
|
|
||||||
y: 'lat1',
|
|
||||||
x1: 'lng1',
|
|
||||||
y1: 'lat2',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
**栅格数据类型 **
|
|
||||||
|
|
||||||
#### image
|
#### image
|
||||||
|
|
||||||
根据图片的经纬度范围,将图片添加到地图上。 配置项
|
[Image 数据格式解析](./image)
|
||||||
|
|
||||||
- type: image
|
|
||||||
- extent: 图像的经纬度范围 []
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
layer.source(
|
|
||||||
'https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg',
|
|
||||||
{
|
|
||||||
parser: {
|
|
||||||
type: 'image',
|
|
||||||
extent: [121.168, 30.2828, 121.384, 30.4219],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### raster
|
|
||||||
|
|
||||||
栅格数据类型,主要表示遥感数据类型 data 栅格数据的二维矩阵数据 parser 配置项
|
|
||||||
|
|
||||||
- type raster
|
|
||||||
- width 数据宽度二维矩阵 columns
|
|
||||||
- height 数据高度
|
|
||||||
- min 数据最大值
|
|
||||||
- max 数据最小值
|
|
||||||
- extent 经纬度范围
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
source(values, {
|
|
||||||
parser: {
|
|
||||||
type: 'raster',
|
|
||||||
width: n,
|
|
||||||
height: m,
|
|
||||||
min: 0,
|
|
||||||
max: 8000,
|
|
||||||
extent: [73.482190241, 3.82501784112, 135.106618732, 57.6300459963],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### transforms
|
### transforms
|
||||||
|
|
||||||
目前支持三种数据处理方法 map,grid,hexagon transform 配置项
|
目前支持两种热力图使用的数据处理方法 grid,hexagon transform 配置项
|
||||||
|
|
||||||
- type 数据处理类型
|
- type 数据处理类型
|
||||||
- tansform cfg 数据处理配置项
|
- tansform cfg 数据处理配置项
|
||||||
|
|
||||||
#### map
|
|
||||||
|
|
||||||
数据处理,支持自定义 callback 函数
|
|
||||||
|
|
||||||
- callback:function 回调函数
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
layer.source(data, {
|
|
||||||
transforms: [
|
|
||||||
{
|
|
||||||
type: 'map',
|
|
||||||
callback: function(item) {
|
|
||||||
const [x, y] = item.coordinates;
|
|
||||||
item.lat = item.lat * 1;
|
|
||||||
item.lng = item.lng * 1;
|
|
||||||
item.v = item.v * 1;
|
|
||||||
item.coordinates = [x * 1, y * 1];
|
|
||||||
return item;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### grid
|
#### grid
|
||||||
|
|
||||||
生成方格网布局,根据数据字段统计,主要在网格热力图中使用
|
生成方格网布局,根据数据字段统计,主要在网格热力图中使用
|
||||||
|
|
|
@ -15,8 +15,11 @@ Current version: ![L7 2.0版本号](https://badgen.net/npm/v/@antv/l7/beta)
|
||||||
|
|
||||||
Include the L7 JS JavaScript <head> of your HTML file.
|
Include the L7 JS JavaScript <head> of your HTML file.
|
||||||
|
|
||||||
|
:warning: 如果需要引用第三方地图API,请确保在先引入第三方API,然后引入L7
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<head>
|
<head>
|
||||||
|
<! --引入第三方地图JSAPI-->
|
||||||
<script src='https://gw.alipayobjects.com/os/antv/pkg/_antv.l7-2.0.0-beta.19/dist/l7.js'>
|
<script src='https://gw.alipayobjects.com/os/antv/pkg/_antv.l7-2.0.0-beta.19/dist/l7.js'>
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -41,6 +44,7 @@ npm install --save @antv/l7-maps;
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### 初始化地图
|
### 初始化地图
|
||||||
|
|
||||||
#### 使用 高德 底图
|
#### 使用 高德 底图
|
||||||
|
@ -80,3 +84,76 @@ const scene = new Scene({
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### React中使用
|
||||||
|
|
||||||
|
React 组件待开发,期待和大家共建l7-react 目前可以暂时以 Submodule 方式使用
|
||||||
|
|
||||||
|
```
|
||||||
|
import { Scene, PolygonLayer } from '@antv/l7';
|
||||||
|
import { AMap } from '@antv/l7-maps';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export default class AMapExample extends React.Component {
|
||||||
|
private scene: Scene;
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
this.scene.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async componentDidMount() {
|
||||||
|
const response = await fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json',
|
||||||
|
);
|
||||||
|
const scene = new Scene({
|
||||||
|
id: 'map',
|
||||||
|
map: new AMap({
|
||||||
|
center: [110.19382669582967, 50.258134],
|
||||||
|
pitch: 0,
|
||||||
|
style: 'dark',
|
||||||
|
zoom: 3,
|
||||||
|
token: 'pg.xxx', // 高德或者 Mapbox 的 token
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const layer = new PolygonLayer({});
|
||||||
|
|
||||||
|
layer
|
||||||
|
.source(await response.json())
|
||||||
|
.size('name', [0, 10000, 50000, 30000, 100000])
|
||||||
|
.color('name', [
|
||||||
|
'#2E8AE6',
|
||||||
|
'#69D1AB',
|
||||||
|
'#DAF291',
|
||||||
|
'#FFD591',
|
||||||
|
'#FF7A45',
|
||||||
|
'#CF1D49',
|
||||||
|
])
|
||||||
|
.shape('fill')
|
||||||
|
.style({
|
||||||
|
opacity: 0.8,
|
||||||
|
});
|
||||||
|
scene.addLayer(layer);
|
||||||
|
this.scene = scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id="map"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
⚠️组件 Unmount 时需要通过 scene.destroy() 手动销毁场景。
|
||||||
|
|
||||||
|
更多React使用 [示例查看](https://github.com/antvis/L7/tree/master/stories)
|
||||||
|
|
||||||
|
### Vue 欢迎补充
|
|
@ -44,67 +44,71 @@ const scene = new Scene({
|
||||||
zoom: 3.802
|
zoom: 3.802
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
Promise.all([
|
addChart();
|
||||||
fetch(
|
scene.render();
|
||||||
'https://gw.alipayobjects.com/os/basement_prod/5b772136-a1f4-4fc5-9a80-9f9974b4b182.json'
|
function addChart() {
|
||||||
).then(d => d.json()),
|
Promise.all([
|
||||||
fetch(
|
fetch(
|
||||||
'https://gw.alipayobjects.com/os/basement_prod/f3c467a4-9ae0-4f08-bb5f-11f9c869b2cb.json'
|
'https://gw.alipayobjects.com/os/basement_prod/5b772136-a1f4-4fc5-9a80-9f9974b4b182.json'
|
||||||
).then(d => d.json())
|
).then(d => d.json()),
|
||||||
]).then(function onLoad([ center, population ]) {
|
fetch(
|
||||||
const popobj = {};
|
'https://gw.alipayobjects.com/os/basement_prod/f3c467a4-9ae0-4f08-bb5f-11f9c869b2cb.json'
|
||||||
population.forEach(element => {
|
).then(d => d.json())
|
||||||
popobj[element.Code] =
|
]).then(function onLoad([ center, population ]) {
|
||||||
element['Population, female (% of total) (% of total)'];
|
const popobj = {};
|
||||||
});
|
population.forEach(element => {
|
||||||
// 数据绑定
|
popobj[element.Code] =
|
||||||
|
element['Population, female (% of total) (% of total)'];
|
||||||
|
});
|
||||||
|
// 数据绑定
|
||||||
|
|
||||||
center.features = center.features.map(fe => {
|
center.features = center.features.map(fe => {
|
||||||
fe.properties.female = popobj[fe.properties.id] * 1 || 0;
|
fe.properties.female = popobj[fe.properties.id] * 1 || 0;
|
||||||
return fe;
|
return fe;
|
||||||
});
|
});
|
||||||
center.features.forEach(point => {
|
center.features.forEach(point => {
|
||||||
const el = document.createElement('div');
|
const el = document.createElement('div');
|
||||||
const coord = point.geometry.coordinates;
|
const coord = point.geometry.coordinates;
|
||||||
const v = point.properties.female * 1;
|
const v = point.properties.female * 1;
|
||||||
if (v < 1 || (v > 46 && v < 54)) {
|
if (v < 1 || (v > 46 && v < 54)) {
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
const size = 60;
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
type: '男性',
|
|
||||||
value: 100.0 - v.toFixed(2)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: '女性',
|
|
||||||
value: v.toFixed(2) * 1
|
|
||||||
}
|
}
|
||||||
];
|
const size = 60;
|
||||||
const chart = new G2.Chart({
|
const data = [
|
||||||
container: el,
|
{
|
||||||
width: size,
|
type: '男性',
|
||||||
height: size,
|
value: 100.0 - v.toFixed(2)
|
||||||
render: 'svg',
|
},
|
||||||
padding: 0
|
{
|
||||||
|
type: '女性',
|
||||||
|
value: v.toFixed(2) * 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const chart = new G2.Chart({
|
||||||
|
container: el,
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
render: 'svg',
|
||||||
|
padding: 0
|
||||||
|
});
|
||||||
|
chart.source(data);
|
||||||
|
chart.legend(false);
|
||||||
|
chart.tooltip(false);
|
||||||
|
chart.coord('theta', {
|
||||||
|
radius: 0.9,
|
||||||
|
innerRadius: 0.6
|
||||||
|
});
|
||||||
|
chart
|
||||||
|
.intervalStack()
|
||||||
|
.position('value')
|
||||||
|
.color('type', [ '#5CCEA1', '#5B8FF9' ])
|
||||||
|
.opacity(1);
|
||||||
|
chart.render();
|
||||||
|
const marker = new Marker({ element: el }).setLnglat({
|
||||||
|
lng: coord[0],
|
||||||
|
lat: coord[1]
|
||||||
|
});
|
||||||
|
scene.addMarker(marker);
|
||||||
});
|
});
|
||||||
chart.source(data);
|
|
||||||
chart.legend(false);
|
|
||||||
chart.tooltip(false);
|
|
||||||
chart.coord('theta', {
|
|
||||||
radius: 0.9,
|
|
||||||
innerRadius: 0.6
|
|
||||||
});
|
|
||||||
chart
|
|
||||||
.intervalStack()
|
|
||||||
.position('value')
|
|
||||||
.color('type', [ '#5CCEA1', '#5B8FF9' ])
|
|
||||||
.opacity(1);
|
|
||||||
chart.render();
|
|
||||||
const marker = new Marker({ element: el }).setLnglat({
|
|
||||||
lng: coord[0],
|
|
||||||
lat: coord[1]
|
|
||||||
});
|
|
||||||
scene.addMarker(marker);
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default class MarkerService implements IMarkerService {
|
||||||
private markers: IMarker[] = [];
|
private markers: IMarker[] = [];
|
||||||
private unAddMarkers: IMarker[] = [];
|
private unAddMarkers: IMarker[] = [];
|
||||||
public addMarker(marker: IMarker): void {
|
public addMarker(marker: IMarker): void {
|
||||||
if (!this.mapsService.map && this.mapsService.getMarkerContainer()) {
|
if (this.mapsService.map && this.mapsService.getMarkerContainer()) {
|
||||||
this.markers.push(marker);
|
this.markers.push(marker);
|
||||||
marker.addTo(this.scene);
|
marker.addTo(this.scene);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -47,9 +47,13 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
||||||
minZoom: 0,
|
minZoom: 0,
|
||||||
maxZoom: 20,
|
maxZoom: 20,
|
||||||
visible: true,
|
visible: true,
|
||||||
|
autoFit: false,
|
||||||
zIndex: 0,
|
zIndex: 0,
|
||||||
enableMultiPassRenderer: false,
|
pickedFeatureID: -1,
|
||||||
enablePicking: false,
|
enableMultiPassRenderer: true,
|
||||||
|
enablePicking: true,
|
||||||
|
active: false,
|
||||||
|
activeColor: 'red',
|
||||||
enableHighlight: false,
|
enableHighlight: false,
|
||||||
highlightColor: 'red',
|
highlightColor: 'red',
|
||||||
enableTAA: false,
|
enableTAA: false,
|
||||||
|
|
|
@ -8,7 +8,7 @@ export interface IInteractionService {
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
on(
|
on(
|
||||||
eventName: InteractionEvent,
|
eventName: InteractionEvent,
|
||||||
callback: (params: { x: number; y: number }) => void,
|
callback: (params: { x: number; y: number; type: string }) => void,
|
||||||
): void;
|
): void;
|
||||||
triggerHover({ x, y }: { x: number; y: number }): void;
|
triggerHover({ x, y, type }: { x: number; y: number; type?: string }): void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { TYPES } from '../../types';
|
||||||
import { ILogService } from '../log/ILogService';
|
import { ILogService } from '../log/ILogService';
|
||||||
import { IMapService } from '../map/IMapService';
|
import { IMapService } from '../map/IMapService';
|
||||||
import { IInteractionService, InteractionEvent } from './IInteractionService';
|
import { IInteractionService, InteractionEvent } from './IInteractionService';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 由于目前 L7 与地图结合的方案为双 canvas 而非共享 WebGL Context,事件监听注册在地图底图上。
|
* 由于目前 L7 与地图结合的方案为双 canvas 而非共享 WebGL Context,事件监听注册在地图底图上。
|
||||||
* 除此之外,后续如果支持非地图场景,事件监听就需要注册在 L7 canvas 上。
|
* 除此之外,后续如果支持非地图场景,事件监听就需要注册在 L7 canvas 上。
|
||||||
|
@ -49,8 +48,13 @@ export default class InteractionService extends EventEmitter
|
||||||
// hammertime.on('panmove', this.onPanmove);
|
// hammertime.on('panmove', this.onPanmove);
|
||||||
// hammertime.on('panend', this.onPanend);
|
// hammertime.on('panend', this.onPanend);
|
||||||
// hammertime.on('pinch', this.onPinch);
|
// hammertime.on('pinch', this.onPinch);
|
||||||
|
|
||||||
$containter.addEventListener('mousemove', this.onHover);
|
$containter.addEventListener('mousemove', this.onHover);
|
||||||
|
$containter.addEventListener('click', this.onHover);
|
||||||
|
$containter.addEventListener('mousedown', this.onHover);
|
||||||
|
$containter.addEventListener('mouseup', this.onHover);
|
||||||
|
$containter.addEventListener('dblclick', this.onHover);
|
||||||
|
$containter.addEventListener('contextmenu', this.onHover);
|
||||||
|
|
||||||
this.hammertime = hammertime;
|
this.hammertime = hammertime;
|
||||||
|
|
||||||
// TODO: 根据场景注册事件到 L7 canvas 上
|
// TODO: 根据场景注册事件到 L7 canvas 上
|
||||||
|
@ -62,16 +66,21 @@ export default class InteractionService extends EventEmitter
|
||||||
const $containter = this.mapService.getMapContainer();
|
const $containter = this.mapService.getMapContainer();
|
||||||
if ($containter) {
|
if ($containter) {
|
||||||
$containter.removeEventListener('mousemove', this.onHover);
|
$containter.removeEventListener('mousemove', this.onHover);
|
||||||
|
$containter.removeEventListener('click', this.onHover);
|
||||||
|
$containter.removeEventListener('mousedown', this.onHover);
|
||||||
|
$containter.removeEventListener('mouseup', this.onHover);
|
||||||
|
$containter.removeEventListener('dblclick', this.onHover);
|
||||||
|
$containter.removeEventListener('contextmenu', this.onHover);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onHover = ({ x, y }: MouseEvent) => {
|
private onHover = ({ x, y, type }: MouseEvent) => {
|
||||||
const $containter = this.mapService.getMapContainer();
|
const $containter = this.mapService.getMapContainer();
|
||||||
if ($containter) {
|
if ($containter) {
|
||||||
const { top, left } = $containter.getBoundingClientRect();
|
const { top, left } = $containter.getBoundingClientRect();
|
||||||
x -= left;
|
x -= left;
|
||||||
y -= top;
|
y -= top;
|
||||||
}
|
}
|
||||||
this.emit(InteractionEvent.Hover, { x, y });
|
this.emit(InteractionEvent.Hover, { x, y, type });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,13 @@ import {
|
||||||
StyleAttributeOption,
|
StyleAttributeOption,
|
||||||
Triangulation,
|
Triangulation,
|
||||||
} from './IStyleAttributeService';
|
} from './IStyleAttributeService';
|
||||||
|
export interface IDataState {
|
||||||
|
dataSourceNeedUpdate: boolean;
|
||||||
|
dataMappingNeedUpdate: boolean;
|
||||||
|
filterNeedUpdate: boolean;
|
||||||
|
featureScaleNeedUpdate: boolean;
|
||||||
|
StyleAttrNeedUpdate: boolean;
|
||||||
|
}
|
||||||
export interface ILayerModelInitializationOptions {
|
export interface ILayerModelInitializationOptions {
|
||||||
moduleName: string;
|
moduleName: string;
|
||||||
vertexShader: string;
|
vertexShader: string;
|
||||||
|
@ -44,6 +50,10 @@ export interface IPickedFeature {
|
||||||
lnglat?: { lng: number; lat: number };
|
lnglat?: { lng: number; lat: number };
|
||||||
feature?: unknown;
|
feature?: unknown;
|
||||||
}
|
}
|
||||||
|
// 交互样式
|
||||||
|
export interface IActiveOption {
|
||||||
|
color: string | number[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ILayer {
|
export interface ILayer {
|
||||||
id: string; // 一个场景中同一类型 Layer 可能存在多个
|
id: string; // 一个场景中同一类型 Layer 可能存在多个
|
||||||
|
@ -52,9 +62,11 @@ export interface ILayer {
|
||||||
zIndex: number;
|
zIndex: number;
|
||||||
plugins: ILayerPlugin[];
|
plugins: ILayerPlugin[];
|
||||||
layerModelNeedUpdate: boolean;
|
layerModelNeedUpdate: boolean;
|
||||||
dataPluginsState: { [key: string]: boolean };
|
dataState: IDataState; // 数据流状态
|
||||||
|
pickedFeatureID: number;
|
||||||
hooks: {
|
hooks: {
|
||||||
init: SyncBailHook<void, boolean | void>;
|
init: SyncBailHook<void, boolean | void>;
|
||||||
|
afterInit: SyncBailHook<void, boolean | void>;
|
||||||
beforeRenderData: SyncWaterfallHook<boolean | void>;
|
beforeRenderData: SyncWaterfallHook<boolean | void>;
|
||||||
beforeRender: SyncBailHook<void, boolean | void>;
|
beforeRender: SyncBailHook<void, boolean | void>;
|
||||||
afterRender: SyncHook<void>;
|
afterRender: SyncHook<void>;
|
||||||
|
@ -87,7 +99,16 @@ export interface ILayer {
|
||||||
animate(option: IAnimateOption): ILayer;
|
animate(option: IAnimateOption): ILayer;
|
||||||
// pattern(field: string, value: StyleAttributeOption): ILayer;
|
// pattern(field: string, value: StyleAttributeOption): ILayer;
|
||||||
filter(field: string, value: StyleAttributeOption): ILayer;
|
filter(field: string, value: StyleAttributeOption): ILayer;
|
||||||
// active(option: ActiveOption): ILayer;
|
active(option: IActiveOption | boolean): ILayer;
|
||||||
|
setActive(
|
||||||
|
id: number | { x: number; y: number },
|
||||||
|
option?: IActiveOption,
|
||||||
|
): void;
|
||||||
|
select(option: IActiveOption | false): ILayer;
|
||||||
|
setSelect(
|
||||||
|
id: number | { x: number; y: number },
|
||||||
|
option?: IActiveOption,
|
||||||
|
): void;
|
||||||
style(options: unknown): ILayer;
|
style(options: unknown): ILayer;
|
||||||
hide(): ILayer;
|
hide(): ILayer;
|
||||||
show(): ILayer;
|
show(): ILayer;
|
||||||
|
@ -100,22 +121,24 @@ export interface ILayer {
|
||||||
destroy(): void;
|
destroy(): void;
|
||||||
source(data: any, option?: ISourceCFG): ILayer;
|
source(data: any, option?: ISourceCFG): ILayer;
|
||||||
setData(data: any, option?: ISourceCFG): ILayer;
|
setData(data: any, option?: ISourceCFG): ILayer;
|
||||||
|
fitBounds(): ILayer;
|
||||||
/**
|
/**
|
||||||
* 向当前图层注册插件
|
* 向当前图层注册插件
|
||||||
* @param plugin 插件实例
|
* @param plugin 插件实例
|
||||||
*/
|
*/
|
||||||
addPlugin(plugin: ILayerPlugin): ILayer;
|
addPlugin(plugin: ILayerPlugin): ILayer;
|
||||||
getSource(): ISource;
|
getSource(): ISource;
|
||||||
isSourceNeedUpdate(): boolean;
|
|
||||||
setSource(source: ISource): void;
|
setSource(source: ISource): void;
|
||||||
setEncodedData(encodedData: IEncodeFeature[]): void;
|
setEncodedData(encodedData: IEncodeFeature[]): void;
|
||||||
getEncodedData(): IEncodeFeature[];
|
getEncodedData(): IEncodeFeature[];
|
||||||
getScaleOptions(): IScaleOptions;
|
getScaleOptions(): IScaleOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件
|
* 事件
|
||||||
*/
|
*/
|
||||||
on(type: string, hander: (...args: any[]) => void): void;
|
on(type: string, hander: (...args: any[]) => void): void;
|
||||||
off(type: string, hander: (...args: any[]) => void): void;
|
off(type: string, hander: (...args: any[]) => void): void;
|
||||||
|
emit(type: string, hander: unknown): void;
|
||||||
once(type: string, hander: (...args: any[]) => void): void;
|
once(type: string, hander: (...args: any[]) => void): void;
|
||||||
/**
|
/**
|
||||||
* JSON Schema 用于校验配置项
|
* JSON Schema 用于校验配置项
|
||||||
|
@ -126,6 +149,8 @@ export interface ILayer {
|
||||||
* 直接调用拾取方法,在非鼠标交互场景中使用
|
* 直接调用拾取方法,在非鼠标交互场景中使用
|
||||||
*/
|
*/
|
||||||
pick(query: { x: number; y: number }): void;
|
pick(query: { x: number; y: number }): void;
|
||||||
|
|
||||||
|
updateLayerConfig(configToUpdate: Partial<ILayerConfig | unknown>): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,6 +185,8 @@ export interface ILayerConfig {
|
||||||
maxZoom: number;
|
maxZoom: number;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
zIndex: number;
|
zIndex: number;
|
||||||
|
autoFit: boolean;
|
||||||
|
pickedFeatureID: number;
|
||||||
enableMultiPassRenderer: boolean;
|
enableMultiPassRenderer: boolean;
|
||||||
passes: Array<string | [string, { [key: string]: unknown }]>;
|
passes: Array<string | [string, { [key: string]: unknown }]>;
|
||||||
|
|
||||||
|
@ -175,6 +202,8 @@ export interface ILayerConfig {
|
||||||
* 高亮颜色
|
* 高亮颜色
|
||||||
*/
|
*/
|
||||||
highlightColor: string | number[];
|
highlightColor: string | number[];
|
||||||
|
active: boolean;
|
||||||
|
activeColor: string | number[];
|
||||||
/**
|
/**
|
||||||
* 开启 TAA
|
* 开启 TAA
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -112,7 +112,18 @@ export default class PixelPickingPass<
|
||||||
* 拾取视口指定坐标属于的要素
|
* 拾取视口指定坐标属于的要素
|
||||||
* TODO:支持区域拾取
|
* TODO:支持区域拾取
|
||||||
*/
|
*/
|
||||||
private pickFromPickingFBO = ({ x, y }: { x: number; y: number }) => {
|
private pickFromPickingFBO = ({
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
type,
|
||||||
|
}: {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
type: string;
|
||||||
|
}) => {
|
||||||
|
if (!this.layer.isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const {
|
const {
|
||||||
getViewportSize,
|
getViewportSize,
|
||||||
readPixels,
|
readPixels,
|
||||||
|
@ -152,9 +163,9 @@ export default class PixelPickingPass<
|
||||||
) {
|
) {
|
||||||
this.logger.debug('picked');
|
this.logger.debug('picked');
|
||||||
const pickedFeatureIdx = decodePickingColor(pickedColors);
|
const pickedFeatureIdx = decodePickingColor(pickedColors);
|
||||||
const rawFeature = this.layer.getSource()?.data?.dataArray[
|
const rawFeature = this.layer
|
||||||
pickedFeatureIdx
|
.getSource()
|
||||||
];
|
.getFeatureById(pickedFeatureIdx);
|
||||||
|
|
||||||
if (!rawFeature) {
|
if (!rawFeature) {
|
||||||
// this.logger.error(
|
// this.logger.error(
|
||||||
|
@ -162,7 +173,7 @@ export default class PixelPickingPass<
|
||||||
// );
|
// );
|
||||||
} else {
|
} else {
|
||||||
// trigger onHover/Click callback on layer
|
// trigger onHover/Click callback on layer
|
||||||
this.triggerHoverOnLayer({ x, y, feature: rawFeature });
|
this.triggerHoverOnLayer({ x, y, type, feature: rawFeature });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -175,27 +186,34 @@ export default class PixelPickingPass<
|
||||||
private triggerHoverOnLayer({
|
private triggerHoverOnLayer({
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
|
type,
|
||||||
feature,
|
feature,
|
||||||
}: {
|
}: {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
|
type: string;
|
||||||
feature: unknown;
|
feature: unknown;
|
||||||
}) {
|
}) {
|
||||||
const { onHover, onClick } = this.layer.getLayerConfig();
|
const { onHover, onClick } = this.layer.getLayerConfig();
|
||||||
if (onHover) {
|
// if (onHover) {
|
||||||
onHover({
|
// onHover({
|
||||||
x,
|
// x,
|
||||||
y,
|
// y,
|
||||||
feature,
|
// feature,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
if (onClick) {
|
// if (onClick) {
|
||||||
onClick({
|
// onClick({
|
||||||
x,
|
// x,
|
||||||
y,
|
// y,
|
||||||
feature,
|
// feature,
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
this.layer.emit(type, {
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
feature,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -61,6 +61,8 @@ export interface ISource {
|
||||||
data: IParserData;
|
data: IParserData;
|
||||||
cluster: boolean;
|
cluster: boolean;
|
||||||
clusterOptions: Partial<IClusterOptions>;
|
clusterOptions: Partial<IClusterOptions>;
|
||||||
|
updateClusterData(zoom: number): void;
|
||||||
|
getFeatureById(id: number): unknown;
|
||||||
}
|
}
|
||||||
export interface IRasterCfg {
|
export interface IRasterCfg {
|
||||||
extent: [number, number, number, number];
|
extent: [number, number, number, number];
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"module": "es/index.js",
|
"module": "es/index.js",
|
||||||
"types": "es/index.d.ts",
|
"types": "es/index.d.ts",
|
||||||
|
"unpkg": "dist/l7.js",
|
||||||
"sideEffects": true,
|
"sideEffects": true,
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import {
|
import {
|
||||||
gl,
|
gl,
|
||||||
|
IActiveOption,
|
||||||
IAnimateOption,
|
IAnimateOption,
|
||||||
|
IDataState,
|
||||||
IEncodeFeature,
|
IEncodeFeature,
|
||||||
IFontService,
|
IFontService,
|
||||||
IGlobalConfigService,
|
IGlobalConfigService,
|
||||||
|
@ -44,12 +46,10 @@ import mergeJsonSchemas from 'merge-json-schemas';
|
||||||
import { SyncBailHook, SyncHook, SyncWaterfallHook } from 'tapable';
|
import { SyncBailHook, SyncHook, SyncWaterfallHook } from 'tapable';
|
||||||
import { normalizePasses } from '../plugins/MultiPassRendererPlugin';
|
import { normalizePasses } from '../plugins/MultiPassRendererPlugin';
|
||||||
import baseLayerSchema from './schema';
|
import baseLayerSchema from './schema';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分配 layer id
|
* 分配 layer id
|
||||||
*/
|
*/
|
||||||
let layerIdCounter = 0;
|
let layerIdCounter = 0;
|
||||||
const MapEventTypes = ['zoomchange', 'dragend', 'camerachange', 'resize'];
|
|
||||||
|
|
||||||
export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
implements ILayer {
|
implements ILayer {
|
||||||
|
@ -61,15 +61,19 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
public maxZoom: number;
|
public maxZoom: number;
|
||||||
public inited: boolean = false;
|
public inited: boolean = false;
|
||||||
public layerModelNeedUpdate: boolean = false;
|
public layerModelNeedUpdate: boolean = false;
|
||||||
public dataPluginsState: { [key: string]: boolean } = {
|
public pickedFeatureID: number = -1;
|
||||||
DataSource: false,
|
|
||||||
DataMapping: false,
|
public dataState: IDataState = {
|
||||||
FeatureScale: false,
|
dataSourceNeedUpdate: false,
|
||||||
StyleAttr: false,
|
dataMappingNeedUpdate: false,
|
||||||
|
filterNeedUpdate: false,
|
||||||
|
featureScaleNeedUpdate: false,
|
||||||
|
StyleAttrNeedUpdate: false,
|
||||||
};
|
};
|
||||||
// 生命周期钩子
|
// 生命周期钩子
|
||||||
public hooks = {
|
public hooks = {
|
||||||
init: new SyncBailHook<void, boolean | void>(),
|
init: new SyncBailHook<void, boolean | void>(),
|
||||||
|
afterInit: new SyncBailHook<void, boolean | void>(),
|
||||||
beforeRender: new SyncBailHook<void, boolean | void>(),
|
beforeRender: new SyncBailHook<void, boolean | void>(),
|
||||||
beforeRenderData: new SyncWaterfallHook<void | boolean>(['data']),
|
beforeRenderData: new SyncWaterfallHook<void | boolean>(['data']),
|
||||||
afterRender: new SyncHook<void>(),
|
afterRender: new SyncHook<void>(),
|
||||||
|
@ -140,6 +144,8 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
|
|
||||||
private rawConfig: Partial<ILayerConfig & ChildLayerStyleOptions>;
|
private rawConfig: Partial<ILayerConfig & ChildLayerStyleOptions>;
|
||||||
|
|
||||||
|
private needUpdateConfig: Partial<ILayerConfig & ChildLayerStyleOptions>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 待更新样式属性,在初始化阶段完成注册
|
* 待更新样式属性,在初始化阶段完成注册
|
||||||
*/
|
*/
|
||||||
|
@ -165,11 +171,20 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
public updateLayerConfig(
|
public updateLayerConfig(
|
||||||
configToUpdate: Partial<ILayerConfig | ChildLayerStyleOptions>,
|
configToUpdate: Partial<ILayerConfig | ChildLayerStyleOptions>,
|
||||||
) {
|
) {
|
||||||
const sceneId = this.container.get<string>(TYPES.SceneID);
|
if (!this.inited) {
|
||||||
this.configService.setLayerConfig(sceneId, this.id, {
|
this.needUpdateConfig = {
|
||||||
...this.configService.getLayerConfig(this.id),
|
...this.needUpdateConfig,
|
||||||
...configToUpdate,
|
...configToUpdate,
|
||||||
});
|
};
|
||||||
|
} else {
|
||||||
|
const sceneId = this.container.get<string>(TYPES.SceneID);
|
||||||
|
this.configService.setLayerConfig(sceneId, this.id, {
|
||||||
|
...this.configService.getLayerConfig(this.id),
|
||||||
|
...this.needUpdateConfig,
|
||||||
|
...configToUpdate,
|
||||||
|
});
|
||||||
|
this.needUpdateConfig = {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -273,10 +288,11 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
|
|
||||||
// 触发 init 生命周期插件
|
// 触发 init 生命周期插件
|
||||||
this.hooks.init.call();
|
this.hooks.init.call();
|
||||||
|
this.inited = true;
|
||||||
|
|
||||||
|
this.hooks.afterInit.call();
|
||||||
|
|
||||||
this.buildModels();
|
this.buildModels();
|
||||||
|
|
||||||
this.inited = true;
|
|
||||||
// 触发初始化完成事件;
|
// 触发初始化完成事件;
|
||||||
this.emit('inited');
|
this.emit('inited');
|
||||||
return this;
|
return this;
|
||||||
|
@ -311,6 +327,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
// 对mapping后的数据过滤,scale保持不变
|
||||||
public filter(
|
public filter(
|
||||||
field: StyleAttributeField,
|
field: StyleAttributeField,
|
||||||
values?: StyleAttributeOption,
|
values?: StyleAttributeOption,
|
||||||
|
@ -322,6 +339,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
attributeValues: values,
|
attributeValues: values,
|
||||||
updateOptions,
|
updateOptions,
|
||||||
});
|
});
|
||||||
|
this.dataState.dataMappingNeedUpdate = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,30 +389,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
this.buildModels();
|
this.buildModels();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isSourceNeedUpdate() {
|
|
||||||
const cluster = this.layerSource.cluster;
|
|
||||||
if (cluster) {
|
|
||||||
const { zoom = 0, bbox = [0, 0, 0, 0] } = this.layerSource.clusterOptions;
|
|
||||||
const newZoom = this.mapService.getZoom();
|
|
||||||
const bounds = this.mapService.getBounds();
|
|
||||||
const newBbox: [number, number, number, number] = [
|
|
||||||
bounds[0][0],
|
|
||||||
bounds[0][1],
|
|
||||||
bounds[1][0],
|
|
||||||
bounds[1][1],
|
|
||||||
];
|
|
||||||
// ||
|
|
||||||
// bbox[0] !== newBbox[0] ||
|
|
||||||
// bbox[2] !== newBbox[2]
|
|
||||||
if (Math.abs(zoom - newZoom) > 1) {
|
|
||||||
this.layerSource.updateClusterData(Math.floor(newZoom), newBbox);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public style(options: object & Partial<ILayerConfig>): ILayer {
|
public style(options: object & Partial<ILayerConfig>): ILayer {
|
||||||
const { passes, ...rest } = options;
|
const { passes, ...rest } = options;
|
||||||
|
|
||||||
|
@ -442,11 +436,51 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public active(options: IActiveOption) {
|
||||||
|
this.updateLayerConfig({
|
||||||
|
enableHighlight: isObject(options) ? true : options,
|
||||||
|
highlightColor: isObject(options)
|
||||||
|
? options.color
|
||||||
|
: this.getLayerConfig().highlightColor,
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public setActive(
|
||||||
|
id: number | { x: number; y: number },
|
||||||
|
options?: IActiveOption,
|
||||||
|
): void {
|
||||||
|
if (isObject(id)) {
|
||||||
|
const { x = 0, y = 0 } = id;
|
||||||
|
this.updateLayerConfig({
|
||||||
|
highlightColor: isObject(options)
|
||||||
|
? options.color
|
||||||
|
: this.getLayerConfig().highlightColor,
|
||||||
|
});
|
||||||
|
this.pick({ x, y });
|
||||||
|
} else {
|
||||||
|
this.updateLayerConfig({
|
||||||
|
pickedFeatureID: id,
|
||||||
|
highlightColor: isObject(options)
|
||||||
|
? options.color
|
||||||
|
: this.getLayerConfig().highlightColor,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public select(option: IActiveOption | false): ILayer {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setSelect(
|
||||||
|
id: number | { x: number; y: number },
|
||||||
|
options?: IActiveOption,
|
||||||
|
): void {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
public show(): ILayer {
|
public show(): ILayer {
|
||||||
this.updateLayerConfig({
|
this.updateLayerConfig({
|
||||||
visible: true,
|
visible: true,
|
||||||
});
|
});
|
||||||
this.layerService.renderLayers();
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +488,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
this.updateLayerConfig({
|
this.updateLayerConfig({
|
||||||
visible: false,
|
visible: false,
|
||||||
});
|
});
|
||||||
this.layerService.renderLayers();
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,13 +524,20 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
/**
|
/**
|
||||||
* zoom to layer Bounds
|
* zoom to layer Bounds
|
||||||
*/
|
*/
|
||||||
public fitBounds(): void {
|
public fitBounds(): ILayer {
|
||||||
|
if (!this.inited) {
|
||||||
|
this.updateLayerConfig({
|
||||||
|
autoFit: true,
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
const source = this.getSource();
|
const source = this.getSource();
|
||||||
const extent = source.extent;
|
const extent = source.extent;
|
||||||
this.mapService.fitBounds([
|
this.mapService.fitBounds([
|
||||||
[extent[0], extent[1]],
|
[extent[0], extent[1]],
|
||||||
[extent[2], extent[3]],
|
[extent[2], extent[3]],
|
||||||
]);
|
]);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
|
@ -537,12 +577,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
const bounds = this.mapService.getBounds();
|
const bounds = this.mapService.getBounds();
|
||||||
const zoom = this.mapService.getZoom();
|
const zoom = this.mapService.getZoom();
|
||||||
if (this.layerSource.cluster) {
|
if (this.layerSource.cluster) {
|
||||||
this.layerSource.updateClusterData(zoom, [
|
this.layerSource.updateClusterData(zoom);
|
||||||
bounds[0][0],
|
|
||||||
bounds[0][1],
|
|
||||||
bounds[1][0],
|
|
||||||
bounds[1][1],
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public getSource() {
|
public getSource() {
|
||||||
|
@ -643,11 +678,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerMapEvent() {
|
|
||||||
MapEventTypes.forEach((type) => {
|
|
||||||
this.mapService.on(type, this.layerMapHander.bind(this, type));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
private layerMapHander(type: string, data: any) {
|
private layerMapHander(type: string, data: any) {
|
||||||
this.emit(type, data);
|
this.emit(type, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,29 +45,29 @@ export default class HexagonModel extends BaseModel {
|
||||||
}
|
}
|
||||||
protected registerBuiltinAttributes() {
|
protected registerBuiltinAttributes() {
|
||||||
// point layer size;
|
// point layer size;
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
// this.styleAttributeService.registerStyleAttribute({
|
||||||
name: 'size',
|
// name: 'size',
|
||||||
type: AttributeType.Attribute,
|
// type: AttributeType.Attribute,
|
||||||
descriptor: {
|
// descriptor: {
|
||||||
name: 'a_Size',
|
// name: 'a_Size',
|
||||||
buffer: {
|
// buffer: {
|
||||||
// give the WebGL driver a hint that this buffer may change
|
// // give the WebGL driver a hint that this buffer may change
|
||||||
usage: gl.DYNAMIC_DRAW,
|
// usage: gl.DYNAMIC_DRAW,
|
||||||
data: [],
|
// data: [],
|
||||||
type: gl.FLOAT,
|
// type: gl.FLOAT,
|
||||||
},
|
// },
|
||||||
size: 1,
|
// size: 1,
|
||||||
update: (
|
// update: (
|
||||||
feature: IEncodeFeature,
|
// feature: IEncodeFeature,
|
||||||
featureIdx: number,
|
// featureIdx: number,
|
||||||
vertex: number[],
|
// vertex: number[],
|
||||||
attributeIdx: number,
|
// attributeIdx: number,
|
||||||
) => {
|
// ) => {
|
||||||
const { size } = feature;
|
// const { size } = feature;
|
||||||
return Array.isArray(size) ? [size[0]] : [size as number];
|
// return Array.isArray(size) ? [size[0]] : [size as number];
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
// point layer size;
|
// point layer size;
|
||||||
this.styleAttributeService.registerStyleAttribute({
|
this.styleAttributeService.registerStyleAttribute({
|
||||||
|
|
|
@ -13,6 +13,7 @@ import ConfigSchemaValidationPlugin from './plugins/ConfigSchemaValidationPlugin
|
||||||
import DataMappingPlugin from './plugins/DataMappingPlugin';
|
import DataMappingPlugin from './plugins/DataMappingPlugin';
|
||||||
import DataSourcePlugin from './plugins/DataSourcePlugin';
|
import DataSourcePlugin from './plugins/DataSourcePlugin';
|
||||||
import FeatureScalePlugin from './plugins/FeatureScalePlugin';
|
import FeatureScalePlugin from './plugins/FeatureScalePlugin';
|
||||||
|
import LayerStylePlugin from './plugins/LayerStylePlugin';
|
||||||
import LightingPlugin from './plugins/LightingPlugin';
|
import LightingPlugin from './plugins/LightingPlugin';
|
||||||
import MultiPassRendererPlugin from './plugins/MultiPassRendererPlugin';
|
import MultiPassRendererPlugin from './plugins/MultiPassRendererPlugin';
|
||||||
import PixelPickingPlugin from './plugins/PixelPickingPlugin';
|
import PixelPickingPlugin from './plugins/PixelPickingPlugin';
|
||||||
|
@ -56,6 +57,15 @@ container
|
||||||
.bind<ILayerPlugin>(TYPES.ILayerPlugin)
|
.bind<ILayerPlugin>(TYPES.ILayerPlugin)
|
||||||
.to(DataMappingPlugin)
|
.to(DataMappingPlugin)
|
||||||
.inRequestScope();
|
.inRequestScope();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新地图样式配置项 如active, show, hide
|
||||||
|
*/
|
||||||
|
container
|
||||||
|
.bind<ILayerPlugin>(TYPES.ILayerPlugin)
|
||||||
|
.to(LayerStylePlugin)
|
||||||
|
.inRequestScope();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 负责属性更新
|
* 负责属性更新
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -27,13 +27,13 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
||||||
}: { styleAttributeService: IStyleAttributeService },
|
}: { styleAttributeService: IStyleAttributeService },
|
||||||
) {
|
) {
|
||||||
layer.hooks.init.tap('DataMappingPlugin', () => {
|
layer.hooks.init.tap('DataMappingPlugin', () => {
|
||||||
this.doMaping(layer, { styleAttributeService });
|
this.generateMaping(layer, { styleAttributeService });
|
||||||
});
|
});
|
||||||
|
|
||||||
layer.hooks.beforeRenderData.tap('DataMappingPlugin', (flag) => {
|
layer.hooks.beforeRenderData.tap('DataMappingPlugin', (flag) => {
|
||||||
if (flag) {
|
if (flag || layer.dataState.dataMappingNeedUpdate) {
|
||||||
layer.dataPluginsState.DataMapping = false;
|
layer.dataState.dataMappingNeedUpdate = false;
|
||||||
this.doMaping(layer, { styleAttributeService });
|
this.generateMaping(layer, { styleAttributeService });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -52,7 +52,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
private doMaping(
|
private generateMaping(
|
||||||
layer: ILayer,
|
layer: ILayer,
|
||||||
{
|
{
|
||||||
styleAttributeService,
|
styleAttributeService,
|
||||||
|
@ -62,6 +62,7 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
||||||
const filter = styleAttributeService.getLayerStyleAttribute('filter');
|
const filter = styleAttributeService.getLayerStyleAttribute('filter');
|
||||||
const { dataArray } = layer.getSource().data;
|
const { dataArray } = layer.getSource().data;
|
||||||
let filterData = dataArray;
|
let filterData = dataArray;
|
||||||
|
// 数据过滤完 在执行数据映射
|
||||||
if (filter?.scale) {
|
if (filter?.scale) {
|
||||||
filterData = dataArray.filter((record: IParseDataItem) => {
|
filterData = dataArray.filter((record: IParseDataItem) => {
|
||||||
return this.applyAttributeMapping(filter, record)[0];
|
return this.applyAttributeMapping(filter, record)[0];
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { ILayer, ILayerPlugin } from '@antv/l7-core';
|
import { ILayer, ILayerPlugin, IMapService, TYPES } from '@antv/l7-core';
|
||||||
import Source from '@antv/l7-source';
|
import Source from '@antv/l7-source';
|
||||||
import { injectable } from 'inversify';
|
import { injectable } from 'inversify';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export default class DataSourcePlugin implements ILayerPlugin {
|
export default class DataSourcePlugin implements ILayerPlugin {
|
||||||
|
protected mapService: IMapService;
|
||||||
public apply(layer: ILayer) {
|
public apply(layer: ILayer) {
|
||||||
|
this.mapService = layer.getContainer().get<IMapService>(TYPES.IMapService);
|
||||||
layer.hooks.init.tap('DataSourcePlugin', () => {
|
layer.hooks.init.tap('DataSourcePlugin', () => {
|
||||||
const { data, options } = layer.sourceOption;
|
const { data, options } = layer.sourceOption;
|
||||||
layer.setSource(new Source(data, options));
|
layer.setSource(new Source(data, options));
|
||||||
|
@ -12,7 +14,12 @@ export default class DataSourcePlugin implements ILayerPlugin {
|
||||||
|
|
||||||
// 检测数据是不否需要更新
|
// 检测数据是不否需要更新
|
||||||
layer.hooks.beforeRenderData.tap('DataSourcePlugin', (flag) => {
|
layer.hooks.beforeRenderData.tap('DataSourcePlugin', (flag) => {
|
||||||
if (layer.isSourceNeedUpdate()) {
|
const source = layer.getSource();
|
||||||
|
const cluster = source.cluster;
|
||||||
|
const { zoom = 0, maxZoom = 16 } = source.clusterOptions;
|
||||||
|
const newZoom = this.mapService.getZoom();
|
||||||
|
if (cluster && Math.abs(zoom - newZoom) > 1 && maxZoom > zoom) {
|
||||||
|
source.updateClusterData(Math.floor(newZoom) + 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
import { ILayer, ILayerPlugin, IMapService, TYPES } from '@antv/l7-core';
|
||||||
|
import Source from '@antv/l7-source';
|
||||||
|
import { injectable } from 'inversify';
|
||||||
|
import { encodePickingColor, rgb2arr } from '../utils/color';
|
||||||
|
@injectable()
|
||||||
|
export default class LayerStylePlugin implements ILayerPlugin {
|
||||||
|
public apply(layer: ILayer) {
|
||||||
|
layer.hooks.afterInit.tap('LayerStylePlugin', () => {
|
||||||
|
layer.updateLayerConfig({});
|
||||||
|
const { autoFit } = layer.getLayerConfig();
|
||||||
|
if (autoFit) {
|
||||||
|
layer.fitBounds();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
layer.hooks.beforeRender.tap('LayerStylePlugin', () => {
|
||||||
|
const {
|
||||||
|
highlightColor = 'red',
|
||||||
|
pickedFeatureID = -1,
|
||||||
|
} = layer.getLayerConfig();
|
||||||
|
layer.models.forEach((model) =>
|
||||||
|
model.addUniforms({
|
||||||
|
u_PickingStage: 2.0,
|
||||||
|
u_PickingColor: encodePickingColor(pickedFeatureID),
|
||||||
|
u_HighlightColor: rgb2arr(highlightColor as string),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,15 +8,7 @@ import {
|
||||||
IStyleAttributeService,
|
IStyleAttributeService,
|
||||||
} from '@antv/l7-core';
|
} from '@antv/l7-core';
|
||||||
import { injectable } from 'inversify';
|
import { injectable } from 'inversify';
|
||||||
import { rgb2arr } from '../utils/color';
|
import { encodePickingColor, rgb2arr } from '../utils/color';
|
||||||
|
|
||||||
function encodePickingColor(featureIdx: number): [number, number, number] {
|
|
||||||
return [
|
|
||||||
(featureIdx + 1) & 255,
|
|
||||||
((featureIdx + 1) >> 8) & 255,
|
|
||||||
(((featureIdx + 1) >> 8) >> 8) & 255,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
const PickingStage = {
|
const PickingStage = {
|
||||||
NONE: 0.0,
|
NONE: 0.0,
|
||||||
|
@ -50,9 +42,13 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
||||||
},
|
},
|
||||||
size: 3,
|
size: 3,
|
||||||
// TODO: 固定 feature range 范围内的 pickingColor 都是固定的,可以生成 cache
|
// TODO: 固定 feature range 范围内的 pickingColor 都是固定的,可以生成 cache
|
||||||
update: (feature: IEncodeFeature, featureIdx: number) =>
|
update: (feature: IEncodeFeature, featureIdx: number) => {
|
||||||
// 只有开启拾取才需要 encode
|
// 只有开启拾取才需要 encode
|
||||||
enablePicking ? encodePickingColor(featureIdx) : [0, 0, 0],
|
const { id } = feature;
|
||||||
|
return enablePicking && layer.isVisible()
|
||||||
|
? encodePickingColor(id as number)
|
||||||
|
: [0, 0, 0];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -60,7 +56,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
||||||
// if (layer.multiPassRenderer) {
|
// if (layer.multiPassRenderer) {
|
||||||
layer.hooks.beforePickingEncode.tap('PixelPickingPlugin', () => {
|
layer.hooks.beforePickingEncode.tap('PixelPickingPlugin', () => {
|
||||||
const { enablePicking } = layer.getLayerConfig();
|
const { enablePicking } = layer.getLayerConfig();
|
||||||
if (enablePicking) {
|
if (enablePicking && layer.isVisible()) {
|
||||||
layer.models.forEach((model) =>
|
layer.models.forEach((model) =>
|
||||||
model.addUniforms({
|
model.addUniforms({
|
||||||
u_PickingStage: PickingStage.ENCODE,
|
u_PickingStage: PickingStage.ENCODE,
|
||||||
|
@ -71,7 +67,7 @@ export default class PixelPickingPlugin implements ILayerPlugin {
|
||||||
|
|
||||||
layer.hooks.afterPickingEncode.tap('PixelPickingPlugin', () => {
|
layer.hooks.afterPickingEncode.tap('PixelPickingPlugin', () => {
|
||||||
const { enablePicking } = layer.getLayerConfig();
|
const { enablePicking } = layer.getLayerConfig();
|
||||||
if (enablePicking) {
|
if (enablePicking && layer.isVisible()) {
|
||||||
layer.models.forEach((model) =>
|
layer.models.forEach((model) =>
|
||||||
model.addUniforms({
|
model.addUniforms({
|
||||||
u_PickingStage: PickingStage.NONE,
|
u_PickingStage: PickingStage.NONE,
|
||||||
|
|
|
@ -15,6 +15,16 @@ export function rgb2arr(str: string) {
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function encodePickingColor(
|
||||||
|
featureIdx: number,
|
||||||
|
): [number, number, number] {
|
||||||
|
return [
|
||||||
|
(featureIdx + 1) & 255,
|
||||||
|
((featureIdx + 1) >> 8) & 255,
|
||||||
|
(((featureIdx + 1) >> 8) >> 8) & 255,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
export function generateColorRamp(colorRamp: IColorRamp): ImageData {
|
export function generateColorRamp(colorRamp: IColorRamp): ImageData {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
|
||||||
|
|
|
@ -20,6 +20,6 @@ describe('source constructor', () => {
|
||||||
field: 'mag',
|
field: 'mag',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
source.updateClusterData(2, [10, 0, 130, 75]);
|
source.updateClusterData(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,8 +6,11 @@ import json from './parser/json';
|
||||||
import raster from './parser/raster';
|
import raster from './parser/raster';
|
||||||
import Source from './source';
|
import Source from './source';
|
||||||
import { cluster } from './transform/cluster';
|
import { cluster } from './transform/cluster';
|
||||||
|
import { filter } from './transform/filter';
|
||||||
import { aggregatorToGrid } from './transform/grid';
|
import { aggregatorToGrid } from './transform/grid';
|
||||||
import { pointToHexbin } from './transform/hexagon';
|
import { pointToHexbin } from './transform/hexagon';
|
||||||
|
import { join } from './transform/join';
|
||||||
|
import { map } from './transform/map';
|
||||||
export default Source;
|
export default Source;
|
||||||
registerParser('geojson', geojson);
|
registerParser('geojson', geojson);
|
||||||
registerParser('image', image);
|
registerParser('image', image);
|
||||||
|
@ -15,6 +18,9 @@ registerParser('csv', csv);
|
||||||
registerParser('json', json);
|
registerParser('json', json);
|
||||||
registerParser('raster', raster);
|
registerParser('raster', raster);
|
||||||
registerTransform('cluster', cluster);
|
registerTransform('cluster', cluster);
|
||||||
|
registerTransform('filter', filter);
|
||||||
|
registerTransform('join', join);
|
||||||
|
registerTransform('map', map);
|
||||||
registerTransform('grid', aggregatorToGrid);
|
registerTransform('grid', aggregatorToGrid);
|
||||||
registerTransform('hexagon', pointToHexbin);
|
registerTransform('hexagon', pointToHexbin);
|
||||||
export {
|
export {
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
import {
|
import {
|
||||||
IClusterOptions,
|
IClusterOptions,
|
||||||
|
IMapService,
|
||||||
IParserCfg,
|
IParserCfg,
|
||||||
IParserData,
|
IParserData,
|
||||||
ISourceCFG,
|
ISourceCFG,
|
||||||
ITransform,
|
ITransform,
|
||||||
|
lazyInject,
|
||||||
|
TYPES,
|
||||||
} from '@antv/l7-core';
|
} from '@antv/l7-core';
|
||||||
import { extent } from '@antv/l7-utils';
|
import { extent } from '@antv/l7-utils';
|
||||||
import {
|
import {
|
||||||
|
@ -14,13 +17,13 @@ import {
|
||||||
Properties,
|
Properties,
|
||||||
} from '@turf/helpers';
|
} from '@turf/helpers';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
import { Container } from 'inversify';
|
||||||
import { cloneDeep, isFunction, isString } from 'lodash';
|
import { cloneDeep, isFunction, isString } from 'lodash';
|
||||||
import Supercluster from 'supercluster';
|
import Supercluster from 'supercluster';
|
||||||
import { SyncHook } from 'tapable';
|
import { SyncHook } from 'tapable';
|
||||||
import { getParser, getTransform } from './';
|
import { getParser, getTransform } from './';
|
||||||
import { statMap } from './utils/statistics';
|
import { statMap } from './utils/statistics';
|
||||||
import { getColumn } from './utils/util';
|
import { getColumn } from './utils/util';
|
||||||
|
|
||||||
export default class Source extends EventEmitter {
|
export default class Source extends EventEmitter {
|
||||||
public data: IParserData;
|
public data: IParserData;
|
||||||
|
|
||||||
|
@ -82,13 +85,9 @@ export default class Source extends EventEmitter {
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateClusterData(
|
public updateClusterData(zoom: number): void {
|
||||||
zoom: number,
|
|
||||||
bbox: [number, number, number, number],
|
|
||||||
): void {
|
|
||||||
const { method = 'sum', field } = this.clusterOptions;
|
const { method = 'sum', field } = this.clusterOptions;
|
||||||
let data = this.clusterIndex.getClusters(bbox, zoom);
|
let data = this.clusterIndex.getClusters(this.extent, zoom);
|
||||||
this.clusterOptions.bbox = bbox;
|
|
||||||
this.clusterOptions.zoom = zoom;
|
this.clusterOptions.zoom = zoom;
|
||||||
data.forEach((p) => {
|
data.forEach((p) => {
|
||||||
if (!p.id) {
|
if (!p.id) {
|
||||||
|
@ -122,6 +121,16 @@ export default class Source extends EventEmitter {
|
||||||
});
|
});
|
||||||
this.executeTrans();
|
this.executeTrans();
|
||||||
}
|
}
|
||||||
|
public getFeatureById(id: number): unknown {
|
||||||
|
const { type = 'geojson' } = this.parser;
|
||||||
|
if (type === 'geojson') {
|
||||||
|
return id < this.rawData.features.length
|
||||||
|
? this.rawData.features[id]
|
||||||
|
: 'null';
|
||||||
|
} else {
|
||||||
|
return id < this.data.dataArray.length ? this.data.dataArray[id] : 'null';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private excuteParser(): void {
|
private excuteParser(): void {
|
||||||
const parser = this.parser;
|
const parser = this.parser;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { IParserData } from '@antv/l7-core';
|
||||||
|
export function filter(data: IParserData, options: { [key: string]: any }) {
|
||||||
|
const { callback } = options;
|
||||||
|
if (callback) {
|
||||||
|
data.dataArray = data.dataArray.filter(callback);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { IParseDataItem, IParserData } from '@antv/l7-core';
|
||||||
|
|
||||||
|
interface IJoinOption {
|
||||||
|
field: 'string';
|
||||||
|
data: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* @param options
|
||||||
|
*/
|
||||||
|
export function join(geoData: IParserData, options: { [key: string]: any }) {
|
||||||
|
const { field, data } = options;
|
||||||
|
const dataObj: { [key: string]: any } = {};
|
||||||
|
data.forEach((element: { [key: string]: any }) => {
|
||||||
|
dataObj[element.field] = element;
|
||||||
|
});
|
||||||
|
geoData.dataArray = data.dataArray.map((item: IParseDataItem) => {
|
||||||
|
const joinName = item[field];
|
||||||
|
return {
|
||||||
|
...dataObj[joinName],
|
||||||
|
...item,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { IParserData } from '@antv/l7-core';
|
||||||
|
type CallBack = (...args: any[]) => any;
|
||||||
|
export function map(data: IParserData, options: { [key: string]: any }) {
|
||||||
|
const { callback } = options;
|
||||||
|
if (callback) {
|
||||||
|
data.dataArray = data.dataArray.map(callback);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import { storiesOf } from '@storybook/react';
|
import { storiesOf } from '@storybook/react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import Chart from './components/chart';
|
||||||
import Marker from './components/Marker';
|
import Marker from './components/Marker';
|
||||||
import Popup from './components/Popup';
|
import Popup from './components/Popup';
|
||||||
import Scale from './components/Scale';
|
import Scale from './components/Scale';
|
||||||
|
@ -9,4 +10,5 @@ storiesOf('UI 组件', module)
|
||||||
.add('Zoom', () => <Zoom />)
|
.add('Zoom', () => <Zoom />)
|
||||||
.add('Scale', () => <Scale />)
|
.add('Scale', () => <Scale />)
|
||||||
.add('Marker', () => <Marker />)
|
.add('Marker', () => <Marker />)
|
||||||
|
.add('Chart', () => <Chart />)
|
||||||
.add('Popup', () => <Popup />);
|
.add('Popup', () => <Popup />);
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
// @ts-ignore
|
||||||
|
import * as G2 from '@antv/g2';
|
||||||
|
import { Marker, Scene } from '@antv/l7';
|
||||||
|
import { GaodeMap, Mapbox } from '@antv/l7-maps';
|
||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export default class ChartComponent extends React.Component {
|
||||||
|
private scene: Scene;
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
this.scene.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async componentDidMount() {
|
||||||
|
const scene = new Scene({
|
||||||
|
id: 'map',
|
||||||
|
map: new GaodeMap({
|
||||||
|
pitch: 0,
|
||||||
|
style: 'dark',
|
||||||
|
center: [52.21496184144132, 24.121126851768906],
|
||||||
|
zoom: 3.802,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
addChart();
|
||||||
|
scene.render();
|
||||||
|
function addChart() {
|
||||||
|
Promise.all([
|
||||||
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/basement_prod/5b772136-a1f4-4fc5-9a80-9f9974b4b182.json',
|
||||||
|
).then((d) => d.json()),
|
||||||
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/basement_prod/f3c467a4-9ae0-4f08-bb5f-11f9c869b2cb.json',
|
||||||
|
).then((d) => d.json()),
|
||||||
|
]).then(function onLoad([center, population]) {
|
||||||
|
const popobj: { [key: string]: any } = {};
|
||||||
|
population.forEach((element: any) => {
|
||||||
|
popobj[element.Code] =
|
||||||
|
element['Population, female (% of total) (% of total)'];
|
||||||
|
});
|
||||||
|
// 数据绑定
|
||||||
|
|
||||||
|
center.features = center.features.map((fe: any) => {
|
||||||
|
fe.properties.female = popobj[fe.properties.id] * 1 || 0;
|
||||||
|
return fe;
|
||||||
|
});
|
||||||
|
center.features.forEach((point: any) => {
|
||||||
|
const el = document.createElement('div');
|
||||||
|
const coord = point.geometry.coordinates;
|
||||||
|
const v = (point.properties.female * 1) as number;
|
||||||
|
if (v < 1 || (v > 46 && v < 54)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const size = 60;
|
||||||
|
const data = [
|
||||||
|
{
|
||||||
|
type: '男性',
|
||||||
|
value: 100.0 - Number(v.toFixed(2)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: '女性',
|
||||||
|
value: v.toFixed(2),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const chart = new G2.Chart({
|
||||||
|
container: el,
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
// render: 'svg',
|
||||||
|
padding: 0,
|
||||||
|
});
|
||||||
|
chart.source(data);
|
||||||
|
chart.legend(false);
|
||||||
|
chart.tooltip(false);
|
||||||
|
chart.coord('theta', {
|
||||||
|
radius: 0.9,
|
||||||
|
innerRadius: 0.6,
|
||||||
|
});
|
||||||
|
chart
|
||||||
|
.intervalStack()
|
||||||
|
.position('value')
|
||||||
|
.color('type', ['#5CCEA1', '#5B8FF9'])
|
||||||
|
.opacity(1);
|
||||||
|
chart.render();
|
||||||
|
const marker = new Marker({ element: el }).setLnglat({
|
||||||
|
lng: coord[0],
|
||||||
|
lat: coord[1],
|
||||||
|
});
|
||||||
|
scene.addMarker(marker);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
id="map"
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,6 @@ import ArcLineDemo from './components/Arcline';
|
||||||
import Column from './components/column';
|
import Column from './components/column';
|
||||||
import DataUpdate from './components/data_update';
|
import DataUpdate from './components/data_update';
|
||||||
import HeatMapDemo from './components/HeatMap';
|
import HeatMapDemo from './components/HeatMap';
|
||||||
import GridHeatMap from './components/HeatmapGrid';
|
|
||||||
import LineLayer from './components/Line';
|
import LineLayer from './components/Line';
|
||||||
import PointDemo from './components/Point';
|
import PointDemo from './components/Point';
|
||||||
import Point3D from './components/Point3D';
|
import Point3D from './components/Point3D';
|
||||||
|
@ -25,7 +24,6 @@ storiesOf('图层', module)
|
||||||
.add('线图层', () => <LineLayer />)
|
.add('线图层', () => <LineLayer />)
|
||||||
.add('3D弧线', () => <ArcLineDemo />)
|
.add('3D弧线', () => <ArcLineDemo />)
|
||||||
.add('2D弧线', () => <Arc2DLineDemo />)
|
.add('2D弧线', () => <Arc2DLineDemo />)
|
||||||
.add('网格热力图', () => <GridHeatMap />)
|
|
||||||
.add('热力图', () => <HeatMapDemo />)
|
.add('热力图', () => <HeatMapDemo />)
|
||||||
.add('栅格', () => <RasterLayerDemo />)
|
.add('栅格', () => <RasterLayerDemo />)
|
||||||
.add('图片', () => <ImageLayerDemo />);
|
.add('图片', () => <ImageLayerDemo />);
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
import { HeatmapLayer, Scene } from '@antv/l7';
|
|
||||||
import { GaodeMap } from '@antv/l7-maps';
|
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
export default class GridHeatMap extends React.Component {
|
|
||||||
// @ts-ignore
|
|
||||||
private scene: Scene;
|
|
||||||
|
|
||||||
public componentWillUnmount() {
|
|
||||||
this.scene.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async componentDidMount() {
|
|
||||||
const response = await fetch(
|
|
||||||
'https://gw.alipayobjects.com/os/basement_prod/7359a5e9-3c5e-453f-b207-bc892fb23b84.csv',
|
|
||||||
);
|
|
||||||
const data = await response.text();
|
|
||||||
const scene = new Scene({
|
|
||||||
id: 'map',
|
|
||||||
map: new GaodeMap({
|
|
||||||
style: 'dark',
|
|
||||||
pitch: 0,
|
|
||||||
center: [110.097892, 33.853662],
|
|
||||||
zoom: 4.056,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
const layer = new HeatmapLayer({
|
|
||||||
enablePicking: true,
|
|
||||||
enableHighlight: true,
|
|
||||||
})
|
|
||||||
.source(data, {
|
|
||||||
parser: {
|
|
||||||
type: 'csv',
|
|
||||||
x: 'lng',
|
|
||||||
y: 'lat',
|
|
||||||
},
|
|
||||||
transforms: [
|
|
||||||
{
|
|
||||||
type: 'grid',
|
|
||||||
size: 10000,
|
|
||||||
field: 'v',
|
|
||||||
method: 'sum',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
.size('count', (value) => {
|
|
||||||
return value * 0;
|
|
||||||
})
|
|
||||||
.shape('square')
|
|
||||||
.style({
|
|
||||||
coverage: 1,
|
|
||||||
angle: 0,
|
|
||||||
})
|
|
||||||
.color(
|
|
||||||
'count',
|
|
||||||
[
|
|
||||||
'#FF3417',
|
|
||||||
'#FF7412',
|
|
||||||
'#FFB02A',
|
|
||||||
'#FFE754',
|
|
||||||
'#46F3FF',
|
|
||||||
'#02BEFF',
|
|
||||||
'#1A7AFF',
|
|
||||||
'#0A1FB2',
|
|
||||||
].reverse(),
|
|
||||||
);
|
|
||||||
scene.addLayer(layer);
|
|
||||||
this.scene = scene;
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
id="map"
|
|
||||||
style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -36,9 +36,6 @@ export default class Point3D extends React.Component {
|
||||||
.scale('point_count', {
|
.scale('point_count', {
|
||||||
type: 'quantile',
|
type: 'quantile',
|
||||||
})
|
})
|
||||||
.filter('point_count', (point_count: number) => {
|
|
||||||
return point_count > 1;
|
|
||||||
})
|
|
||||||
.size('point_count', [5, 10, 15, 20, 25])
|
.size('point_count', [5, 10, 15, 20, 25])
|
||||||
.color('red')
|
.color('red')
|
||||||
.style({
|
.style({
|
||||||
|
@ -46,7 +43,6 @@ export default class Point3D extends React.Component {
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
});
|
});
|
||||||
scene.addLayer(pointLayer);
|
scene.addLayer(pointLayer);
|
||||||
console.log(pointLayer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
|
|
|
@ -38,13 +38,18 @@ export default class AdvancedAPI extends React.Component {
|
||||||
highlightColor: [0, 0, 1, 1],
|
highlightColor: [0, 0, 1, 1],
|
||||||
onHover: (pickedFeature) => {
|
onHover: (pickedFeature) => {
|
||||||
// tslint:disable-next-line:no-console
|
// tslint:disable-next-line:no-console
|
||||||
console.log(pickedFeature);
|
},
|
||||||
|
onClick: (pickedFeature) => {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
layer
|
layer
|
||||||
.source(await response.json())
|
.source(await response.json())
|
||||||
.size('name', [0, 10000, 50000, 30000, 100000])
|
.size('name', [0, 10000, 50000, 30000, 100000])
|
||||||
|
.active({
|
||||||
|
color: 'red',
|
||||||
|
})
|
||||||
.color('name', [
|
.color('name', [
|
||||||
'#2E8AE6',
|
'#2E8AE6',
|
||||||
'#69D1AB',
|
'#69D1AB',
|
||||||
|
@ -58,6 +63,9 @@ export default class AdvancedAPI extends React.Component {
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
});
|
});
|
||||||
scene.addLayer(layer);
|
scene.addLayer(layer);
|
||||||
|
layer.on('click', (e) => {
|
||||||
|
console.log(e);
|
||||||
|
});
|
||||||
|
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
|
|
||||||
|
@ -67,9 +75,10 @@ export default class AdvancedAPI extends React.Component {
|
||||||
const styleOptions = {
|
const styleOptions = {
|
||||||
enablePicking: true,
|
enablePicking: true,
|
||||||
enableHighlight: true,
|
enableHighlight: true,
|
||||||
highlightColor: [0, 0, 255],
|
highlightColor: [1, 0, 0],
|
||||||
pickingX: window.innerWidth / 2,
|
pickingX: window.innerWidth / 2,
|
||||||
pickingY: window.innerHeight / 2,
|
pickingY: window.innerHeight / 2,
|
||||||
|
visible: true,
|
||||||
};
|
};
|
||||||
const pointFolder = gui.addFolder('非鼠标 hover 交互');
|
const pointFolder = gui.addFolder('非鼠标 hover 交互');
|
||||||
pointFolder
|
pointFolder
|
||||||
|
@ -80,23 +89,30 @@ export default class AdvancedAPI extends React.Component {
|
||||||
});
|
});
|
||||||
scene.render();
|
scene.render();
|
||||||
});
|
});
|
||||||
|
pointFolder.add(styleOptions, 'visible').onChange((visible: boolean) => {
|
||||||
|
layer.style({
|
||||||
|
visible,
|
||||||
|
});
|
||||||
|
scene.render();
|
||||||
|
});
|
||||||
pointFolder
|
pointFolder
|
||||||
.add(styleOptions, 'pickingX', 0, window.innerWidth)
|
.add(styleOptions, 'pickingX', 0, window.innerWidth)
|
||||||
.onChange((pickingX: number) => {
|
.onChange((pickingX: number) => {
|
||||||
layer.pick({ x: pickingX, y: styleOptions.pickingY });
|
layer.setActive({ x: pickingX, y: styleOptions.pickingY });
|
||||||
});
|
});
|
||||||
pointFolder
|
pointFolder
|
||||||
.add(styleOptions, 'pickingY', 0, window.innerHeight)
|
.add(styleOptions, 'pickingY', 0, window.innerHeight)
|
||||||
.onChange((pickingY: number) => {
|
.onChange((pickingY: number) => {
|
||||||
layer.pick({ x: styleOptions.pickingX, y: pickingY });
|
layer.setActive({ x: styleOptions.pickingX, y: pickingY });
|
||||||
});
|
});
|
||||||
pointFolder
|
pointFolder
|
||||||
.addColor(styleOptions, 'highlightColor')
|
.addColor(styleOptions, 'highlightColor')
|
||||||
.onChange((highlightColor: number[]) => {
|
.onChange((highlightColor: number[]) => {
|
||||||
const [r, g, b] = highlightColor.map((c) => c / 255);
|
const [r, g, b] = highlightColor.map((c) => c / 255);
|
||||||
layer.style({
|
layer.setActive(
|
||||||
highlightColor: [r, g, b, 1],
|
{ x: styleOptions.pickingX, y: styleOptions.pickingY },
|
||||||
});
|
{ color: [r, g, b, 1] },
|
||||||
|
);
|
||||||
scene.render();
|
scene.render();
|
||||||
});
|
});
|
||||||
pointFolder.open();
|
pointFolder.open();
|
||||||
|
|
Loading…
Reference in New Issue