chore(map): merge master

This commit is contained in:
thinkinggis 2020-07-15 21:08:14 +08:00
commit 5d732176bf
129 changed files with 1764 additions and 434 deletions

97
.github/CONTRIBUTING_ENGLISH.md vendored Normal file
View File

@ -0,0 +1,97 @@
# Contributing to L7
👍🎉 Welcome to contribute code to L7! 🎉👍
## Pre-installation
### Install Yarn
Since Yarn workspace is used, Yarn needs to be installed first: https://yarnpkg.com/en/docs/install#windows-stable
### Windows environment configuration
[The L7 test solution](https://github.com/antvis/L7/blob/master/dev-docs/%E8%87%AA%E5%8A%A8%E5%8C%96%E6%B5%8B%E8%AF%95%E6%96%B9%E6%A1%88.md) relies on headless-gl, which requires node-gyp [to compile local dependencies](https://github.com/nodejs/node-gyp#on-windows).
1. Start PowerShell as an administrator
2. Run `npm install --global --production windows-build-tools` to install Microsoft's windows-build-tools
See [other issues](https://github.com/antvis/L7/issues/101) during installation.
## Install dependencies
Install dependencies and complete Yarn workspace initialization:
```bash
yarn install
```
### Windows
```bash
copy node_modules/gl/deps/windows/dll/x64/*.dll c:\windows\system32
```
## Run DEMO
Start each package code change monitoring:
```bash
yarn watch
```
Start Storybook, it will automatically open `http://localhost:6006/`:
```bash
yarn storybook
```
## Run test
Run unit tests:
```bash
yarn test
```
Run unit tests and view code coverage:
```bash
yarn coveralls
```
## Add Lerna package
Add a new lerna package:
```bash
lerna create my-pack -y
```
Use ui-lib as a dependency of my-pack:
```bash
yarn workspace my-pack add ui-lib/1.0.0
```
Add lodash as a dependency of all packages (excluding root)
```bash
yarn workspaces run add lodash
```
Set typescript to root development dependency:
```bash
yarn add -W -D typescript jest
```
## Submit code
Instead of `git commit`:
```bash
yarn commit
```
## release
### Set the version number
```bash
yarn run version:prerelease
```
After setting, you need to commit the code
### release
yarn run release

View File

@ -37,7 +37,7 @@ module.exports = ({ config }) => {
}
);
config.resolve.alias = {
'@antv/l7-district': path.resolve(__dirname, '../packages/boundry/src'),
'@antv/l7-district': path.resolve(__dirname, '../packages/boundary/src'),
}
config.resolve.extensions.push('.ts', '.tsx', 'css', '.js', '.glsl');

View File

@ -40,7 +40,8 @@ scene.addMarkerLayer(markerLayer);
- field `string` 聚合统计字段
- method `sum| max| min| mean`
- element `function` 通过回调函数设置聚合 Marker 的样式,返回 dom 元素
参数feature
回调函数包含以下参数
point_count 默认 聚合元素个数
clusterData `Array` 聚合节点的原始数据
point_sum 聚合求和 根据 field 和 method 计算

View File

@ -41,9 +41,7 @@ scene.addMarkerLayer(markerLayer);
- field `string` 聚合统计字段
- method `sum| max| min| mean`
- element `function` 通过回调函数设置聚合 Marker 的样式,返回 dom 元素
参数feature
回调函数包含以下参数
- point_count 默认 聚合元素个数
- clusterData `Array` 聚合节点的原始数据
- point_sum 聚合求和 根据 field 和 method 计算

View File

@ -24,6 +24,8 @@ order: 2
- joinBy 数据关联,属性数据如何内部空间数据关联绑定 目前支持 NAME_CHN,adcode 字段连接
对照表 `Array [string, string]` 第一个值为空间数据字段,第二个为传入数据字段名
- depth 数据显示层级 0国家级1:省级2: 市级3线级
- showBorder `boolean` 是否显示国界线,默认显示,不建议不显示
- simplifyTolerance 数据抽稀容差,默认不抽稀 `boolean | number` 单位为度,一度约 111km数字越大精度越低。参考设置数据 0.01
- label 标注配置项 支持常量,不支持数据映射
- enable `boolean` 是否显示标注
@ -91,6 +93,8 @@ District 提供 polygon 数据需要跟用户的属性数据,通过关系字
#### fillLayer
图层事件可以通过该属性进行设置
### 方法
#### updateData(data, joinBy)
@ -102,6 +106,10 @@ District 提供 polygon 数据需要跟用户的属性数据,通过关系字
- data 需要更新的数据
- joinBy 关联字段 可选,如果不设置保持和初始化一致。
### getFillData
获取填充数据,可用于绘制独立的边界线
#### show
显示图层

View File

@ -22,6 +22,7 @@ order: 2
- data `Array` 属性数据用于可视化渲染
- visible 地图是否可见
- joinBy 数据关联,属性数据如何内部空间数据关联绑定 目前支持 NAME_CHN,adcode 字段连接
- simplifyTolerance 数据抽稀容差,默认不抽稀 `boolean | number` 单位为度,一度约 111km数字越大精度越低。参考设置数据 0.01
对照表 `Array [string, string]` 第一个值为空间数据字段,第二个为传入数据字段名
- depth 数据显示层级 0国家级1:省级2: 市级3线级
- label 标注配置项 支持常量,不支持数据映射
@ -34,6 +35,9 @@ order: 2
- strokeWidth 文字描边宽度
- textAllowOverlap 是否允许文字压盖
- opacity 标注透明度
- spacing: `number` 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
- padding: `[number, number]` 文本相对锚点的偏移量 [x, y]
其他包括 text [style 的配置](../layer/point_layer/text#style)
- fill 填充配置项 支持数据映射
- color 图层填充颜色,支持常量和数据映射
@ -41,14 +45,17 @@ order: 2
数据映射
- field 填充映射字段
- values 映射值,同 color 方法第二个参数数组,回调函数
- filter 图层过滤方法,支持常量和数据映射 同 layer.filter 方法
数据映射 - field 填充映射字段 - values 回调函数 `false` 返回值将会被过滤掉
- style 同 polygonLayer 的 style 方法
- activeColor 鼠标滑过高亮颜色
- activeColor 鼠标滑过高亮颜色, `string | boolean` 如果设置为 `false`取消高亮
- bubble 气泡图
- enable `boolean` 是否显示气泡 default false
- color 气泡颜色 支持常量、数据映射
- size 气泡大小 支持常量、数据映射
- shape 气泡形状 支持常量、数据映射
- style 气泡图样式 同 PointLayer
- showBorder `boolean` 是否显示国界线,默认显示,不建议不显示
- stroke 填充描边颜色 `ProvinceLayer, CityLayer, CountyLayer`
- strokeWidth 填充描边宽度 `ProvinceLayer, CityLayer, CountyLayer`
- autoFit 是否自动缩放到图层范围 `boolean`
@ -91,6 +98,8 @@ District 提供 polygon 数据需要跟用户的属性数据,通过关系字
#### fillLayer
图层事件可以通过该属性进行设置
### 方法
#### updateData(data, joinBy)
@ -102,6 +111,10 @@ District 提供 polygon 数据需要跟用户的属性数据,通过关系字
- data 需要更新的数据
- joinBy 关联字段 可选,如果不设置保持和初始化一致。
### getFillData
获取填充数据,可用于绘制独立的边界线
#### show
显示图层

View File

@ -70,6 +70,9 @@ DrillDownLayer 提供默认提供通过 Layer 的交互事件,实现上钻下
- strokeWidth `number` 描边宽度 `2`
- textAllowOverlap: `boolean` 文字是否允许压盖 `true`
- opacity `number` 透明度 `1`
- spacing: `number` 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
- padding: `[number, number]` 文本相对锚点的偏移量 [x, y]
其他包括 text [style 的配置](../layer/point_layer/text#style)
#### bubbleOption

View File

@ -27,7 +27,21 @@ layer.shape('name','text')
### style
- opacity `number`
- textAnchor `string` 文本相对锚点的位置 center|left|right|top|bottom|top-left
- textAnchor `string` 文本相对锚点的位置
`'right'
| 'top-right'
| 'left'
| 'bottom-right'
| 'left'
| 'top-left'
| 'bottom-left'
| 'bottom'
| 'bottom-right'
| 'bottom-left'
| 'top'
| 'top-right'
| 'top-left'
| 'center';`
- spacing: `number` 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
- padding: `[number, number]` 文本相对锚点的偏移量 [x, y]
- stroke: `string`; 描边颜色

View File

@ -3,11 +3,30 @@ title: Layer Component
order: 2
---
## Layer 类型
React 各个组件名称和 L7 名称保持一致
- PointLayer
- PolygonLayer
- LineLayer
- HeatmapLayer
- RasterLayer
- ImageLayer
- CityBuildingLayer
### 使用方式
```jsx
import { PointLayer } '@antv/l7-react';
```
## Layer Props
| prop name | Type | Default | Description |
| ------------- | ------------------------------ | --------------------------------------------------------- | --------------------------------------- |
| option | `layer option` | | layer 配置项 |
| options | `layer options` | | layer 配置项 |
| source | `sourceOption` | | 数据源配置项 |
| color | `attributeOption` | | 颜色通道 |
| shape | `attributeOption` | | 图层形状属性 |
@ -17,17 +36,21 @@ order: 2
| filter | `Function` | | 图层数据过滤方法 |
| select | `boolean` `interaction option` | | 图层选中高亮 |
| active | `boolean` `interaction option` | `false` | 图层 hover 高亮 |
| animate | `animate Option` | `null` | 图层动画配置 |
| onLayerLoaded | `Function` | | 图层添加完成后回调,用于获取 layer 对象 |
### layer option
### layer options
| prop name | Type | Default | Description |
| --------- | --------- | ----------------------- | ---------------------------------------- |
| name | `string` | | 图层名字,可根据名称获取 layer |
| visible | `boolean` | `true` | 图层是否可见 |
| zIndex | `number` | 0 | 图层绘制顺序, |
| minZoom | `number` | 0 | 设置 layer 最小可见等级,小于则不显示 |
| maxZoom | `number` | 与 map 最大缩放等级一致 | 设置 layerd 的最大可见等级,大于则不显示 |
| prop name | Type | Default | Description |
| ------------- | --------- | ----------------------- | -------------------------------------------------------------------------------------------------------- |
| name | `string` | | 图层名字,可根据名称获取 layer |
| visible | `boolean` | `true` | 图层是否可见 |
| zIndex | `number` | 0 | 图层绘制顺序, |
| minZoom | `number` | 0 | 设置 layer 最小可见等级,小于则不显示 |
| maxZoom | `number` | 与 map 最大缩放等级一致 | 设置 layerd 的最大可见等级,大于则不显示 |
| aotoFit | `boolean` | `false` | 是否缩放到图层范围 |
| blend | 'string' | 'normal' | 图层元素混合效果 [详情](../layer/layer/#blend) |
| pickingBuffer | 'number' | '0' | 图层拾取缓存机制,如 1px 宽度的线鼠标很难拾取(点击)到, 通过设置该参数可扩大拾取的范围 {number} default 0 |
### attribute Option
@ -71,19 +94,25 @@ const scales = {
### interaction option
activeselect 配置项
**option**
- color 设置交互的颜色,指滑过或者选中的
```jsx
<>
```
### 获取 layer 对象
#### onLayerLoaded
回调函数获取 layer, scene 对象
onLayerLoaded=(layer, scene) =>{
}
```javascript
onLayerLoaded = (layer, scene) => {};
```
#### Context API

View File

@ -49,7 +49,7 @@ import { PointLayer } '@antv/l7-react';
| minZoom | `number` | 0 | 设置 layer 最小可见等级,小于则不显示 |
| maxZoom | `number` | 与 map 最大缩放等级一致 | 设置 layerd 的最大可见等级,大于则不显示 |
| aotoFit | `boolean` | `false` | 是否缩放到图层范围 |
| blend | 'string' | 'normal' | 图层元素混合效果 [详情]('../layer/layer/#blend') |
| blend | 'string' | 'normal' | 图层元素混合效果 [详情](../layer/layer/#blend) |
| pickingBuffer | 'number' | '0' | 图层拾取缓存机制,如 1px 宽度的线鼠标很难拾取(点击)到, 通过设置该参数可扩大拾取的范围 {number} default 0 |
### attribute Option

View File

@ -3,15 +3,23 @@ title: Scene
order: 1
---
## 使用
在 React 版本中 Mapbox 和高德地图作为两个组件封装的。
```javascript
import { MapboxScene, AmapScene } from '@antv/l7-react';
```
## Scene Props
| prop name | Type | Default | Description |
| ------------- | ---------- | ---------- | -------------------------------------- |
| style | `Object` | `null` | scene css 样式 |
| className | `string` | `null` | 样式名称 |
| map | `Object` | `Required` | map option [地图配置项]() |
| option | `Object` | `void` | scene option 配置项 [详情](#map-props) |
| onSceneLoaded | `Function` | `void` | scene 加载回调函数 |
| prop name | Type | Default | Description |
| ------------- | -------------- | ---------- | ----------------------------------------- |
| style | `Object` | `null` | scene css 样式 |
| className | `string` | `null` | 样式名称 |
| map | `map option` | `Required` | map option [地图配置项](#map-option) |
| option | `scene option` | `void` | scene option 配置项 [详情](#scene-option) |
| onSceneLoaded | `Function` | `void` | scene 加载回调函数 |
### 高德地图场景

View File

@ -13,13 +13,13 @@ import { MapboxScene, AmapScene } from '@antv/l7-react';
## Scene Props
| prop name | Type | Default | Description |
| ------------- | -------------- | ---------- | -------------------------------------- |
| style | `Object` | `null` | scene css 样式 |
| className | `string` | `null` | 样式名称 |
| map | `map option` | `Required` | map option [地图配置项]() |
| option | `scene option` | `void` | scene option 配置项 [详情](#map-props) |
| onSceneLoaded | `Function` | `void` | scene 加载回调函数 |
| prop name | Type | Default | Description |
| ------------- | -------------- | ---------- | ----------------------------------------- |
| style | `Object` | `null` | scene css 样式 |
| className | `string` | `null` | 样式名称 |
| map | `map option` | `Required` | map option [地图配置项](#map-option) |
| option | `scene option` | `void` | scene option 配置项 [详情](#scene-option) |
| onSceneLoaded | `Function` | `void` | scene 加载回调函数 |
### 高德地图场景

View File

@ -134,5 +134,4 @@ const scene = new Scene({
});
```
离线无token使用mapbox [demo](https://codesandbox.io/embed/frosty-architecture-tv6uv?fontsize=14&hidenavigation=1&theme=dark)<br />![image.png](https://cdn.nlark.com/yuque/0/2019/png/104251/1575463410498-0784ce76-743d-4cc4-8d68-964dfd010925.png#align=left&display=inline&height=514&name=image.png&originHeight=514&originWidth=824&size=156914&status=done&style=none&width=824)
[d离线无token使用mapbox demo](https://codesandbox.io/embed/frosty-architecture-tv6uv?fontsize=14&hidenavigation=1&theme=dark)<br />

View File

@ -132,5 +132,4 @@ const scene = new Scene({
});
```
离线无token使用mapbox [demo](https://codesandbox.io/embed/frosty-architecture-tv6uv?fontsize=14&hidenavigation=1&theme=dark)<br />![image.png](https://cdn.nlark.com/yuque/0/2019/png/104251/1575463410498-0784ce76-743d-4cc4-8d68-964dfd010925.png#align=left&display=inline&height=514&name=image.png&originHeight=514&originWidth=824&size=156914&status=done&style=none&width=824)
离线无token使用mapbox [demo](https://codesandbox.io/embed/frosty-architecture-tv6uv?fontsize=14&hidenavigation=1&theme=dark)

View File

@ -86,79 +86,6 @@ 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)
## 不同项目使用模板
不同项目模板在CodeSandbox你可以预览也可以下载到本地

View File

@ -43,6 +43,8 @@ District 支持下面几种图
- joinBy 数据关联,属性数据如何内部空间数据关联绑定 目前支持 NAME_CHN,adcode 字段连接
对照表 `Array [string, string]` 第一个值为空间数据字段,第二个为传入数据字段名
- depth 数据显示层级 0国家级1:省级2: 市级3线级
- showBorder `boolean` 是否显示国界线,默认显示,不建议不显示
- simplifyTolerance 数据抽稀容差,默认不抽稀 `boolean | number` 单位为度一度约111km数字越大精度越低。参考设置数据 0.01
- label 标注配置项 支持常量,不支持数据映射
- enable `boolean` 是否显示标注
- color 标注字体颜色 常量
@ -52,6 +54,9 @@ District 支持下面几种图
- strokeWidth 文字描边宽度
- textAllowOverlap 是否允许文字压盖
- opacity 标注透明度
- spacing: `number` 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
- padding: `[number, number]` 文本相对锚点的偏移量 [x, y]
其他包括 text [style 的配置](../layer/point_layer/text#style)
- fill 填充配置项 支持数据映射
- color 图层填充颜色,支持常量和数据映射
常量:统一设置成一样的颜色
@ -66,6 +71,7 @@ District 支持下面几种图
- size 气泡大小 支持常量、数据映射
- shape 气泡形状 支持常量、数据映射
- style 气泡图样式 同 PointLayer
- stroke 填充描边颜色
- strokeWidth 填充描边宽度
- autoFit 是否自动缩放到图层范围 `boolean`
@ -101,6 +107,8 @@ District 提供polygon数据需要跟用户的属性数据通过关系字段
行政区划组件每个图层有多个子图层组成,如标注层,国界线、省界线等等,
#### fillLayer
图层事件可以通过该属性进行设置
### 方法
@ -111,6 +119,10 @@ District 提供polygon数据需要跟用户的属性数据通过关系字段
- data 需要更新的数据
- joinBy 关联字段 可选,如果不设置保持和初始化一致。
### getFillData
获取填充数据,可用于绘制独立的边界线
#### show
显示图层

View File

@ -19,7 +19,6 @@ import { WorldLayer } from '@antv/l7-district';
<script src="https://unpkg.com/@antv/l7-district"></script>
</head>
```
⚠️⚠️⚠️ District 相关配置和接口还在完善中,你可以适用体验,某些配置和接口可能会进行调整
## 简介
@ -41,6 +40,8 @@ District 支持下面几种图
- visible 地图是否可见
- joinBy 数据关联,属性数据如何内部空间数据关联绑定 目前支持 NAME_CHN,adcode 字段连接
对照表 `Array [string, string]` 第一个值为空间数据字段,第二个为传入数据字段名
- showBorder `boolean` 是否显示国界线,默认显示,不建议不显示
- simplifyTolerance 数据抽稀容差,默认不抽稀 `boolean | number` 单位为度一度约111km数字越大精度越低。参考设置数据 0.01
- depth 数据显示层级 0国家级1:省级2: 市级3线级
- label 标注配置项 支持常量,不支持数据映射
- enable `boolean` 是否显示标注
@ -51,19 +52,31 @@ District 支持下面几种图
- strokeWidth 文字描边宽度
- textAllowOverlap 是否允许文字压盖
- opacity 标注透明度
- spacing: `number` 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
- padding: `[number, number]` 文本相对锚点的偏移量 [x, y]
其他包括 text [style 的配置](../layer/point_layer/text#style)
- fill 填充配置项 支持数据映射
- color 图层填充颜色,支持常量和数据映射
常量:统一设置成一样的颜色
数据映射
- field 填充映射字段
- values 映射值同color方法第二个参数数组回调函数
- filter 图层过滤方法,支持常量和数据映射 同layer.filter方法
数据映射
- field 填充映射字段
- values 回调函数 `false` 返回值将会被过滤掉
- style 同 polygonLayer的style方法
- activeColor 鼠标滑过高亮颜色
- activeColor 鼠标滑过高亮颜色, `string | boolean` 如果设置为 `false`取消高亮
- bubble 气泡图
- enable `boolean` 是否显示气泡 default false
- color 气泡颜色 支持常量、数据映射
- size 气泡大小 支持常量、数据映射
- shape 气泡形状 支持常量、数据映射
- filter 图层过滤方法,支持常量和数据映射 同layer.filter方法
数据映射
- field 填充映射字段
- values 回调函数 `false` 返回值将会被过滤掉
- style 气泡图样式 同 PointLayer
- stroke 填充描边颜色 `ProvinceLayer, CityLayer, CountyLayer`
- strokeWidth 填充描边宽度 `ProvinceLayer, CityLayer, CountyLayer`
@ -102,6 +115,7 @@ District 提供polygon数据需要跟用户的属性数据通过关系字段
行政区划组件每个图层有多个子图层组成,如标注层,国界线、省界线等等,
#### fillLayer
图层事件可以通过该属性进行设置
### 方法
@ -112,6 +126,10 @@ District 提供polygon数据需要跟用户的属性数据通过关系字段
- data 需要更新的数据
- joinBy 关联字段 可选,如果不设置保持和初始化一致。
### getFillData
获取填充数据,可用于绘制独立的边界线
#### show
显示图层

View File

@ -0,0 +1,98 @@
import { Scene } from '@antv/l7';
import { CountryLayer } from '@antv/l7-district';
import { Mapbox } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new Mapbox({
center: [ 116.2825, 39.9 ],
pitch: 0,
style: 'blank',
zoom: 3,
minZoom: 0,
maxZoom: 10
})
});
const attachMapContainer = document.createElement('div');
attachMapContainer.id = 'attach';
attachMapContainer.style.cssText = `position: absolute;
height: 125px;
width: 98px;
right: 50px;
bottom: 20px;
border: 1px solid #333;`;
document.getElementById('map').parentElement.append(attachMapContainer);
scene.on('loaded', () => {
new CountryLayer(scene, {
data: [],
joinBy: [ 'NAME_CHN', 'name' ],
depth: 1,
provinceStroke: '#783D2D',
cityStroke: '#EBCCB4',
cityStrokeWidth: 1,
label: {
enable: false
},
fill: {
color: {
field: 'NAME_CHN',
values: [
'#feedde',
'#fdd0a2',
'#fdae6b',
'#fd8d3c',
'#e6550d',
'#a63603'
]
}
},
popup: {
enable: true,
Html: props => {
return `<span>${props.NAME_CHN}</span>`;
}
}
});
});
// 添加附图,附图需要和主图保持一致
const scene2 = new Scene({
id: 'attach',
logoVisible: false,
map: new Mapbox({
center: [ 113.60540108435657, 12.833692637803168 ],
pitch: 0,
style: 'blank',
zoom: 1.93,
minZoom: 0,
maxZoom: 3,
interactive: false
})
});
scene2.on('loaded', () => {
new CountryLayer(scene2, {
data: [],
label: {
enable: false
},
popup: {
enable: false
},
autoFit: false,
depth: 1,
fill: {
color: {
field: 'NAME_CHN',
values: [
'#feedde',
'#fdd0a2',
'#fdae6b',
'#fd8d3c',
'#e6550d',
'#a63603'
]
}
}
});
});

View File

@ -0,0 +1,106 @@
import { Scene } from '@antv/l7';
import { ProvinceLayer, CountryLayer } from '@antv/l7-district';
import { Mapbox } from '@antv/l7-maps';
async function initMap() {
const scene = new Scene({
id: 'map',
map: new Mapbox({
center: [ 109.803, 19.347 ],
pitch: 0,
style: 'blank',
zoom: 7,
minZoom: 6,
maxZoom: 11
})
});
const attachMapContainer = document.createElement('div');
attachMapContainer.id = 'attach';
attachMapContainer.style.cssText = `position: absolute;
height: 125px;
width: 98px;
right: 50px;
bottom: 20px;
border: 1px solid #333;`;
document.getElementById('map').parentElement.append(attachMapContainer);
scene.on('loaded', () => {
new ProvinceLayer(scene, {
data: [],
geoDataLevel: 1,
autoFit: false,
joinBy: [ 'adcode', 'code' ],
adcode: [ '460000' ],
depth: 2,
stroke: '#aaa',
label: {
enable: false,
field: 'NAME_CHN',
textAllowOverlap: false
},
fill: {
color: '#A3d7FF'
},
popup: {
enable: false,
Html: props => {
return `<span>${props.NAME_CHN}:</span><span>${props.pop}</span>`;
}
}
});
});
const scene2 = new Scene({
id: 'attach',
logoVisible: false,
map: new Mapbox({
center: [ 113.60540108435657, 12.833692637803168 ],
pitch: 0,
style: 'blank',
zoom: 1.93,
// zoom: 3,
minZoom: 0,
maxZoom: 3,
interactive: false
})
});
scene2.on('loaded', () => {
new CountryLayer(scene2, {
data: [],
label: {
enable: false
},
popup: {
enable: false
},
autoFit: false,
provinceStroke: '#aaa',
depth: 1,
fill: {
color: '#A3d7FF'
}
});
new ProvinceLayer(scene2, {
data: [],
autoFit: false,
adcode: [ '460000' ],
depth: 2,
zIndex: 2,
stroke: '#aaa',
strokeWidth: 0.1,
label: {
enable: false,
field: 'NAME_CHN',
textAllowOverlap: false
},
fill: {
color: '#A3d7ff'
},
popup: {
enable: false,
Html: props => {
return `<span>${props.NAME_CHN}:</span><span>${props.pop}</span>`;
}
}
});
});
}
initMap();

View File

@ -28,6 +28,16 @@
"filename": "county.js",
"title": "中国县地图",
"screenshot": "https://gw.alipayobjects.com/mdn/rms_8e1672/afts/img/A*iVwLSpIf_ckAAAAAAAAAAABkARQnAQ"
},
{
"filename": "attach_map.js",
"title": "中国地图附图",
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*bGX-Tbw5uVAAAAAAAAAAAABkARQnAQ"
},
{
"filename": "hainan.js",
"title": "海南省地图",
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*nHOTQ61hFbYAAAAAAAAAAABkARQnAQ"
}
]
}

View File

@ -217,7 +217,7 @@ class Province extends React.Component {
const { province } = this.state;
this.provinceLayer = new ProvinceLayer(scene, {
adcode: ['230000'],
depth: 3,
depth: 1,
label: {
field: 'NAME_CHN',
textAllowOverlap: false,

View File

@ -1,9 +1,9 @@
import { Scene, HeatmapLayer } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
import { GaodeMap } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new Mapbox({
map: new GaodeMap({
style: 'dark',
pitch: 58.5,
center: [ 111.8759, 30.6942 ],

View File

@ -7,7 +7,7 @@ const World = React.memo(function Map() {
React.useEffect(() => {
const fetchData = async () => {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/68dc6756-627b-4e9e-a5ba-e834f6ba48f8.json'
'https://gw.alipayobjects.com/os/antvdemo/assets/data/world.geo.json'
);
const data = await response.json();
setData(data);

View File

@ -0,0 +1,63 @@
import { PolygonLayer, LineLayer, Scene } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new GaodeMap({
style: 'light',
pitch: 0,
center: [ 118.7368, 32.0560 ],
zoom: 9
})
});
scene.on('loaded', () => {
fetch(
'https://gw.alipayobjects.com/os/basement_prod/91247d10-585b-4406-b1e2-93b001e3a0e4.json'
)
.then(res => res.json())
.then(data => {
const filllayer = new PolygonLayer({
name: 'fill'
})
.source(data)
.shape('fill')
.color('unit_price', [ '#f0f9e8', '#ccebc5', '#a8ddb5', '#7bccc4', '#43a2ca', '#0868ac' ])
.style({
opacity: 1
});
const linelayer = new LineLayer({
zIndex: 1,
name: 'line'
})
.source(data)
.shape('line')
.size(0.5)
.color('#fff')
.style({
opacity: 0.5
});
const hightLayer = new LineLayer({
zIndex: 4, // 设置显示层级
name: 'hightlight'
})
.source({
type: 'FeatureCollection',
features: [ ]
})
.shape('line')
.size(2)
.color('red')
.style({
opacity: 1
});
scene.addLayer(filllayer);
scene.addLayer(linelayer);
scene.addLayer(hightLayer);
filllayer.on('click', feature => {
console.log(feature);
hightLayer.setData({
type: 'FeatureCollection',
features: [ feature.feature ]
});
});
});
});

View File

@ -0,0 +1,17 @@
import { Scale, Zoom, Scene } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new Mapbox({
style: 'light',
pitch: 0,
center: [ 107.054293, 35.246265 ],
zoom: 4.056
})
});
scene.on('loaded', () => {
const zoomControl = new Zoom();
const scaleControl = new Scale();
scene.addControl(zoomControl);
scene.addControl(scaleControl);
});

View File

@ -0,0 +1,18 @@
{
"title": {
"zh": "地图",
"en": "Category"
},
"demos": [
{
"filename": "amap.js",
"title": "高德底图组件",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*yXzQRYcGTyoAAAAAAAAAAABkARQnAQ"
},
{
"filename": "mapbox.js",
"title": "MapBox底图组件",
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*_SIYR50bbcoAAAAAAAAAAABkARQnAQ"
}
]
}

View File

@ -0,0 +1,5 @@
---
title: Layer
order: 2
---
How to use the map control

View File

@ -0,0 +1,5 @@
---
title: 图层
order: 2
---
图层初始化与交互

View File

@ -21,6 +21,6 @@ exports.onCreateWebpackConfig = ({ getConfig }) => {
'@antv/l7-utils': path.resolve(__dirname, 'packages/utils/src'),
'@antv/l7-react': path.resolve(__dirname, 'packages/react/src'),
'@antv/l7-draw': path.resolve(__dirname, 'packages/draw/src'),
'@antv/l7-district': path.resolve(__dirname, 'packages/boundry/src')
'@antv/l7-district': path.resolve(__dirname, 'packages/boundary/src')
};
};

View File

@ -14,7 +14,7 @@
"message": "chore: publish"
}
},
"version": "2.2.14",
"version": "2.2.21",
"npmClient": "yarn",
"useWorkspaces": true,
"publishConfig": {

View File

@ -0,0 +1,34 @@
// import { WorldLayer } from '@antv/l7-district';
describe('baseLayer', () => {
it('set option', () => {
const option = {
adcode: [],
data: [
{
name: 1,
code: 2,
},
{
name: 2,
code: 3,
},
{
name: 3,
code: 4,
},
],
};
// @ts-ignore
// const layer = new WorldLayer(null, option);
// layer.setOption({
// data: [
// {
// name: 1,
// code: 4,
// },
// ],
// });
// // @ts-ignore
// expect(layer.options.data.length).toBe(1);
});
});

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-district",
"version": "2.2.14",
"version": "2.2.21",
"description": "L7 district moudules",
"keywords": [],
"author": "thinkinggis <lzx199065@gmail.com>",
@ -34,7 +34,7 @@
"test": "jest"
},
"dependencies": {
"@antv/l7": "2.2.14",
"@antv/l7": "2.2.21",
"@babel/runtime": "^7.7.7",
"@turf/circle": "^6.0.1",
"@turf/distance": "^6.0.1",
@ -44,7 +44,8 @@
"eventemitter3": "^4.0.0",
"geobuf": "^3.0.1",
"lodash": "^4.6.2",
"pbf": "^3.2.1"
"pbf": "^3.2.1",
"simplify-geojson": "^1.0.3"
},
"bugs": {
"url": "https://github.com/antvis/L7/issues"
@ -55,5 +56,6 @@
"postcss-url": "^8.0.0",
"rollup": "^2.3.3",
"rollup-plugin-less": "^1.1.2"
}
},
"gitHead": "20154fe30d512024b03ac5e40f77731bc0580bb0"
}

View File

@ -1,18 +1,18 @@
// tslint:disable-next-line:no-submodule-imports
import merge from 'lodash/merge';
let DataLevel = 2;
let DataLevel = 2; // d
const dataLevel2: { [key: string]: any } = {
world: {
fill: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/e66cdd3f-cd41-4533-9746-d8fdbe0a0056.bin',
'https://gw.alipayobjects.com/os/bmw-prod/ad26cd25-96ea-40fd-935d-7e21a5c08893.bin',
},
line: {
type: 'pbf',
url:
'https://gw.alipayobjects.com/os/bmw-prod/f1b0fd97-ac90-4adb-b99c-01709e0e52c8.bin',
'https://gw.alipayobjects.com/os/bmw-prod/62f61f5f-cca7-4137-845d-13c8f9969664.bin',
},
label: {
type: 'pbf',
@ -127,17 +127,17 @@ const dataLevel1: { [key: string]: any } = {
fill: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/56cb34eb-cf61-4512-a6f3-fe4a45a7b1a3.bin',
'https://gw.alipayobjects.com/os/bmw-prod/35bb8365-1926-471c-b357-db2c02ff3a81.bin',
},
line: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/76914518-e04c-42c9-8c4b-1ae71aabb024.bin',
'https://gw.alipayobjects.com/os/bmw-prod/8ec671c3-a4f9-4fdf-8e88-85d2ab1d8930.bin',
},
label: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/90c51eb3-04d7-402f-bd05-95e4bd27dd62.bin',
'https://gw.alipayobjects.com/os/bmw-prod/90c51eb3-04d7-402f-bd05-95e4bd27dd62.bin',
parser: {
type: 'geojson',
},
@ -145,7 +145,7 @@ const dataLevel1: { [key: string]: any } = {
nationalBoundaries: {
type: 'json',
url:
'//gw.alipayobjects.com/os/bmw-prod/ee493a41-0558-4c0e-bee6-520276c4f1a8.json',
'https://gw.alipayobjects.com/os/bmw-prod/ee493a41-0558-4c0e-bee6-520276c4f1a8.json',
},
},
country: {
@ -154,29 +154,29 @@ const dataLevel1: { [key: string]: any } = {
fill: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/70ec087e-c48a-4b76-8825-6452f17bae7a.bin',
'https://gw.alipayobjects.com/os/bmw-prod/380370e0-76aa-4240-8874-5732de77e71d.bin',
},
line: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/70ec087e-c48a-4b76-8825-6452f17bae7a.bin',
'https://gw.alipayobjects.com/os/bmw-prod/70ec087e-c48a-4b76-8825-6452f17bae7a.bin',
},
provinceLine: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/778ad7ba-5a3f-4ed6-a94a-b8ab8acae9d6.bin',
'https://gw.alipayobjects.com/os/bmw-prod/778ad7ba-5a3f-4ed6-a94a-b8ab8acae9d6.bin',
},
label: {
type: 'json',
url:
'//gw.alipayobjects.com/os/bmw-prod/36832a45-68f8-4b51-b006-9dec71f92a23.json',
'https://gw.alipayobjects.com/os/bmw-prod/36832a45-68f8-4b51-b006-9dec71f92a23.json',
},
},
2: {
fill: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/561e2cfe-9460-42d1-a2f8-3fd2e1274c52.bin',
'https://gw.alipayobjects.com/os/bmw-prod/feeb1f06-11c6-4495-84c9-f41ea6f77123.bin',
},
line: {
type: 'pbf',
@ -198,43 +198,43 @@ const dataLevel1: { [key: string]: any } = {
fill: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/516b2703-d692-44e6-80dd-b3f5df0186e7.bin',
'https://gw.alipayobjects.com/os/bmw-prod/24a9ee83-2be1-4fc1-b187-769ac939269d.bin',
},
line: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/bc97875a-90f2-42c0-a62c-43d2efd7460d.bin',
'https://gw.alipayobjects.com/os/bmw-prod/bc97875a-90f2-42c0-a62c-43d2efd7460d.bin',
},
countryLine: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/bc97875a-90f2-42c0-a62c-43d2efd7460d.bin',
'https://gw.alipayobjects.com/os/bmw-prod/bc97875a-90f2-42c0-a62c-43d2efd7460d.bin',
},
cityLine: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/8bfbfe7e-bd0e-4bbe-84d8-629f4dc7abc4.bin',
'https://gw.alipayobjects.com/os/bmw-prod/8bfbfe7e-bd0e-4bbe-84d8-629f4dc7abc4.bin',
},
provinceLine: {
type: 'pbf',
url:
'//gw.alipayobjects.com/os/bmw-prod/778ad7ba-5a3f-4ed6-a94a-b8ab8acae9d6.bin',
'https://gw.alipayobjects.com/os/bmw-prod/778ad7ba-5a3f-4ed6-a94a-b8ab8acae9d6.bin',
},
},
nationalBoundaries: {
type: 'json',
url:
'//gw.alipayobjects.com/os/bmw-prod/ee493a41-0558-4c0e-bee6-520276c4f1a8.json',
'https://gw.alipayobjects.com/os/bmw-prod/ee493a41-0558-4c0e-bee6-520276c4f1a8.json',
},
nationalBoundaries2: {
type: 'json',
url:
'//gw.alipayobjects.com/os/bmw-prod/f2189cc4-662b-4358-8573-36f0f918b7ca.json',
'https://gw.alipayobjects.com/os/bmw-prod/f2189cc4-662b-4358-8573-36f0f918b7ca.json',
},
island: {
type: 'json',
url:
'//gw.alipayobjects.com/os/bmw-prod/fe49b393-1147-4769-94ed-70471f4ff15d.json',
'https://gw.alipayobjects.com/os/bmw-prod/fe49b393-1147-4769-94ed-70471f4ff15d.json',
},
},
},

View File

@ -17,6 +17,8 @@ import isObject from 'lodash/isObject';
import mergeWith from 'lodash/mergeWith';
// @ts-ignore
import Pbf from 'pbf';
// @ts-ignore
import simplify from 'simplify-geojson';
import { setDataLevel } from '../config';
import { AttributeType, IDistrictLayerOption } from './interface';
@ -56,7 +58,11 @@ export default class BaseLayer extends EventEmitter {
}
public setOption(newOption: { [key: string]: any }) {
this.options = mergeWith(this.options, newOption);
this.options = mergeWith(this.options, newOption, mergeCustomizer);
}
public getFillData() {
return this.fillData;
}
public updateData(
@ -85,7 +91,10 @@ export default class BaseLayer extends EventEmitter {
protected async fetchData(data: { url: any; type: string }) {
if (data.type === 'pbf') {
const buffer = await (await fetch(data.url)).arrayBuffer();
const geojson = geobuf.decode(new Pbf(buffer));
let geojson = geobuf.decode(new Pbf(buffer));
if (this.options.simplifyTolerance !== false) {
geojson = simplify(geojson, this.options.simplifyTolerance);
}
return geojson;
} else {
return isObject(data.url) ? data.url : (await fetch(data.url)).json();
@ -99,15 +108,18 @@ export default class BaseLayer extends EventEmitter {
depth: 1,
adcode: [],
joinBy: ['name', 'name'],
simplifyTolerance: false,
label: {
enable: true,
color: '#000',
field: 'name',
size: 8,
size: 10,
stroke: '#fff',
strokeWidth: 2,
textAllowOverlap: true,
opacity: 1,
textOffset: [0, 0],
padding: [5, 5],
},
bubble: {
enable: false,
@ -126,16 +138,19 @@ export default class BaseLayer extends EventEmitter {
style: {
opacity: 1.0,
},
activeColor: 'rgba(0,0,255,0.3)',
activeColor: false,
},
autoFit: true,
showBorder: true,
stroke: '#bdbdbd',
strokeVisible: true,
strokeWidth: 0.6,
cityStroke: '#636363',
cityStrokeWidth: 0.6,
countyStrokeWidth: 0.6,
provinceStrokeWidth: 0.6,
provinceStroke: '#f0f0f0',
provinceStrokeVisible: true,
countyStroke: '#525252',
coastlineStroke: '#4190da',
coastlineWidth: 0.6,
@ -176,18 +191,20 @@ export default class BaseLayer extends EventEmitter {
],
});
this.setLayerAttribute(fillLayer, 'color', fill.color as AttributeType);
this.setLayerAttribute(fillLayer, 'filter', fill.filter as AttributeType);
if (fill.scale && isObject(fill.color)) {
fillLayer.scale('color', {
type: fill.scale,
field: fill.color.field as string,
});
}
fillLayer
.shape('fill')
.active({
fillLayer.shape('fill').style(fill.style);
if (fill.activeColor) {
fillLayer.active({
color: fill.activeColor as string,
})
.style(fill.style);
});
}
this.fillLayer = fillLayer;
this.layers.push(fillLayer);
this.scene.addLayer(fillLayer);
@ -256,6 +273,11 @@ export default class BaseLayer extends EventEmitter {
this.setLayerAttribute(bubbleLayer, 'color', bubble.color as AttributeType);
this.setLayerAttribute(bubbleLayer, 'size', bubble.size as AttributeType);
this.setLayerAttribute(bubbleLayer, 'shape', bubble.shape as AttributeType);
this.setLayerAttribute(
bubbleLayer,
'filter',
bubble.filter as AttributeType,
);
if (bubble.scale) {
bubbleLayer.scale(bubble.scale.field, {
type: bubble.scale.type,
@ -271,7 +293,7 @@ export default class BaseLayer extends EventEmitter {
protected addLabel(labelData: any, type: string = 'json') {
const { label, zIndex, visible } = this.options;
const labelLayer = new PointLayer({
zIndex: zIndex + 0.4,
zIndex: zIndex + 5,
visible,
})
.source(labelData, {
@ -280,15 +302,11 @@ export default class BaseLayer extends EventEmitter {
coordinates: 'center',
},
})
.color(label.color as StyleAttrField)
.shape(label.field as StyleAttrField, 'text')
.size(10)
.style({
opacity: label.opacity,
stroke: label.stroke,
strokeWidth: label.strokeWidth,
textAllowOverlap: label.textAllowOverlap,
});
.style(label);
this.setLayerAttribute(labelLayer, 'color', label.color as AttributeType);
this.setLayerAttribute(labelLayer, 'size', label.size as AttributeType);
this.setLayerAttribute(labelLayer, 'filter', label.filter);
return labelLayer;
}
@ -325,12 +343,17 @@ export default class BaseLayer extends EventEmitter {
private setLayerAttribute(
layer: ILayer,
type: 'color' | 'size' | 'shape',
attr: AttributeType,
type: 'color' | 'size' | 'shape' | 'filter',
attr: AttributeType | undefined,
) {
if (!attr) {
return;
}
if (isObject(attr)) {
// @ts-ignore
layer[type](attr.field, attr.values);
} else {
// @ts-ignore
layer[type](attr);
}
}

View File

@ -1,4 +1,4 @@
import { LineLayer, PointLayer, Scene, StyleAttrField } from '@antv/l7';
import { AttributeType, LineLayer, PointLayer, Scene } from '@antv/l7';
import { getDataConfig } from '../index';
import BaseLayer from './baseLayer';
import { IDistrictLayerOption } from './interface';
@ -6,20 +6,20 @@ import { IDistrictLayerOption } from './interface';
export default class CountryLayer extends BaseLayer {
constructor(scene: Scene, option: Partial<IDistrictLayerOption> = {}) {
super(scene, option);
const { depth } = this.options;
const { depth, showBorder } = this.options;
this.addProvinceFill();
this.addProvinceLabel();
const countryConfig = getDataConfig(this.options.geoDataLevel).country.CHN[
depth
];
this.addProvinceLine(countryConfig.provinceLine);
if (depth === 2 * 1) {
this.addCityBorder(countryConfig.fill);
}
if (depth === 3 * 1) {
this.addCountyBorder(countryConfig.fill);
if (showBorder) {
this.addProvinceLine(countryConfig.provinceLine);
if (depth === 2 * 1) {
this.addCityBorder(countryConfig.fill);
}
if (depth === 3 * 1) {
this.addCountyBorder(countryConfig.fill);
}
}
}
protected async addProvinceFill() {
@ -127,6 +127,7 @@ export default class CountryLayer extends BaseLayer {
chinaNationalWidth,
coastlineStroke,
coastlineWidth,
showBorder,
stroke,
strokeWidth,
visible,
@ -135,7 +136,7 @@ export default class CountryLayer extends BaseLayer {
// 添加国界线
const lineLayer = new LineLayer({
zIndex: zIndex + 0.1,
visible,
visible: visible && showBorder,
})
.source(boundaries)
.size('type', (v: string) => {
@ -152,11 +153,11 @@ export default class CountryLayer extends BaseLayer {
.shape('line')
.color('type', (v: string) => {
if (v === '3') {
return provinceStroke;
return provinceStroke; // 省界
} else if (v === '2') {
return coastlineStroke;
return coastlineStroke; // 海岸线
} else if (v === '0') {
return chinaNationalStroke;
return chinaNationalStroke; // 中国国界线
} else {
return '#fff';
}
@ -164,7 +165,7 @@ export default class CountryLayer extends BaseLayer {
// 添加未定国界
const lineLayer2 = new LineLayer({
zIndex: zIndex + 0.1,
visible,
visible: visible && showBorder,
})
.source(boundaries2)
.size(chinaNationalWidth)
@ -178,7 +179,7 @@ export default class CountryLayer extends BaseLayer {
// 添加澳门香港界限
const lineLayer3 = new LineLayer({
zIndex: zIndex + 0.1,
visible,
visible: visible && showBorder,
})
.source(boundaries3)
.size(provinceStrokeWidth)
@ -262,9 +263,9 @@ export default class CountryLayer extends BaseLayer {
coordinates: 'center',
},
})
.color(label.color as StyleAttrField)
.color(label.color as AttributeType)
.shape('name', 'text')
.size(10)
.size(label.size as AttributeType)
.style({
opacity: label.opacity,
stroke: label.stroke,

View File

@ -184,7 +184,7 @@ export default class DrillDownLayer {
}
private getLayerOption(type: 'province' | 'city' | 'county') {
const { joinBy, label, bubble, fill, popup, province } = this.options;
const { joinBy, label, bubble, fill, popup, geoDataLevel } = this.options;
const datatype = (type + 'Data') as
| 'provinceData'
| 'cityData'
@ -196,6 +196,7 @@ export default class DrillDownLayer {
bubble,
fill,
popup,
geoDataLevel,
...this.options[type],
};
}

View File

@ -4,15 +4,37 @@ import {
StyleAttributeField,
StyleAttributeOption,
} from '@antv/l7';
export type anchorType =
| 'right'
| 'top-right'
| 'left'
| 'bottom-right'
| 'left'
| 'top-left'
| 'bottom-left'
| 'bottom'
| 'bottom-right'
| 'bottom-left'
| 'top'
| 'top-right'
| 'top-left'
| 'center';
export interface ILabelOption {
enable: boolean;
color: string;
color: AttributeType;
field: string;
size: number;
size: AttributeType;
stroke: string;
strokeWidth: number;
textAllowOverlap: boolean;
padding: [number, number];
strokeOpacity: number;
fontWeight: number;
spacing: number;
textAnchor: anchorType;
textOffset: [number, number];
opacity: number;
filter: AttributeType;
}
export interface IAttributeOption {
@ -36,7 +58,8 @@ export interface IFillOptions {
color: AttributeType;
values: StyleAttributeOption;
style: any;
activeColor: string;
activeColor: string | boolean;
filter: AttributeType;
}
export type TriggeEventType =
| 'mousemove'
@ -60,6 +83,7 @@ export interface IBubbleOption {
shape: AttributeType;
size: AttributeType;
color: AttributeType;
filter: AttributeType;
scale: {
field: string;
type: ScaleTypeName;
@ -78,14 +102,18 @@ export interface IDistrictLayerOption {
data?: Array<{ [key: string]: any }>;
joinBy: [string, string];
adcode: adcodeType;
simplifyTolerance: number | boolean;
depth: 0 | 1 | 2 | 3;
label: Partial<ILabelOption>;
bubble: Partial<IBubbleOption>;
fill: Partial<IFillOptions>;
showBorder: boolean;
autoFit: boolean;
stroke: string;
strokeVisible: boolean;
strokeWidth: number;
provinceStroke: string;
provinceStrokeVisible: boolean;
cityStroke: string;
provinceStrokeWidth: number;
cityStrokeWidth: number;
@ -107,6 +135,7 @@ interface IDrawOption {
}
export interface IDrillDownOption {
drillDepth: 0 | 1 | 2;
geoDataLevel: 1 | 2;
customTrigger: boolean;
drillDownTriggerEvent: TriggeEventType;
drillUpTriggerEvent: TriggeEventType & DrillUpTriggeEventType;

View File

@ -34,6 +34,7 @@ export default class ProvinceLayer extends BaseLayer {
this.hide();
return;
}
const { label, showBorder } = this.options;
this.setOption({ adcode });
const fillData = this.filterData(this.fillRawData, adcode);
const lineData = this.filterData(this.lineRawData, adcode);
@ -49,8 +50,13 @@ export default class ProvinceLayer extends BaseLayer {
}
this.fillData = fillData;
this.updateData(newData, joinByField);
this.lineLayer.setData(lineData);
this.labelLayer.setData(labelData);
if (showBorder) {
this.lineLayer.setData(lineData);
}
if (label.enable) {
this.labelLayer.setData(labelData);
}
this.show();
}
@ -96,7 +102,8 @@ export default class ProvinceLayer extends BaseLayer {
return features;
}
private async addProvinceFillLayer() {
const { depth, adcode } = this.options as IProvinceLayerOption;
const { depth, adcode, label, showBorder } = this
.options as IProvinceLayerOption;
const countryConfig = getDataConfig(this.options.geoDataLevel).country.CHN[
depth
];
@ -109,12 +116,17 @@ export default class ProvinceLayer extends BaseLayer {
};
});
const data = this.filterData(fillData, adcode);
this.fillData = data;
const labelData = this.filterLabelData(this.labelRawData, adcode);
this.fillRawData = fillData;
this.addFillLayer(data);
this.addLabelLayer(labelData);
if (label.enable) {
this.addLabelLayer(labelData);
}
this.lineRawData = fillData;
this.addFillLine(data);
if (showBorder) {
this.addFillLine(data);
}
}
private async addProvinceLineLayer() {

View File

@ -14,7 +14,9 @@ export default class WorldLayer extends BaseLayer {
super(scene, option);
this.loadData().then(([fillData, lineData, fillLabel]) => {
this.addFillLayer(fillData);
this.addFillLine(lineData);
if (this.options.showBorder) {
this.addFillLine(lineData);
}
if (this.options.label?.enable) {
this.addLabelLayer(fillLabel, 'json');
}

View File

@ -1,9 +0,0 @@
import BaseLayer from '../src/layer/baseLayer';
describe('baseLayer', () => {
it('set option', () => {
const option = {
adcode: [],
};
// const layer = new BaseLayer(null, option);
});
});

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-component",
"version": "2.2.14",
"version": "2.2.21",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
@ -24,14 +24,14 @@
"author": "lzxue",
"license": "ISC",
"dependencies": {
"@antv/l7-core": "2.2.14",
"@antv/l7-utils": "2.2.14",
"@antv/l7-core": "2.2.21",
"@antv/l7-utils": "2.2.21",
"@babel/runtime": "^7.7.7",
"eventemitter3": "^4.0.0",
"inversify": "^5.0.1",
"load-styles": "^2.0.0"
},
"gitHead": "532ade40831b35b04a677b351d092e54c00613d8",
"gitHead": "20154fe30d512024b03ac5e40f77731bc0580bb0",
"publishConfig": {
"access": "public"
}

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-core",
"version": "2.2.14",
"version": "2.2.21",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
@ -23,7 +23,7 @@
"license": "ISC",
"dependencies": {
"@antv/async-hook": "^2.1.0",
"@antv/l7-utils": "2.2.14",
"@antv/l7-utils": "2.2.21",
"@babel/runtime": "^7.7.7",
"@mapbox/tiny-sdf": "^1.1.1",
"ajv": "^6.10.2",
@ -46,7 +46,7 @@
"@types/lodash": "^4.14.138",
"@types/viewport-mercator-project": "^6.1.0"
},
"gitHead": "532ade40831b35b04a677b351d092e54c00613d8",
"gitHead": "20154fe30d512024b03ac5e40f77731bc0580bb0",
"publishConfig": {
"access": "public"
}

View File

@ -19,6 +19,7 @@ export interface IICONMap {
export interface IIconService {
canvasHeight: number;
on(event: string, fn: EventEmitter.ListenerFn, context?: any): this;
off(event: string, fn: EventEmitter.ListenerFn, context?: any): this;
init(): void;
addImage(id: string, image: IImage): void;
hasImage(id: string): boolean;

View File

@ -57,7 +57,9 @@ export interface ILayerModel {
getDefaultStyle(): unknown;
getAnimateUniforms(): IModelUniform;
buildModels(): IModel[];
initModels(): IModel[];
needUpdate(): boolean;
clearModels(): void;
}
export interface IModelUniform {
[key: string]: IUniform;
@ -82,6 +84,7 @@ export interface ILayer {
zIndex: number;
plugins: ILayerPlugin[];
layerModelNeedUpdate: boolean;
styleNeedUpdate: boolean;
layerModel: ILayerModel;
dataState: IDataState; // 数据流状态
pickedFeatureID: number | null;
@ -117,6 +120,7 @@ export interface ILayer {
prepareBuildModel(): void;
renderModels(): void;
buildModels(): void;
rebuildModels(): void;
buildLayerModel(
options: ILayerModelInitializationOptions &
Partial<IModelInitializationOptions>,
@ -154,6 +158,8 @@ export interface ILayer {
setBlend(type: keyof typeof BlendType): void;
// animate(field: string, option: any): ILayer;
render(): ILayer;
clear(): void;
clearModels(): void;
destroy(): void;
source(data: any, option?: ISourceCFG): ILayer;
setData(data: any, option?: ISourceCFG): ILayer;

View File

@ -92,7 +92,6 @@ export default class LayerService implements ILayerService {
this.layers.sort((pre: ILayer, next: ILayer) => {
return pre.zIndex - next.zIndex;
});
this.renderLayers();
}
public destroy() {

View File

@ -18,6 +18,10 @@ import {
} from './IStyleAttributeService';
import StyleAttribute from './StyleAttribute';
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const bytesPerElementMap = {
[gl.FLOAT]: 4,
[gl.UNSIGNED_BYTE]: 1,
@ -216,27 +220,18 @@ export default class StyleAttributeService implements IStyleAttributeService {
indicesForCurrentFeature.forEach((i) => {
indices.push(i + verticesNum);
});
verticesForCurrentFeature.forEach((index) => {
vertices.push(index);
});
// fix Maximum call stack size exceeded https://stackoverflow.com/questions/22123769/rangeerror-maximum-call-stack-size-exceeded-why
if (normalsForCurrentFeature) {
normalsForCurrentFeature.forEach((normal) => {
normals.push(normal);
});
}
size = vertexSize;
const verticesNumForCurrentFeature =
verticesForCurrentFeature.length / vertexSize;
// 记录三角化结果,用于后续精确更新指定 feature
this.featureLayout.sizePerElement = size;
this.featureLayout.elements.push({
featureIdx,
vertices: verticesForCurrentFeature,
normals: normalsForCurrentFeature as number[],
offset: verticesNum,
});
// this.featureLayout.sizePerElement = size;
// this.featureLayout.elements.push({
// featureIdx,
// vertices: verticesForCurrentFeature,
// normals: normalsForCurrentFeature as number[],
// offset: verticesNum,
// });
verticesNum += verticesNumForCurrentFeature;
// 根据 position 顶点生成其他顶点数据
@ -245,21 +240,20 @@ export default class StyleAttributeService implements IStyleAttributeService {
vertexIdx < verticesNumForCurrentFeature;
vertexIdx++
) {
const normal =
normalsForCurrentFeature?.slice(vertexIdx * 3, vertexIdx * 3 + 3) ||
[];
const vertice = verticesForCurrentFeature.slice(
vertexIdx * vertexSize,
vertexIdx * vertexSize + vertexSize,
);
descriptors.forEach((descriptor, attributeIdx) => {
if (descriptor && descriptor.update) {
const normal =
normalsForCurrentFeature?.slice(
vertexIdx * 3,
vertexIdx * 3 + 3,
) || [];
(descriptor.buffer.data as number[]).push(
...descriptor.update(
feature,
featureIdx,
verticesForCurrentFeature.slice(
vertexIdx * vertexSize,
vertexIdx * vertexSize + vertexSize,
),
vertice,
vertexIdx, // 当前顶点所在feature索引
normal,
// TODO: 传入顶点索引 vertexIdx
@ -313,6 +307,8 @@ export default class StyleAttributeService implements IStyleAttributeService {
attribute.vertexAttribute.destroy();
}
});
this.attributesAndIndices.elements.destroy();
this.attributes = [];
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-draw",
"version": "2.2.14",
"version": "2.2.21",
"description": "L7 Draw moudules",
"keywords": [],
"author": "thinkinggis <lzx199065@gmail.com>",
@ -35,7 +35,7 @@
"test": "jest"
},
"dependencies": {
"@antv/l7": "2.2.14",
"@antv/l7": "2.2.21",
"@babel/runtime": "^7.7.7",
"@turf/circle": "^6.0.1",
"@turf/distance": "^6.0.1",
@ -55,5 +55,5 @@
"rollup": "^2.3.3",
"rollup-plugin-less": "^1.1.2"
},
"gitHead": "532ade40831b35b04a677b351d092e54c00613d8"
"gitHead": "20154fe30d512024b03ac5e40f77731bc0580bb0"
}

View File

@ -2,7 +2,7 @@
* @Author: lzxue
* @Date: 2020-04-03 19:24:16
* @Last Modified by: lzxue
* @Last Modified time: 2020-05-13 11:58:01
* @Last Modified time: 2020-06-22 17:33:14
*/
import { Control, DOM, IControlOption, PositionType, Scene } from '@antv/l7';
import './css/draw.less';

View File

@ -243,6 +243,7 @@ export default abstract class DrawFeature extends DrawMode {
if (this.drawStatus === 'DrawSelected') {
this.clear();
this.source.removeFeature(this.currentFeature as Feature);
this.normalLayer.update(this.source.data);
this.drawLayer.disableSelect();
this.selectMode.disable();

View File

@ -28,7 +28,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.8.3/polyfill.min.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js"></script>
<script src="../dist/l7.js"></script>
<script src="../dist/l7-dev.js"></script>
<script>
console.log(L7);
const scene = new L7.Scene({

View File

@ -27,7 +27,7 @@
<!-- <script src="https://cdn.jsdelivr.net/npm/symbol-es6@0.1.2/symbol-es6.min.js"></script> -->
<script src="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js"></script>
<script src="../dist/l7.js"></script>
<script src="../dist/l7-dev.js"></script>
<script>
console.log(L7);
const scene = new L7.Scene({

View File

@ -26,7 +26,7 @@
<div id="map"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.8.3/polyfill.min.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js"></script>
<script src="../dist/l7.js"></script>
<script src="../dist/l7-dev.js"></script>
<script>
const data =
{"type":"FeatureCollection","features":[

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7",
"version": "2.2.14",
"version": "2.2.21",
"description": "A Large-scale WebGL-powered Geospatial Data Visualization",
"main": "lib/index.js",
"module": "es/index.js",
@ -24,15 +24,15 @@
"author": "antv",
"license": "MIT",
"dependencies": {
"@antv/l7-component": "2.2.14",
"@antv/l7-core": "2.2.14",
"@antv/l7-layers": "2.2.14",
"@antv/l7-maps": "2.2.14",
"@antv/l7-scene": "2.2.14",
"@antv/l7-utils": "2.2.14",
"@antv/l7-component": "2.2.21",
"@antv/l7-core": "2.2.21",
"@antv/l7-layers": "2.2.21",
"@antv/l7-maps": "2.2.21",
"@antv/l7-scene": "2.2.21",
"@antv/l7-utils": "2.2.21",
"@babel/runtime": "^7.7.7"
},
"gitHead": "532ade40831b35b04a677b351d092e54c00613d8",
"gitHead": "20154fe30d512024b03ac5e40f77731bc0580bb0",
"publishConfig": {
"access": "public"
}

View File

@ -1,2 +1,2 @@
const version = '2.2.14';
const version = '2.2.21';
export { version };

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-layers",
"version": "2.2.14",
"version": "2.2.21",
"description": "L7's collection of built-in layers",
"main": "lib/index.js",
"module": "es/index.js",
@ -23,9 +23,9 @@
"license": "ISC",
"dependencies": {
"@antv/async-hook": "^2.1.0",
"@antv/l7-core": "2.2.14",
"@antv/l7-source": "2.2.14",
"@antv/l7-utils": "2.2.14",
"@antv/l7-core": "2.2.21",
"@antv/l7-source": "2.2.21",
"@antv/l7-utils": "2.2.21",
"@babel/runtime": "^7.7.7",
"@mapbox/martini": "^0.2.0",
"@turf/meta": "^6.0.2",
@ -34,6 +34,7 @@
"d3-scale": "2",
"earcut": "^2.2.1",
"eventemitter3": "^4.0.0",
"extrude-polyline": "^1.0.6",
"gl-matrix": "^3.1.0",
"gl-vec2": "^1.3.0",
"inversify": "^5.0.1",
@ -50,7 +51,7 @@
"@types/gl-matrix": "^2.4.5",
"@types/lodash": "^4.14.138"
},
"gitHead": "532ade40831b35b04a677b351d092e54c00613d8",
"gitHead": "20154fe30d512024b03ac5e40f77731bc0580bb0",
"publishConfig": {
"access": "public"
}

View File

@ -6,6 +6,9 @@ export default class CityBuildingLayer extends BaseLayer {
public type: string = 'PolygonLayer';
public buildModels() {
this.layerModel = new CityBuildModel(this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}
public setLight(t: number) {

View File

@ -29,7 +29,7 @@ export default class CityBuildModel extends BaseModel {
};
}
public buildModels(): IModel[] {
public initModels(): IModel[] {
this.startModelAnimate();
return [
this.layer.buildLayerModel({

View File

@ -70,6 +70,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
public layerModelNeedUpdate: boolean = false;
public pickedFeatureID: number | null = null;
public selectedFeatureID: number | null = null;
public styleNeedUpdate: boolean = false;
public dataState: IDataState = {
dataSourceNeedUpdate: false,
@ -469,6 +470,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
if (this.container) {
this.updateLayerConfig(this.rawConfig);
this.styleNeedUpdate = true;
}
return this;
}
@ -495,7 +497,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
// } else {
// this.renderModels();
// }
this.renderModels();
// this.multiPassRenderer.render();
// this.renderModels();
@ -708,7 +709,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
// 清除所有属性以及关联的 vao
this.styleAttributeService.clearAllAttributes();
// 销毁所有 model
this.models.forEach((model) => model.destroy());
// this.models.forEach((model) => model.destroy());
this.hooks.afterDestroy.call();
@ -725,7 +726,10 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
public clear() {
this.styleAttributeService.clearAllAttributes();
// 销毁所有 model
}
public clearModels() {
this.models.forEach((model) => model.destroy());
this.layerModel.clearModels();
}
public isDirty() {
@ -886,6 +890,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
public buildModels() {
throw new Error('Method not implemented.');
}
public rebuildModels() {
throw new Error('Method not implemented.');
}
public renderModels() {
if (this.layerModelNeedUpdate && this.layerModel) {

View File

@ -97,6 +97,12 @@ export default class BaseModel<ChildLayerStyleOptions = {}>
public buildModels(): IModel[] {
throw new Error('Method not implemented.');
}
public initModels(): IModel[] {
throw new Error('Method not implemented.');
}
public clearModels() {
return;
}
public getAttribute(): {
attributes: {
[attributeName: string]: IAttribute;

View File

@ -2,8 +2,8 @@ import { IEncodeFeature } from '@antv/l7-core';
import { aProjectFlat, lngLatToMeters } from '@antv/l7-utils';
import earcut from 'earcut';
import { vec3 } from 'gl-matrix';
import ExtrudePolyline from '../utils/extrude_polyline';
import { calculteCentroid } from '../utils/geo';
import getNormals from '../utils/polylineNormal';
import extrudePolygon, {
extrude_PolygonNormal,
fillPolygon,
@ -74,11 +74,16 @@ export function LineTriangulation(feature: IEncodeFeature) {
if (Array.isArray(path[0][0])) {
path = coordinates[0] as number[][];
}
const line = getNormals(path as number[][], false, 0);
const line = new ExtrudePolyline({
dash: true,
join: 'bevel', //
});
const linebuffer = line.extrude(path as number[][]);
return {
vertices: line.attrPos, // [ x,y,z, distance, miter,total ]
indices: line.attrIndex,
normals: line.normals,
vertices: linebuffer.positions, // [ x,y,z, distance, miter,total ]
indices: linebuffer.indices,
normals: linebuffer.normals,
size: 6,
};
}
@ -87,7 +92,6 @@ export function polygonTriangulation(feature: IEncodeFeature) {
const { coordinates } = feature;
const flattengeo = earcut.flatten(coordinates as number[][][]);
const { vertices, dimensions, holes } = flattengeo;
return {
indices: earcut(vertices, holes, dimensions),
vertices,

View File

@ -10,6 +10,9 @@ export default class HeatMapLayer extends BaseLayer<IHeatMapLayerStyleOptions> {
public buildModels() {
const shape = this.getModelType();
this.layerModel = new HeatMapModels[shape](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}
public renderModels() {

View File

@ -32,6 +32,10 @@ export default class GridModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -33,6 +33,10 @@ export default class Grid3DModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -45,6 +45,9 @@ export default class HeatMapModel extends BaseModel {
});
this.drawIntensityMode();
});
if (this.layer.styleNeedUpdate) {
this.updateColorTexture();
}
this.shapeType === 'heatmap' ? this.drawColorMode() : this.draw3DHeatMap();
}
@ -52,7 +55,7 @@ export default class HeatMapModel extends BaseModel {
throw new Error('Method not implemented.');
}
public buildModels(): IModel[] {
public initModels(): IModel[] {
const {
createFramebuffer,
clear,
@ -92,20 +95,15 @@ export default class HeatMapModel extends BaseModel {
depth: false,
});
// 初始化颜色纹理
this.colorTexture = createTexture2D({
data: new Uint8Array(imageData.data),
width: imageData.width,
height: imageData.height,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
min: gl.NEAREST,
mag: gl.NEAREST,
flipY: false,
});
this.updateColorTexture();
return [this.intensityModel, this.colorModel];
}
public buildModels(): IModel[] {
return this.initModels();
}
protected registerBuiltinAttributes() {
this.styleAttributeService.registerStyleAttribute({
name: 'dir',
@ -335,4 +333,29 @@ export default class HeatMapModel extends BaseModel {
}),
});
}
private updateStyle() {
this.updateColorTexture();
}
private updateColorTexture() {
const { createTexture2D } = this.rendererService;
if (this.texture) {
this.texture.destroy();
}
const {
rampColors,
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
const imageData = generateColorRamp(rampColors as IColorRamp);
this.colorTexture = createTexture2D({
data: new Uint8Array(imageData.data),
width: imageData.width,
height: imageData.height,
wrapS: gl.CLAMP_TO_EDGE,
wrapT: gl.CLAMP_TO_EDGE,
min: gl.NEAREST,
mag: gl.NEAREST,
flipY: false,
});
}
}

View File

@ -34,6 +34,10 @@ export default class HexagonModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -8,6 +8,9 @@ export default class ImageLayer extends BaseLayer<IImageLayerStyleOptions> {
public buildModels() {
const modelType = this.getModelType();
this.layerModel = new ImageModels[modelType](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}
protected getConfigSchema() {

View File

@ -31,7 +31,7 @@ export default class ImageModel extends BaseModel {
u_texture: this.texture,
};
}
public buildModels() {
public initModels() {
const source = this.layer.getSource();
const { createTexture2D } = this.rendererService;
this.texture = createTexture2D({
@ -58,6 +58,9 @@ export default class ImageModel extends BaseModel {
}),
];
}
public buildModels() {
return this.initModels();
}
protected getConfigSchema() {
return {

View File

@ -8,6 +8,9 @@ export default class LineLayer extends BaseLayer<ILineLayerStyleOptions> {
public buildModels() {
const shape = this.getModelType();
this.layerModel = new LineModels[shape](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}

View File

@ -44,6 +44,10 @@ export default class ArcModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -41,6 +41,10 @@ export default class Arc3DModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -43,6 +43,10 @@ export default class GreatCircleModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -41,6 +41,10 @@ export default class LineModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({
@ -48,7 +52,9 @@ export default class LineModel extends BaseModel {
vertexShader: line_vert,
fragmentShader: line_frag,
triangulation: LineTriangulation,
primitive: gl.TRIANGLES,
blend: this.getBlend(),
depth: { enable: false },
}),
];
}
@ -66,7 +72,7 @@ export default class LineModel extends BaseModel {
name: 'a_Distance',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
@ -88,7 +94,7 @@ export default class LineModel extends BaseModel {
name: 'a_Total_Distance',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
@ -141,6 +147,7 @@ export default class LineModel extends BaseModel {
type: gl.FLOAT,
},
size: 3,
// @ts-ignore
update: (
feature: IEncodeFeature,
featureIdx: number,
@ -160,7 +167,7 @@ export default class LineModel extends BaseModel {
name: 'a_Miter',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},

View File

@ -24,8 +24,8 @@ uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
void main() {
gl_FragColor = v_color;
// anti-alias
// float blur = 1.- smoothstep(u_blur, 1., length(v_normal.xy));
gl_FragColor.a *= u_opacity;
float blur = 1.- smoothstep(u_blur, 1., length(v_normal.xy));
gl_FragColor.a *= u_opacity * blur ;
if(u_aimate.x == Animate) {
float alpha =1.0 - fract( mod(1.0- v_distance_ratio, u_aimate.z)* (1.0/ u_aimate.z) + u_time / u_aimate.y);

View File

@ -39,6 +39,9 @@ export default class DataMappingPlugin implements ILayerPlugin {
// remapping before render
layer.hooks.beforeRender.tap('DataMappingPlugin', () => {
if (layer.layerModelNeedUpdate) {
return;
}
const attributes = styleAttributeService.getLayerStyleAttributes() || [];
const filter = styleAttributeService.getLayerStyleAttribute('filter');
const { dataArray } = layer.getSource().data;

View File

@ -72,14 +72,18 @@ export default class FeatureScalePlugin implements ILayerPlugin {
this.scaleOptions = layer.getScaleOptions();
const attributes = styleAttributeService.getLayerStyleAttributes();
const { dataArray } = layer.getSource().data;
if (dataArray.length === 0) {
return;
}
// if (dataArray.length === 0) {
// return;
// }
this.caculateScalesForAttributes(attributes || [], dataArray);
layer.layerModelNeedUpdate = true;
return true;
});
layer.hooks.beforeRender.tap('FeatureScalePlugin', () => {
if (layer.layerModelNeedUpdate) {
return;
}
this.scaleOptions = layer.getScaleOptions();
const attributes = styleAttributeService.getLayerStyleAttributes();
if (attributes) {

View File

@ -11,11 +11,14 @@ export default class LayerModelPlugin implements ILayerPlugin {
layer.prepareBuildModel();
// 初始化 Model
layer.buildModels();
layer.styleNeedUpdate = false;
});
layer.hooks.beforeRenderData.tap('DataSourcePlugin', () => {
// 更新Model 配置项
layer.prepareBuildModel();
layer.clearModels();
// 初始化 Model
layer.buildModels();
layer.layerModelNeedUpdate = false;

View File

@ -25,10 +25,10 @@ export default class UpdateStyleAttributePlugin implements ILayerPlugin {
this.initStyleAttribute(layer, { styleAttributeService });
});
layer.hooks.beforeRenderData.tap('styleAttributeService', () => {
layer.layerModelNeedUpdate = true;
return true;
});
// layer.hooks.beforeRenderData.tap('styleAttributeService', () => {
// // layer.layerModelNeedUpdate = true;
// return true;
// });
layer.hooks.beforeRender.tap('UpdateStyleAttributePlugin', () => {
if (layer.layerModelNeedUpdate) {

View File

@ -0,0 +1,49 @@
import PointLayer from '../';
import { Mapbox } from '../../../../maps/src';
import { Scene } from '../../../../scene/src';
describe('pointLayer', () => {
const el = document.createElement('div');
el.id = 'test-div-id';
el.style.width = '500px';
el.style.height = '500px';
document.querySelector('body')?.appendChild(el);
const pointdata = {
type: 'FeatureCollection',
features: [],
};
it('init', () => {
const scene = new Scene({
id: 'test-div-id',
map: new Mapbox({
style: 'dark',
center: [110.19382669582967, 30.258134],
pitch: 0,
zoom: 3,
}),
});
scene.on('loaded', () => {
const layer = new PointLayer()
.source(pointdata)
.color('red')
.shape('circle')
.size(5);
scene.addLayer(layer);
scene.render();
layer.setData({
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [99.84374999999999, 32.54681317351514],
},
},
],
});
expect(layer.getEncodedData().length).toBe(1);
});
});
});

View File

@ -11,6 +11,9 @@ export default class PointLayer extends BaseLayer<IPointLayerStyleOptions> {
public buildModels() {
const modelType = this.getModelType();
this.layerModel = new PointModels[modelType](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}
protected getConfigSchema() {

View File

@ -14,6 +14,9 @@ export default class ExtrudeModel extends BaseModel {
u_opacity: opacity || 1.0,
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [

View File

@ -54,6 +54,9 @@ export default class FillModel extends BaseModel {
PointFillTriangulation,
);
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -29,7 +29,7 @@ export default class IconeModel extends BaseModel {
};
}
public buildModels(): IModel[] {
public initModels(): IModel[] {
this.initIconFontGlyphs();
this.registerBuiltinAttributes();
this.updateTexture();

View File

@ -30,13 +30,18 @@ export default class ImageModel extends BaseModel {
};
}
public buildModels(): IModel[] {
public initModels(): IModel[] {
this.registerBuiltinAttributes();
this.updateTexture();
this.iconService.on('imageUpdate', () => {
this.updateTexture();
this.layer.render(); // TODO 调用全局render
});
this.iconService.on('imageUpdate', this.updateTexture);
return this.buildModels();
}
public clearModels() {
this.iconService.off('imageUpdate', this.updateTexture);
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({
moduleName: 'pointImage',
@ -49,7 +54,6 @@ export default class ImageModel extends BaseModel {
}),
];
}
protected registerBuiltinAttributes() {
// point layer size;
this.styleAttributeService.registerStyleAttribute({
@ -105,8 +109,11 @@ export default class ImageModel extends BaseModel {
});
}
private updateTexture() {
private updateTexture = () => {
const { createTexture2D } = this.rendererService;
if (this.texture) {
this.texture.destroy();
}
this.texture = createTexture2D({
data: this.iconService.getCanvas(),
mag: gl.LINEAR,
@ -114,5 +121,6 @@ export default class ImageModel extends BaseModel {
width: 1024,
height: this.iconService.canvasHeight || 128,
});
}
this.layer.render();
};
}

View File

@ -45,6 +45,11 @@ export default class NormalModel extends BaseModel {
u_stroke_color: rgb2arr(stroke),
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -14,6 +14,7 @@ import BaseModel from '../../core/BaseModel';
import CollisionIndex from '../../utils/collision-index';
import { calculteCentroid } from '../../utils/geo';
import {
anchorType,
getGlyphQuads,
IGlyphQuad,
shapeText,
@ -22,7 +23,7 @@ import textFrag from '../shaders/text_frag.glsl';
import textVert from '../shaders/text_vert.glsl';
interface IPointTextLayerStyleOptions {
opacity: number;
textAnchor: string;
textAnchor: anchorType;
spacing: number;
padding: [number, number];
stroke: string;
@ -140,12 +141,8 @@ export default class TextModel extends BaseModel {
};
}
public buildModels(): IModel[] {
this.layer.on('remapping', () => {
this.initGlyph();
this.updateTexture();
this.reBuildModel();
});
public initModels(): IModel[] {
this.layer.on('remapping', this.buildModels);
this.extent = this.textExtent();
const {
textAnchor = 'center',
@ -155,6 +152,10 @@ export default class TextModel extends BaseModel {
textAnchor,
textAllowOverlap,
};
return this.buildModels();
}
public buildModels = () => {
this.initGlyph();
this.updateTexture();
this.filterGlyphs();
@ -168,7 +169,7 @@ export default class TextModel extends BaseModel {
blend: this.getBlend(),
}),
];
}
};
public needUpdate() {
const {
textAllowOverlap = false,
@ -188,6 +189,9 @@ export default class TextModel extends BaseModel {
return false;
}
public clearModels() {
this.layer.off('remapping', this.buildModels);
}
protected registerBuiltinAttributes() {
this.styleAttributeService.registerStyleAttribute({
name: 'textOffsets',
@ -390,6 +394,9 @@ export default class TextModel extends BaseModel {
const { createTexture2D } = this.rendererService;
const { canvas } = this.fontService;
this.textureHeight = canvas.height;
if (this.texture) {
this.texture.destroy();
}
this.texture = createTexture2D({
data: canvas,
mag: gl.LINEAR,

View File

@ -12,9 +12,11 @@ export default class PolygonLayer extends BaseLayer<IPolygonLayerStyleOptions> {
public buildModels() {
const shape = this.getModelType();
this.layerModel = new PolygonModels[shape](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}
protected getConfigSchema() {
return {
properties: {

View File

@ -16,6 +16,10 @@ export default class ExtrudeModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -29,6 +29,10 @@ export default class FillModel extends BaseModel {
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
return [
this.layer.buildLayerModel({

View File

@ -14,6 +14,9 @@ export default class RaterLayer extends BaseLayer<IRasterLayerStyleOptions> {
public buildModels() {
const modelType = this.getModelType();
this.layerModel = new RasterModels[modelType](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}
protected getConfigSchema() {

View File

@ -50,7 +50,7 @@ export default class RasterModel extends BaseModel {
};
}
public buildModels() {
public initModels() {
const source = this.layer.getSource();
const { createTexture2D } = this.rendererService;
const parserDataItem = source.data.dataArray[0];
@ -85,6 +85,9 @@ export default class RasterModel extends BaseModel {
];
}
public buildModels() {
return this.initModels();
}
protected registerBuiltinAttributes() {
// point layer size;
this.styleAttributeService.registerStyleAttribute({

View File

@ -0,0 +1,23 @@
import { aProjectFlat } from '@antv/l7-utils';
import ExtrudePolyLine from '../extrude_polyline';
describe('extrude polyline', () => {
const coords = [
[57.65624999999999, 55.178867663281984],
[74.8828125, 54.77534585936447],
[74.8828125, 49.83798245308484],
];
const extrude = new ExtrudePolyLine({
thickness: 1,
});
it('extrude line', () => {
coords.forEach((coord) => {
const [lng, lat] = aProjectFlat(coord);
coord[0] = lng;
coord[1] = lat;
});
const mesh = extrude.extrude(coords);
expect(mesh.indices.length).toBe(12);
});
});

View File

@ -0,0 +1,332 @@
import { aProjectFlat } from '@antv/l7-utils';
import { vec2 } from 'gl-matrix';
const tmp = vec2.create();
const capEnd = vec2.create();
const lineA = vec2.create();
const lineB = vec2.create();
const tangent = vec2.create();
export function computeMiter(
lineTangent: vec2,
miter: vec2,
start: vec2,
end: vec2,
halfThick: number,
): [number, vec2] {
vec2.add(lineTangent, start, end);
vec2.normalize(lineTangent, lineTangent);
miter = vec2.fromValues(-lineTangent[1], lineTangent[0]);
const tmpvec = vec2.fromValues(-start[1], start[0]);
return [halfThick / vec2.dot(miter, tmpvec), miter];
}
export function computeNormal(out: vec2, dir: vec2) {
return vec2.set(out, -dir[1], dir[0]);
}
export function direction(out: vec2, a: vec2, b: vec2) {
vec2.sub(out, a, b);
vec2.normalize(out, out);
return out;
}
function isPointEqual(a: vec2, b: vec2) {
return a[0] === b[0] && a[1] === b[1];
}
export interface IExtrudeLineOption {
join: string;
cap: string;
dash: boolean;
closed: boolean;
indexOffset: number;
miterLimit: number;
thickness: number;
}
export default class ExtrudePolyline {
private join: string;
private cap: string;
private miterLimit: number;
private thickness: number;
private normal: vec2 | null;
private lastFlip: number = -1;
private miter: vec2 = vec2.fromValues(0, 0);
private started: boolean = false;
private dash: boolean = false;
private totalDistance: number = 0;
constructor(opts: Partial<IExtrudeLineOption> = {}) {
this.join = opts.join || 'miter';
this.cap = opts.cap || 'butt';
this.miterLimit = opts.miterLimit || 10;
this.thickness = opts.thickness || 1;
this.dash = opts.dash || false;
}
public extrude(points: number[][]) {
const complex: {
positions: number[];
indices: number[];
normals: number[];
} = {
positions: [],
indices: [],
normals: [],
};
if (points.length <= 1) {
return complex;
}
this.lastFlip = -1;
this.started = false;
this.normal = null;
this.totalDistance = 0;
const total = points.length;
for (let i = 1, count = 0; i < total; i++) {
const last = points[i - 1] as vec2;
const cur = points[i] as vec2;
const next = i < points.length - 1 ? points[i + 1] : null;
// 如果当前点和前一点相同,跳过
if (isPointEqual(last, cur)) {
continue;
}
const amt = this.segment(complex, count, last, cur, next as vec2);
count += amt;
}
if (this.dash) {
for (let i = 0; i < complex.positions.length / 6; i++) {
complex.positions[i * 6 + 5] = this.totalDistance;
}
}
return complex;
}
private segment(
complex: any,
index: number,
last: vec2,
cur: vec2,
next: vec2,
) {
let count = 0;
const indices = complex.indices;
const positions = complex.positions;
const normals = complex.normals;
const capSquare = this.cap === 'square';
const joinBevel = this.join === 'bevel';
const flatCur = aProjectFlat([cur[0], cur[1]]) as [number, number];
const flatLast = aProjectFlat([last[0], last[1]]) as [number, number];
direction(lineA, flatCur, flatLast);
let segmentDistance = 0;
if (this.dash) {
segmentDistance = this.lineSegmentDistance(flatCur, flatLast);
this.totalDistance += segmentDistance;
}
if (!this.normal) {
this.normal = vec2.create();
computeNormal(this.normal, lineA);
}
if (!this.started) {
this.started = true;
// if the end cap is type square, we can just push the verts out a bit
if (capSquare) {
// vec2.scaleAndAdd(capEnd, last, lineA, -this.thickness);
const out1 = vec2.create();
const out2 = vec2.create();
vec2.add(out1, this.normal, lineA);
vec2.add(out2, this.normal, lineA);
normals.push(out2[0], out2[1], 0);
normals.push(out1[0], out1[1], 0);
positions.push(
last[0],
last[1],
0,
this.totalDistance - segmentDistance,
-this.thickness,
0,
);
positions.push(
last[0],
last[1],
0,
this.totalDistance - segmentDistance,
this.thickness,
0,
);
// this.extrusions(positions, normals, last, out, this.thickness);
// last = capEnd;
} else {
this.extrusions(
positions,
normals,
last,
this.normal,
this.thickness,
this.totalDistance - segmentDistance,
);
}
}
indices.push(index + 0, index + 1, index + 2);
if (!next) {
computeNormal(this.normal, lineA);
if (capSquare) {
// vec2.scaleAndAdd(capEnd, cur, lineA, this.thickness);
// cur = capEnd;
const out1 = vec2.create();
const out2 = vec2.create();
vec2.sub(out2, lineA, this.normal);
vec2.add(out1, lineA, this.normal);
// this.extrusions(positions, normals, cur, out, this.thickness);
normals.push(out2[0], out2[1], 0);
normals.push(out1[0], out1[1], 0);
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
this.thickness,
0,
);
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
this.thickness,
0,
);
} else {
this.extrusions(
positions,
normals,
cur,
this.normal,
this.thickness,
this.totalDistance,
);
}
// this.extrusions(positions, normals, cur, this.normal, this.thickness);
indices.push(
...(this.lastFlip === 1
? [index, index + 2, index + 3]
: [index + 2, index + 1, index + 3]),
);
count += 2;
} else {
const flatNext = aProjectFlat([next[0], next[1]]) as [number, number];
if (isPointEqual(flatCur, flatNext)) {
vec2.add(
flatNext,
flatCur,
vec2.normalize(flatNext, vec2.subtract(flatNext, flatCur, flatLast)),
);
}
direction(lineB, flatNext, flatCur);
// stores tangent & miter
const [miterLen, miter] = computeMiter(
tangent,
vec2.create(),
lineA,
lineB,
this.thickness,
);
// normal(tmp, lineA)
// get orientation
let flip = vec2.dot(tangent, this.normal) < 0 ? -1 : 1;
let bevel = joinBevel;
if (!bevel && this.join === 'miter') {
const limit = miterLen;
if (limit > this.miterLimit) {
bevel = true;
}
}
if (bevel) {
normals.push(this.normal[0], this.normal[1], 0);
normals.push(miter[0], miter[1], 0);
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
-this.thickness * flip,
0,
);
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
this.thickness * flip,
0,
);
indices.push(
...(this.lastFlip !== -flip
? [index, index + 2, index + 3]
: [index + 2, index + 1, index + 3]),
);
// now add the bevel triangle
indices.push(index + 2, index + 3, index + 4);
computeNormal(tmp, lineB);
vec2.copy(this.normal, tmp); // store normal for next round
normals.push(this.normal[0], this.normal[1], 0);
positions.push(
cur[0],
cur[1],
0,
this.totalDistance,
-this.thickness * flip,
0,
);
count += 3;
} else {
this.extrusions(
positions,
normals,
cur,
miter,
miterLen,
this.totalDistance,
);
indices.push(
...(this.lastFlip === 1
? [index, index + 2, index + 3]
: [index + 2, index + 1, index + 3]),
);
flip = -1;
// the miter is now the normal for our next join
vec2.copy(this.normal, miter);
count += 2;
}
this.lastFlip = flip;
}
return count;
}
private extrusions(
positions: number[],
normals: number[],
point: vec2, // 顶点
normal: vec2, // 法向量
thickness: number, // 高度
distanceRadio: number,
) {
normals.push(normal[0], normal[1], 0);
normals.push(normal[0], normal[1], 0);
positions.push(point[0], point[1], 0, distanceRadio, -thickness, 0);
positions.push(point[0], point[1], 0, distanceRadio, thickness, 0);
}
private lineSegmentDistance(b1: vec2, a1: vec2) {
const dx = a1[0] - b1[0];
const dy = a1[1] - b1[1];
return Math.sqrt(dx * dx + dy * dy);
}
}

View File

@ -71,7 +71,7 @@ export default function(
let lineNormal = null;
const tmp = vec2.create();
let count = indexOffset || 0;
const miterLimit = 3;
const miterLimit = 4;
const out: number[] = [];
const attrPos: number[] = [];
@ -172,7 +172,6 @@ export default function(
count += 4;
continue;
}
if (bevel) {
miterLen = miterLimit;
@ -232,7 +231,7 @@ export default function(
return {
normals: out,
attrIndex,
attrPos: pickData, // [x,y,z, distance, miter ,tatal ]
attrPos: pickData, // [x,y,z, distance, miter ,t0tal ]
};
}
// [x,y,z, distance, miter ]

View File

@ -1,7 +1,24 @@
import { type } from 'os';
interface IPoint {
x: number;
y: number;
}
export type anchorType =
| 'right'
| 'top-right'
| 'left'
| 'bottom-right'
| 'left'
| 'top-left'
| 'bottom-left'
| 'bottom'
| 'bottom-right'
| 'bottom-left'
| 'top'
| 'top-right'
| 'top-left'
| 'center';
export interface IGlyphQuad {
tr: IPoint;
tl: IPoint;
@ -22,10 +39,9 @@ export interface IGlyphQuad {
* @param {string} anchor
* @return {alignment} alignment
*/
function getAnchorAlignment(anchor: string) {
function getAnchorAlignment(anchor: anchorType) {
let horizontalAlign = 0.5;
let verticalAlign = 0.5;
switch (anchor) {
case 'right':
case 'top-right':
@ -109,7 +125,7 @@ function shapeLines(
glyphMap: any,
lines: any[],
lineHeight: number,
textAnchor: string,
textAnchor: anchorType,
textJustify: string,
spacing: number,
) {
@ -197,7 +213,7 @@ export function shapeText(
text: string,
glyphs: any,
lineHeight: number,
textAnchor: string,
textAnchor: anchorType,
textJustify: string,
spacing: number,
translate: [number, number] = [0, 0],

Some files were not shown because too many files have changed in this diff Show More