mirror of https://gitee.com/antv-l7/antv-l7
commit
1fb2e9d3a2
|
@ -42,11 +42,11 @@ scene.addLayer(layer);
|
|||
|
||||
### minZoom
|
||||
|
||||
图层显示最小缩放等级,(0-18) {number} Mapbox (0-24) 高德 (3-18)
|
||||
图层显示最小缩放等级,(0-18) {number} Mapbox (0-24) 高德 (2-19)
|
||||
|
||||
### maxZoom
|
||||
|
||||
图层显示最大缩放等级 (0-18) {number} Mapbox (0-24) 高德 (3-18)
|
||||
图层显示最大缩放等级 (0-18) {number} Mapbox (0-24) 高德 (2-19)
|
||||
|
||||
### autoFit
|
||||
|
||||
|
@ -590,3 +590,17 @@ layer.on('inited', (option) => {});
|
|||
|
||||
- target 当前 layer
|
||||
- type 事件类型
|
||||
|
||||
## 图层框选
|
||||
|
||||
### boxSelect
|
||||
|
||||
参数 option
|
||||
- box [x1: number, y1: number, x2: number, y2: number] 相较于
|
||||
- cb (...args: any[]) => void 传入的回调方法,返回框选内部的 feature
|
||||
|
||||
```javascript
|
||||
layer.boxSelect(box, cb);
|
||||
// (x1, y1), (x2, y2) 框选的方框左上角和右下角相对于地图左上角的像素坐标
|
||||
// cb 是传入的回调函数,回调函数返回的参数是选中的 feature 对象数组,对象的字段和用户传入的数据相关
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@ order: 1
|
|||
|
||||
### 数据
|
||||
|
||||
绘制弧线只需提供起止点坐标即可
|
||||
绘制弧线只需提供起止点坐标即可(起止点调换位置,弧线的形状会对称相反,飞线动画的方向也会相反)
|
||||
|
||||
```javascript
|
||||
source(data, {
|
||||
|
|
|
@ -1,71 +1,5 @@
|
|||
---
|
||||
title: LineLayer
|
||||
order: 2
|
||||
order: 0
|
||||
---
|
||||
`markdown:docs/common/style.md`
|
||||
## 线图层
|
||||
|
||||
### shape
|
||||
|
||||
线图层支持 4 种 shape
|
||||
|
||||
- line 绘制路径图,
|
||||
- arc 绘制弧线 通过贝塞尔曲线算法技术弧线
|
||||
- greatcircle 大圆航线,地图两个点的最近距离不是两个点连线,而是大圆航线
|
||||
- arc3d 3d 弧线地图 3D 视角
|
||||
|
||||
⚠️ 弧线只需要设置起止点坐标即可
|
||||
|
||||
```
|
||||
new LineLayer()
|
||||
.source(data, {
|
||||
parser: {
|
||||
type: 'csv',
|
||||
x: 'lng1',
|
||||
y: 'lat1',
|
||||
x1: 'lng2',
|
||||
y1: 'lat2',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
如果 geojson 数据绘制弧线图 coordinates 第一对坐标为起点,第二对为终点
|
||||
|
||||
```
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[
|
||||
106.5234375,
|
||||
57.51582286553883
|
||||
],
|
||||
[
|
||||
136.40625,
|
||||
61.77312286453146
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### size
|
||||
|
||||
线图层 可以设置高度
|
||||
|
||||
- size 类型为 number 则表示 line 的宽度
|
||||
- size 类型为 [number , number] 分别表示宽度和高度
|
||||
|
||||
```javascript
|
||||
lineLayer.size(1); // 线的宽度为 1
|
||||
lineLayer.size([1, 2]); // 宽度为1,高度2
|
||||
```
|
||||
`markdown:docs/common/layer/base.md`
|
||||
`markdown:docs/api/layer/line_layer/linelayer.zh.md`
|
||||
|
|
|
@ -1,5 +1,71 @@
|
|||
---
|
||||
title: LineLayer
|
||||
order: 0
|
||||
order: 2
|
||||
---
|
||||
`markdown:docs/api/layer/line_layer/linelayer.en.md`
|
||||
`markdown:docs/common/style.md`
|
||||
## 线图层
|
||||
|
||||
### shape
|
||||
|
||||
线图层支持 4 种 shape
|
||||
|
||||
- line 绘制路径图,
|
||||
- arc 绘制弧线 通过贝塞尔曲线算法技术弧线
|
||||
- greatcircle 大圆航线,地图两个点的最近距离不是两个点连线,而是大圆航线
|
||||
- arc3d 3d 弧线地图 3D 视角
|
||||
|
||||
⚠️ 弧线只需要设置起止点坐标即可
|
||||
|
||||
```
|
||||
new LineLayer()
|
||||
.source(data, {
|
||||
parser: {
|
||||
type: 'csv',
|
||||
x: 'lng1',
|
||||
y: 'lat1',
|
||||
x1: 'lng2',
|
||||
y1: 'lat2',
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
如果 geojson 数据绘制弧线图 coordinates 第一对坐标为起点,第二对为终点
|
||||
|
||||
```
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[
|
||||
106.5234375,
|
||||
57.51582286553883
|
||||
],
|
||||
[
|
||||
136.40625,
|
||||
61.77312286453146
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
### size
|
||||
|
||||
线图层 可以设置高度
|
||||
|
||||
- size 类型为 number 则表示 line 的宽度
|
||||
- size 类型为 [number , number] 分别表示宽度和高度
|
||||
|
||||
```javascript
|
||||
lineLayer.size(1); // 线的宽度为 1
|
||||
lineLayer.size([1, 2]); // 宽度为1,高度2
|
||||
```
|
||||
`markdown:docs/common/layer/base.md`
|
||||
|
|
|
@ -34,7 +34,7 @@ shape 支持
|
|||
|
||||
**图片标注**
|
||||
|
||||
通过 `Scene.addImage()` 可以添加图片资源,
|
||||
通过 `Scene.addImage()` 可以添加图片资源
|
||||
|
||||
### 代码示例
|
||||
|
||||
|
|
|
@ -15,7 +15,8 @@ L7 在内部解决了不同地图底图之间差异,同时 L7 层面统一管
|
|||
### 引入 Map
|
||||
|
||||
```javascript
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
import { GaodeMap } from '@antv/l7-maps'; // 默认引入高德2.0
|
||||
import { GaodeMapV1 } from '@antv/l7-maps'; // 默认引入高德1.x 版本
|
||||
|
||||
import { Mapbox } from '@antv/l7-maps';
|
||||
```
|
||||
|
@ -70,7 +71,7 @@ const scene = new Scene({
|
|||
|
||||
⚠️ 传入地图实例需要自行引入相关地图的 API
|
||||
|
||||
⚠️ viewMode 设置为 3D 模式
|
||||
⚠️ viewMode 设置为 3D 模式(GaodeMap2.0 支持 2D 模式,可以不设置)
|
||||
|
||||
#### 传入高德地图实例
|
||||
|
||||
|
@ -92,11 +93,13 @@ const scene = new Scene({
|
|||
[示例地址](/zh/examples/tutorial/map#amapInstance)
|
||||
[代码地址](https://github.com/antvis/L7/blob/master/examples/tutorial/map/demo/amapInstance.js)
|
||||
|
||||
[示例地址( 2D )](/zh/examples/tutorial/map#amapInstance2d)
|
||||
[代码地址](https://github.com/antvis/L7/blob/master/examples/tutorial/map/demo/amapInstance.js)
|
||||
|
||||
#### 传入 Mapbox 地图实例
|
||||
|
||||
```javascript
|
||||
mapboxgl.accessToken =
|
||||
'pk.eyJ1IjoibHp4dWUiLCJhIjoiYnhfTURyRSJ9.Ugm314vAKPHBzcPmY1p4KQ';
|
||||
mapboxgl.accessToken = 'xxxx - token';
|
||||
const map = new mapboxgl.Map({
|
||||
container: 'map', // container id
|
||||
style: 'mapbox://styles/mapbox/streets-v11', // stylesheet location
|
||||
|
|
|
@ -113,7 +113,7 @@ L7 Logo 的显示位置 默认左下角
|
|||
|
||||
<description> _number_ </description>
|
||||
|
||||
地图初始显示级别 {number} Mapbox (0-24) 高德 (3-18)
|
||||
地图初始显示级别 {number} Mapbox (0-24) 高德 (2-19)
|
||||
|
||||
### center 地图中心
|
||||
|
||||
|
@ -146,11 +146,11 @@ L7 Logo 的显示位置 默认左下角
|
|||
|
||||
### minZoom 最小缩放等级
|
||||
|
||||
地图最小缩放等级 {number} default 0 Mapbox 0-24) 高德 (3-18)
|
||||
地图最小缩放等级 {number} default 0 Mapbox 0-24) 高德 (2-19)
|
||||
|
||||
### maxZoom 最大缩放等级
|
||||
|
||||
地图最大缩放等级 {number} default 22 Mapbox(0-24) 高德 (3-18)
|
||||
地图最大缩放等级 {number} default 22 Mapbox(0-24) 高德 (2-19)
|
||||
|
||||
### rotateEnable 是否允许旋转
|
||||
|
||||
|
@ -166,7 +166,167 @@ L7 Logo 的显示位置 默认左下角
|
|||
|
||||
高德地图适用,是否关闭偏移坐标系
|
||||
|
||||
## 方法
|
||||
## Layer 方法
|
||||
|
||||
### addLayer(layer) 增加图层对象
|
||||
|
||||
增加图层对象
|
||||
|
||||
参数 :
|
||||
|
||||
- `layer` {ILayer} 图层对象
|
||||
|
||||
```javascript
|
||||
scene.addLayer(layer);
|
||||
```
|
||||
|
||||
### getLayer(id) 获取对应的图层对象
|
||||
|
||||
获取对应的图层对象
|
||||
|
||||
参数 :
|
||||
|
||||
- `id` {string}
|
||||
|
||||
```javascript
|
||||
scene.getLayer('layerID');
|
||||
```
|
||||
|
||||
### getLayers() 获取所有的地图图层
|
||||
|
||||
获取所有的地图图层
|
||||
|
||||
```javascript
|
||||
scene.getLayers();
|
||||
```
|
||||
|
||||
### getLayerByName(name) 根据图层名称获取图层
|
||||
|
||||
根据图层名称获取图层
|
||||
|
||||
参数
|
||||
|
||||
- `name` {string} layer 初始化可配置图层 name
|
||||
|
||||
```javascript
|
||||
scene.getLayerByName(name); // return Layer 图层对象
|
||||
```
|
||||
|
||||
### removeLayer 移除 layer 图层
|
||||
|
||||
移除 layer 图层
|
||||
|
||||
```javascript
|
||||
scene.removeLayer(layer);
|
||||
```
|
||||
|
||||
参数 :
|
||||
|
||||
- `layer` {Layer}
|
||||
|
||||
### removeAllLayer() 移除所有的图层对象
|
||||
|
||||
移除所有的图层对象
|
||||
|
||||
```javascript
|
||||
scene.removeAllLayer();
|
||||
```
|
||||
|
||||
## 控制组件方法
|
||||
|
||||
### addControl(ctl) 添加组件控件
|
||||
|
||||
添加组件控件
|
||||
|
||||
参数 :
|
||||
|
||||
- `crl` { IControl } 用户创建的控件对象
|
||||
|
||||
```javascript
|
||||
scene.addControl(ctl);
|
||||
```
|
||||
|
||||
### removeControl(ctr) 移除用户添加的组件控件
|
||||
|
||||
移除用户添加的组件控件
|
||||
|
||||
参数 :
|
||||
|
||||
- `ctl` { IControl } 用户创建的控件对象
|
||||
|
||||
```javascript
|
||||
scene.removeControl(ctl);
|
||||
```
|
||||
|
||||
### getControlByName(name) 根据控件的名称来获取控件
|
||||
|
||||
根据控件的名称来获取控件
|
||||
|
||||
- `name` { string }
|
||||
|
||||
```javascript
|
||||
const zoomControl = new Zoom({
|
||||
// zoom 控件
|
||||
name: 'z1', // 用户传入的控件名称(也可以不传入,该控件默认名称为 zoom)
|
||||
position: 'topright',
|
||||
});
|
||||
|
||||
scene.getControlByName('z1');
|
||||
```
|
||||
|
||||
## 标记方法
|
||||
|
||||
### addMarker(maker) 添加标记
|
||||
|
||||
往场景中添加标记对象
|
||||
|
||||
参数 :
|
||||
|
||||
- `maker` { IMarker } Marker 实例
|
||||
|
||||
```javascript
|
||||
const marker = new Marker({
|
||||
element: el,
|
||||
}).setLnglat({ lng: nodes[i].x * 1, lat: nodes[i].y });
|
||||
scene.addMarker(marker);
|
||||
```
|
||||
|
||||
### addMarkerLayer(layer) 添加 Marker 统一管理图层
|
||||
|
||||
当用户需要添加许多个 Marker 实例时,为了方便管理可以使用 markerLayer 对象统一管理
|
||||
|
||||
参数 :
|
||||
|
||||
- `layer` { IMarkerLayer } 标记图层对象
|
||||
|
||||
```javascript
|
||||
const markerLayer = new MarkerLayer();
|
||||
scene.addMarkerLayer(markerLayer);
|
||||
```
|
||||
|
||||
[示例地址](/zh/examples/point/marker#markerlayer)
|
||||
|
||||
### removeMarkerLayer(layer) 移除标签图层
|
||||
|
||||
移除标签图层
|
||||
|
||||
参数 :
|
||||
|
||||
- `layer` { IMarkerLayer } 标记图层对象
|
||||
|
||||
```javascript
|
||||
scene.removeMarkerLayer(markerLayer);
|
||||
```
|
||||
|
||||
### removeAllMakers() 移除场景中所有的标签对象
|
||||
|
||||
移除场景中所有的标签对象
|
||||
|
||||
```javascript
|
||||
scene.removeAllMakers();
|
||||
```
|
||||
|
||||
## 地图方法
|
||||
|
||||
### getZoom 获取缩放等级
|
||||
|
||||
|
@ -178,30 +338,6 @@ scene.getZoom();
|
|||
|
||||
return {float} 当前缩放等级
|
||||
|
||||
### getLayers() 获取所有图层
|
||||
|
||||
获取所有的地图图层
|
||||
|
||||
```javascript
|
||||
scene.getLayers();
|
||||
```
|
||||
|
||||
### getLayerByName(name) 根据名称获取图层
|
||||
|
||||
根据图层名称获取图层
|
||||
|
||||
参数
|
||||
|
||||
- name {string}
|
||||
|
||||
layer 初始化可配置图层 name
|
||||
|
||||
```javascript
|
||||
scene.getLayerByName(name);
|
||||
```
|
||||
|
||||
return Layer 图层对象
|
||||
|
||||
### getCenter() 获取地图中心
|
||||
|
||||
获取地图中心点
|
||||
|
@ -385,18 +521,6 @@ scene.fitBounds([
|
|||
]);
|
||||
```
|
||||
|
||||
### removeLayer 移除图层
|
||||
|
||||
移除 layer
|
||||
|
||||
```javascript
|
||||
scene.removeLayer(layer);
|
||||
```
|
||||
|
||||
参数
|
||||
|
||||
- `layer` {Layer}
|
||||
|
||||
### exportMap 导出地图图片
|
||||
|
||||
导出地图,目前仅支持导出可视化层,不支持底图导出
|
||||
|
@ -411,10 +535,133 @@ scene.exportMap('png');
|
|||
|
||||
scene 销毁方法,离开页面,或者不需要使用地图可以调用
|
||||
|
||||
```
|
||||
```javascript
|
||||
scene.destroy();
|
||||
```
|
||||
|
||||
## iconfont 映射支持
|
||||
|
||||
### addIconFont(name, fontUnicode) 增加对数据中 unicode 的映射支持
|
||||
|
||||
支持对用户传入的数据进行 unicode 的映射,在内部维护一组名称和对应 key 的键值对
|
||||
|
||||
参数 :
|
||||
|
||||
- `name` {string}
|
||||
- `fontUnicode` {string}
|
||||
|
||||
```javascript
|
||||
scene.addIconFont('icon1', '');
|
||||
scene.addIconFont('icon2', '');
|
||||
scene.addFontFace(fontFamily, fontPath);
|
||||
const pointIconFontLayer = new PointLayer({})
|
||||
.source(
|
||||
[
|
||||
{
|
||||
j: 140,
|
||||
w: 34,
|
||||
m: 'icon1',
|
||||
},
|
||||
{
|
||||
j: 140,
|
||||
w: 36,
|
||||
m: 'icon2',
|
||||
},
|
||||
],
|
||||
{
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'j',
|
||||
y: 'w',
|
||||
},
|
||||
},
|
||||
)
|
||||
.shape('m', 'text')
|
||||
.size(12)
|
||||
.color('w', ['#f00', '#f00', '#0f0'])
|
||||
.style({
|
||||
fontFamily,
|
||||
iconfont: true,
|
||||
textAllowOverlap: true,
|
||||
});
|
||||
scene.addLayer(pointIconFontLayer);
|
||||
```
|
||||
|
||||
### addIconFonts(options) 同时传入多组 name - unicode 的键值对
|
||||
|
||||
同时传入多组 name - unicode 的键值对
|
||||
|
||||
参数 :
|
||||
|
||||
- `options` { Array<[name, unicode]> }
|
||||
|
||||
```javascript
|
||||
scene.addIconFonts([
|
||||
['icon1', ''],
|
||||
['icon2', ''],
|
||||
]);
|
||||
```
|
||||
|
||||
## 全局资源
|
||||
|
||||
### addImage(id, img) 全局中添加的图片资源
|
||||
|
||||
在 L7 的图层对象可以使用在 scene 全局中添加的图片资源
|
||||
|
||||
参数 :
|
||||
|
||||
- `id` {string}
|
||||
- `img` {HTMLImageElement | File | string}
|
||||
|
||||
```javascript
|
||||
scene.addImage(
|
||||
'02',
|
||||
'https://gw.alipayobjects.com/zos/bmw-prod/ce83fc30-701f-415b-9750-4b146f4b3dd6.svg',
|
||||
);
|
||||
```
|
||||
|
||||
[示例地址](/zh/examples/gallery/animate#animate_path_texture)
|
||||
|
||||
### hasImage(id) 判断全局图片资源
|
||||
|
||||
判断是否已经在全局添加过相应的图片资源
|
||||
|
||||
参数 :
|
||||
|
||||
- `id` {string}
|
||||
|
||||
```javascript
|
||||
scene.hasImage('imageID');
|
||||
```
|
||||
|
||||
### removeImage(id) 全局删除图片资源
|
||||
|
||||
从全局删除对应的图片资源
|
||||
|
||||
参数 :
|
||||
|
||||
- `id` {string}
|
||||
|
||||
```javascript
|
||||
scene.removeImage('imageID');
|
||||
```
|
||||
|
||||
### addFontFace(fontFamily, fontPath) 添加字体文件
|
||||
|
||||
添加字体文件
|
||||
|
||||
参数 :
|
||||
|
||||
- `fontFamily` {string} 用户为自己定义的字体名称
|
||||
- `fontPath` {string} 导入的文件地址
|
||||
|
||||
```javascript
|
||||
let fontFamily = 'iconfont';
|
||||
let fontPath =
|
||||
'//at.alicdn.com/t/font_2534097_iiet9d3nekn.woff2?t=1620444089776';
|
||||
scene.addFontFace(fontFamily, fontPath);
|
||||
```
|
||||
|
||||
## 事件
|
||||
|
||||
### on
|
||||
|
|
|
@ -7,7 +7,7 @@ order: 0
|
|||
|
||||
## 概述
|
||||
|
||||
source 地理数据处理模块,主要包含数据解析(parser),和数据处理(transform);
|
||||
source 地理数据处理模块,主要包含数据解析(parser),和数据处理(transform)
|
||||
|
||||
- data
|
||||
- option
|
||||
|
@ -18,7 +18,7 @@ source 地理数据处理模块,主要包含数据解析(parser),和数据
|
|||
|
||||
### parser
|
||||
|
||||
不同数据类型处理成统一数据格式。矢量数据包括 GeoJON, CSV,Json 等不同数据格式,栅格数据,包括 Raster,Image 数据。将来还会支持瓦片格式数据。
|
||||
不同数据类型处理成统一数据格式。矢量数据包括 GeoJON, CSV,Json 等不同数据格式,栅格数据,包括 Raster,Image 数据。将来还会支持瓦片格式数据。
|
||||
|
||||
空间数据分矢量数据和栅格数据两大类
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
### minZoom
|
||||
<description> _number_ **可选** _default:_ `0`</description>
|
||||
|
||||
图层显示最小缩放等级,(0-18) {number} Mapbox (0-24) 高德 (3-18)
|
||||
图层显示最小缩放等级,(0-18) {number} Mapbox (0-24) 高德 (2-19)
|
||||
|
||||
### maxZoom
|
||||
<description> _number_ **可选** _default:_ `22`</description>
|
||||
图层显示最大缩放等级 (0-18) {number} Mapbox (0-24) 高德 (3-18)
|
||||
图层显示最大缩放等级 (0-18) {number} Mapbox (0-24) 高德 (2-19)
|
||||
|
||||
### autoFit
|
||||
<description> _bool_ **可选** _default:_ `false`</description>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Scene } from '@antv/l7';
|
||||
import { DrillDownLayer } from '@antv/l7-district';
|
||||
import { Mapbox } from '@antv/l7-maps';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
const colors = [ '#B8E1FF', '#7DAAFF', '#3D76DD', '#0047A5', '#001D70' ];
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new Mapbox({
|
||||
map: new GaodeMap({
|
||||
center: [ 116.2825, 39.9 ],
|
||||
pitch: 0,
|
||||
style: 'blank',
|
||||
|
|
|
@ -9,6 +9,16 @@
|
|||
"title": "中国地图钻取",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_8e1672/afts/img/A*xjjARqU70xoAAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "drill_down_view.js",
|
||||
"title": "中国地图钻取",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*KphnSq_0C6sAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "drill_down_province.js",
|
||||
"title": "省级地图钻取",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*fVHISrzrz44AAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "drill_down_bubble.js",
|
||||
"title": "中国地图钻取气泡图",
|
||||
|
|
|
@ -203,7 +203,7 @@ class Province extends React.Component {
|
|||
});
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new Mapbox({
|
||||
map: new GaodeMap({
|
||||
center: [116.2825, 39.9],
|
||||
pitch: 0,
|
||||
style: 'blank',
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import { Scene, LineLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 120.19382669582967, 30.258134 ],
|
||||
pitch: 20,
|
||||
zoom: 18,
|
||||
style: 'light'
|
||||
})
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
scene.addImage(
|
||||
'02',
|
||||
'https://gw.alipayobjects.com/zos/bmw-prod/ce83fc30-701f-415b-9750-4b146f4b3dd6.svg'
|
||||
);
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/basement_prod/40ef2173-df66-4154-a8c0-785e93a5f18e.json'
|
||||
)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
const layer = new LineLayer()
|
||||
.source(data)
|
||||
.size(4)
|
||||
.shape('line')
|
||||
.texture('02')
|
||||
.color('#25d8b7')
|
||||
.animate({
|
||||
interval: 1, // 间隔
|
||||
duration: 1, // 持续时间,延时
|
||||
trailLength: 2 // 流线长度
|
||||
})
|
||||
.style({
|
||||
lineTexture: true, // 开启线的贴图功能
|
||||
iconStep: 100 // 设置贴图纹理的间距
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
});
|
||||
});
|
|
@ -4,7 +4,7 @@ import { GaodeMap } from '@antv/l7-maps';
|
|||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
style: 'amap://styles/a49ef8d081db7b85adb2e90ba7941f1e?isPublic=true',
|
||||
style: 'dark',
|
||||
center: [ 120.173104, 30.244072 ],
|
||||
pitch: 70.41138037735848,
|
||||
zoom: 17.18,
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
"en": "Gallery"
|
||||
},
|
||||
"demos": [
|
||||
{
|
||||
"filename": "animate_path_texture.js",
|
||||
"title": "路径贴图",
|
||||
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*0UrUTakTFQsAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "animate_path.js",
|
||||
"title": "路径动画",
|
||||
|
|
|
@ -4,6 +4,11 @@
|
|||
"en": "line"
|
||||
},
|
||||
"demos": [
|
||||
{
|
||||
"filename": "wind.js",
|
||||
"title": "风场弧线",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*LpcBTKiazZcAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "arcCircle.js",
|
||||
"title": "大圆弧线",
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
import { Scene, LineLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
pitch: 0,
|
||||
style: 'light',
|
||||
center: [ 60, 40.7128 ],
|
||||
zoom: 2
|
||||
})
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/bmw-prod/7455fead-1dc0-458d-b91a-fb4cf99e701e.txt'
|
||||
)
|
||||
.then(res => res.text())
|
||||
.then(data => {
|
||||
const layer = new LineLayer({ blend: 'normal' })
|
||||
.source(data,
|
||||
{
|
||||
parser: {
|
||||
type: 'csv',
|
||||
x: 'lng1',
|
||||
y: 'lat1',
|
||||
x1: 'lng2',
|
||||
y1: 'lat2'
|
||||
}
|
||||
})
|
||||
.size(1)
|
||||
.shape('arc')
|
||||
.color('#6495ED')
|
||||
.animate({
|
||||
duration: 4,
|
||||
interval: 0.2,
|
||||
trailLength: 0.6
|
||||
});
|
||||
// .forward(false)
|
||||
scene.addLayer(layer);
|
||||
});
|
||||
});
|
|
@ -16,14 +16,19 @@
|
|||
},
|
||||
{
|
||||
"filename": "road_light.js",
|
||||
"title": "路径",
|
||||
"title": "路径light",
|
||||
"screenshot":"https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*LuXiTZAq_84AAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "road_dark.js",
|
||||
"title": "路径",
|
||||
"title": "路径dark",
|
||||
"screenshot":"https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*DDjQRLEnwpoAAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "road_red.js",
|
||||
"title": "路径2d",
|
||||
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*1cF2RYwkcq8AAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "road_dark_dash.js",
|
||||
"title": "路径虚线",
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import {
|
||||
Scene,
|
||||
LineLayer
|
||||
} from '@antv/l7';
|
||||
import {
|
||||
GaodeMap
|
||||
} from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 116.3956, 39.9392 ],
|
||||
pitch: 0,
|
||||
zoom: 10,
|
||||
rotation: 0,
|
||||
style: 'amap://styles/light',
|
||||
viewMode: '2D'
|
||||
})
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/basement_prod/0d2f0113-f48b-4db9-8adc-a3937243d5a3.json'
|
||||
)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
const layer = new LineLayer({})
|
||||
.source(data)
|
||||
.size(1.5)
|
||||
.shape('line')
|
||||
.color('标准名称', [ '#5B8FF9', '#5CCEA1', '#5D7092' ]);
|
||||
scene.addLayer(layer);
|
||||
});
|
||||
});
|
|
@ -18,6 +18,11 @@
|
|||
"filename": "weather.js",
|
||||
"title": "天气",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*-nk1RZJeGooAAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "road.js",
|
||||
"title": "路线图",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*2HLeQ4AjxacAAAAAAAAAAAAAARQnAQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
import { Scene, LineLayer, PointLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 120.115, 30.221 ],
|
||||
pitch: 40,
|
||||
zoom: 16,
|
||||
viewMode: '3D'
|
||||
})
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/bmw-prod/91d27a97-869a-459b-a617-498dcc9c3e7f.json'
|
||||
)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
scene.addImage(
|
||||
'road',
|
||||
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*haGlTpW2BQgAAAAAAAAAAAAAARQnAQ'
|
||||
);
|
||||
|
||||
const layer = new LineLayer()
|
||||
.source(data)
|
||||
.size(8)
|
||||
.shape('line')
|
||||
.texture('road')
|
||||
.color('rgb(20, 180, 90)')
|
||||
.animate({
|
||||
interval: 1, // 间隔
|
||||
duration: 1, // 持续时间,延时
|
||||
trailLength: 2 // 流线长度
|
||||
})
|
||||
.style({
|
||||
lineTexture: true, // 开启线的贴图功能
|
||||
iconStep: 200 // 设置贴图纹理的间距
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
|
||||
scene.addImage(
|
||||
'start',
|
||||
'https://gw.alipayobjects.com/zos/bmw-prod/ebb0af57-4a8a-46e0-a296-2d51f9fa8007.svg'
|
||||
);
|
||||
scene.addImage(
|
||||
'visitor',
|
||||
'https://gw.alipayobjects.com/zos/bmw-prod/64db255d-b636-4929-b072-068e75178b23.svg'
|
||||
);
|
||||
scene.addImage(
|
||||
'museum',
|
||||
'https://gw.alipayobjects.com/zos/bmw-prod/0630591d-64db-4057-a04d-d65f43aebf0f.svg'
|
||||
);
|
||||
scene.addImage(
|
||||
'supermarket',
|
||||
'https://gw.alipayobjects.com/zos/bmw-prod/ab42799d-dea6-4d37-bd62-3ee3e06bf6c0.svg'
|
||||
);
|
||||
scene.addImage(
|
||||
'tower',
|
||||
'https://gw.alipayobjects.com/zos/bmw-prod/6d27cf89-638c-432b-a8c4-cac289ee98a8.svg'
|
||||
);
|
||||
scene.addImage(
|
||||
'end',
|
||||
'https://gw.alipayobjects.com/zos/bmw-prod/59717737-5652-479f-9e6b-e7d2c5441446.svg'
|
||||
);
|
||||
const imageLayer = new PointLayer()
|
||||
.source([{
|
||||
lng: 120.11025885601617,
|
||||
lat: 30.22006389085372,
|
||||
icon: 'start'
|
||||
}, {
|
||||
lng: 120.11123578376913,
|
||||
lat: 30.220443561196277,
|
||||
icon: 'visitor'
|
||||
}, {
|
||||
lng: 120.11408457779198,
|
||||
lat: 30.22019805564678,
|
||||
icon: 'museum'
|
||||
}, {
|
||||
lng: 120.11683172384723,
|
||||
lat: 30.21875509667716,
|
||||
icon: 'supermarket'
|
||||
}, {
|
||||
lng: 120.11945546294194,
|
||||
lat: 30.218724022876376,
|
||||
icon: 'tower'
|
||||
}, {
|
||||
lng: 120.1184189041221,
|
||||
lat: 30.21783201718256,
|
||||
icon: 'end'
|
||||
}
|
||||
], {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat'
|
||||
}
|
||||
})
|
||||
.shape('icon', [ 'start', 'visitor', 'museum', 'supermarket', 'tower', 'end' ])
|
||||
.size(35)
|
||||
.style({
|
||||
offsets: [ 0, 20 ]
|
||||
});
|
||||
scene.addLayer(imageLayer);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
import { Scene, PointLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
style: 'light',
|
||||
center: [ 112, 23.69 ],
|
||||
zoom: 2.5
|
||||
})
|
||||
});
|
||||
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/basement_prod/9078fd36-ce8d-4ee2-91bc-605db8315fdf.csv'
|
||||
)
|
||||
.then(res => res.text())
|
||||
.then(data => {
|
||||
const pointLayer = new PointLayer({})
|
||||
.source(data, {
|
||||
parser: {
|
||||
type: 'csv',
|
||||
x: 'Longitude',
|
||||
y: 'Latitude'
|
||||
}
|
||||
})
|
||||
.shape('circle')
|
||||
.active(true)
|
||||
.animate(true)
|
||||
.size(40)
|
||||
.color('#ffa842')
|
||||
.style({
|
||||
opacity: 1,
|
||||
offsets: [ 40, 40 ]
|
||||
});
|
||||
const pointLayer2 = new PointLayer({})
|
||||
.source(data, {
|
||||
parser: {
|
||||
type: 'csv',
|
||||
x: 'Longitude',
|
||||
y: 'Latitude'
|
||||
}
|
||||
})
|
||||
.shape('circle')
|
||||
.active(true)
|
||||
.animate(true)
|
||||
.size(50)
|
||||
.color('#f00')
|
||||
.style({
|
||||
opacity: 1
|
||||
});
|
||||
|
||||
scene.addLayer(pointLayer);
|
||||
scene.addLayer(pointLayer2);
|
||||
});
|
|
@ -0,0 +1,52 @@
|
|||
import { Scene, PointLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
style: 'light',
|
||||
center: [ 120.19382669582967, 30.258134 ],
|
||||
zoom: 10
|
||||
})
|
||||
});
|
||||
|
||||
const radius = 0.1;
|
||||
|
||||
function pointOnCircle(angle) {
|
||||
return {
|
||||
type: 'FeatureCollection',
|
||||
features: [
|
||||
{
|
||||
type: 'Feature',
|
||||
properties: {},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [
|
||||
120.19382669582967 + Math.cos(angle) * radius,
|
||||
30.258134 + Math.sin(angle) * radius
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
const layer = new PointLayer({})
|
||||
.source(pointOnCircle(0))
|
||||
.shape('circle')
|
||||
.size(15) // default 1
|
||||
.active(false)
|
||||
.color('#2F54EB')
|
||||
.style({
|
||||
stroke: '#fff',
|
||||
strokeWidth: 2,
|
||||
opacity: 1
|
||||
});
|
||||
scene.addLayer(layer);
|
||||
layer.setData(pointOnCircle(1000));
|
||||
|
||||
function animateMarker(timestamp) {
|
||||
layer.setData(pointOnCircle(timestamp / 1000));
|
||||
scene.render();
|
||||
requestAnimationFrame(animateMarker);
|
||||
}
|
||||
animateMarker(0);
|
|
@ -8,8 +8,16 @@
|
|||
"filename": "scatter.js",
|
||||
"title": "散点图",
|
||||
"screenshot":"https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*LnlmQ7sFWigAAAAAAAAAAABkARQnAQ"
|
||||
|
||||
},
|
||||
{
|
||||
"filename": "dynamicScatter.js",
|
||||
"title": "动态散点",
|
||||
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*iourTIHnDk0AAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "animatePoint.js",
|
||||
"title": "水波散点",
|
||||
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*BsEnTrJ5JRcAAAAAAAAAAAAAARQnAQ"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
import { Scene, PointLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 110, 30 ],
|
||||
pitch: 0,
|
||||
// style: 'light',
|
||||
style: 'amap://styles/453e2f8e11603fc8f7548fe18959e9e9',
|
||||
zoom: 5
|
||||
})
|
||||
});
|
||||
const fontFamily = 'iconfont';
|
||||
const fontPath = '//at.alicdn.com/t/font_2534097_fcae9o2mxbv.woff2?t=1622200439140';
|
||||
scene.addFontFace(fontFamily, fontPath);
|
||||
scene.addIconFont('icon1', '');
|
||||
|
||||
scene.on('loaded', () => {
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/bmw-prod/70408903-80db-4278-a318-461604acb2df.json'
|
||||
)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
const pointLayer = new PointLayer({})
|
||||
.source(data.list, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'j',
|
||||
y: 'w'
|
||||
}
|
||||
})
|
||||
.shape('icon', 'text')
|
||||
.size(20)
|
||||
.color('w', [ '#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99' ])
|
||||
.style({
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [ 40, 0 ], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||
padding: [ 0, 0 ], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
||||
stroke: '#ffffff', // 描边颜色
|
||||
fontFamily,
|
||||
iconfont: true,
|
||||
textAllowOverlap: true
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,268 @@
|
|||
import { Scene, PointLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 120.5, 30.2 ],
|
||||
pitch: 0,
|
||||
style: 'amap://styles/453e2f8e11603fc8f7548fe18959e9e9',
|
||||
zoom: 8.5,
|
||||
zooms: [ 8, 10 ],
|
||||
viewMode: '2D'
|
||||
})
|
||||
});
|
||||
const dataColor = {
|
||||
bigRainBC: '#285A8C',
|
||||
middleRainBC: '#326EA0',
|
||||
smallRainBC: '#4678AA',
|
||||
sunBC: '#00BFFF',
|
||||
cloudBC: '#1E90FF'
|
||||
};
|
||||
const originData = [
|
||||
{
|
||||
lng: 121.7,
|
||||
lat: 30.6,
|
||||
iconType: 'hugeRain',
|
||||
iconColor: '#4678D2',
|
||||
backgoundColor: dataColor.bigRainBC,
|
||||
temperature: '20℃',
|
||||
weather: '大雨'
|
||||
},
|
||||
{
|
||||
lng: 119.2,
|
||||
lat: 30.0,
|
||||
iconType: 'smallRain',
|
||||
iconColor: '#6EA0FF',
|
||||
backgoundColor: dataColor.smallRainBC,
|
||||
temperature: '22℃',
|
||||
weather: '小雨'
|
||||
},
|
||||
{
|
||||
lng: 119.67,
|
||||
lat: 30.2,
|
||||
iconType: 'sun',
|
||||
iconColor: '#FFA500',
|
||||
backgoundColor: dataColor.sunBC,
|
||||
temperature: '28℃',
|
||||
weather: '晴朗'
|
||||
},
|
||||
{
|
||||
lng: 119.63,
|
||||
lat: 30.6,
|
||||
iconType: 'sun',
|
||||
iconColor: '#FFA500',
|
||||
backgoundColor: dataColor.sunBC,
|
||||
temperature: '28℃',
|
||||
weather: '晴朗'
|
||||
},
|
||||
{
|
||||
lng: 120,
|
||||
lat: 30,
|
||||
iconType: 'sun',
|
||||
iconColor: '#FFA500',
|
||||
backgoundColor: dataColor.sunBC,
|
||||
temperature: '28℃',
|
||||
weather: '晴朗'
|
||||
},
|
||||
{
|
||||
lng: 120.2,
|
||||
lat: 30.5,
|
||||
iconType: 'sun',
|
||||
iconColor: '#FFA500',
|
||||
backgoundColor: dataColor.sunBC,
|
||||
temperature: '28℃',
|
||||
weather: '晴朗'
|
||||
},
|
||||
{
|
||||
lng: 121.5,
|
||||
lat: 31.4,
|
||||
iconType: 'cloud',
|
||||
iconColor: '#F0F8FF',
|
||||
backgoundColor: dataColor.cloudBC,
|
||||
temperature: '22℃',
|
||||
weather: '多云'
|
||||
},
|
||||
{
|
||||
lng: 120,
|
||||
lat: 31,
|
||||
iconType: 'cloud',
|
||||
iconColor: '#F0F8FF',
|
||||
backgoundColor: dataColor.cloudBC,
|
||||
temperature: '22℃',
|
||||
weather: '多云'
|
||||
},
|
||||
{
|
||||
lng: 120.6,
|
||||
lat: 30.8,
|
||||
iconType: 'cloud',
|
||||
iconColor: '#F0F8FF',
|
||||
backgoundColor: dataColor.cloudBC,
|
||||
temperature: '22℃',
|
||||
weather: '多云'
|
||||
},
|
||||
{
|
||||
lng: 120.5,
|
||||
lat: 31.3,
|
||||
iconType: 'cloud',
|
||||
iconColor: '#F0F8FF',
|
||||
backgoundColor: dataColor.cloudBC,
|
||||
temperature: '22℃',
|
||||
weather: '多云'
|
||||
},
|
||||
{
|
||||
lng: 121.3,
|
||||
lat: 30.2,
|
||||
iconType: 'smallRain',
|
||||
iconColor: '#6EA0FF',
|
||||
backgoundColor: dataColor.smallRainBC,
|
||||
temperature: '22℃',
|
||||
weather: '小雨'
|
||||
},
|
||||
{
|
||||
lng: 121,
|
||||
lat: 30.5,
|
||||
iconType: 'smallRain',
|
||||
iconColor: '#6EA0FF',
|
||||
backgoundColor: dataColor.smallRainBC,
|
||||
temperature: '22℃',
|
||||
weather: '小雨'
|
||||
},
|
||||
{
|
||||
lng: 120.6,
|
||||
lat: 30,
|
||||
iconType: 'middleRain',
|
||||
iconColor: '#6495ED',
|
||||
backgoundColor: dataColor.middleRainBC,
|
||||
temperature: '24℃',
|
||||
weather: '中雨'
|
||||
},
|
||||
{
|
||||
lng: 120.2,
|
||||
lat: 29.7,
|
||||
iconType: 'smallRain',
|
||||
iconColor: '#6EA0FF',
|
||||
backgoundColor: dataColor.smallRainBC,
|
||||
temperature: '22℃',
|
||||
weather: '小雨'
|
||||
},
|
||||
{
|
||||
lng: 121.7,
|
||||
lat: 29.8,
|
||||
iconType: 'middleRain',
|
||||
iconColor: '#6495ED',
|
||||
backgoundColor: dataColor.middleRainBC,
|
||||
temperature: '24℃',
|
||||
weather: '中雨'
|
||||
},
|
||||
{
|
||||
lng: 121.5,
|
||||
lat: 30,
|
||||
iconType: 'hugeRain',
|
||||
iconColor: '#4678D2',
|
||||
backgoundColor: dataColor.bigRainBC,
|
||||
temperature: '20℃',
|
||||
weather: '大雨'
|
||||
}
|
||||
];
|
||||
const fontFamily = 'iconfont';
|
||||
const fontPath = '//at.alicdn.com/t/font_2534097_ao9soua2obv.woff2?t=1622021146076';
|
||||
scene.addFontFace(fontFamily, fontPath);
|
||||
scene.addIconFonts([
|
||||
[ 'smallRain', '' ],
|
||||
[ 'middleRain', '' ],
|
||||
[ 'hugeRain', '' ],
|
||||
[ 'sun', '' ],
|
||||
[ 'cloud', '' ]
|
||||
]);
|
||||
|
||||
scene.on('loaded', () => {
|
||||
|
||||
const layer = new PointLayer()
|
||||
.source(originData, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat'
|
||||
}
|
||||
})
|
||||
.shape('circle')
|
||||
.color('backgoundColor')
|
||||
.size(42);
|
||||
scene.addLayer(layer);
|
||||
|
||||
|
||||
const pointIconFontLayer = new PointLayer({})
|
||||
.source(originData, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat'
|
||||
}
|
||||
}
|
||||
)
|
||||
.shape('iconType', 'text')
|
||||
.size(30)
|
||||
.color('iconColor')
|
||||
.style({
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [ 38, 10 ], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||
fontFamily,
|
||||
iconfont: true,
|
||||
textAllowOverlap: true
|
||||
});
|
||||
scene.addLayer(pointIconFontLayer);
|
||||
|
||||
const textLayer = new PointLayer({})
|
||||
.source(originData,
|
||||
{
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat'
|
||||
}
|
||||
}
|
||||
)
|
||||
.shape('temperature', 'text')
|
||||
.size(10)
|
||||
.color('#ffffff')
|
||||
.style({
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [ 5, -55 ], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||
spacing: 2, // 字符间距
|
||||
padding: [ 1, 1 ], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
||||
stroke: '#ffffff', // 描边颜色
|
||||
strokeWidth: 0.3, // 描边宽度
|
||||
strokeOpacity: 1.0,
|
||||
fontFamily: 'Times New Roman',
|
||||
textAllowOverlap: true
|
||||
});
|
||||
scene.addLayer(textLayer);
|
||||
|
||||
const textLayer2 = new PointLayer({})
|
||||
.source(originData,
|
||||
{
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'lng',
|
||||
y: 'lat'
|
||||
}
|
||||
}
|
||||
)
|
||||
.shape('weather', 'text')
|
||||
.size(14)
|
||||
.color('#ffffff')
|
||||
.style({
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [ 5, -15 ], // 文本相对锚点的偏移量 [水平, 垂直]
|
||||
spacing: 2, // 字符间距
|
||||
padding: [ 1, 1 ], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近
|
||||
stroke: '#ffffff', // 描边颜色
|
||||
strokeWidth: 0.3, // 描边宽度
|
||||
strokeOpacity: 1.0,
|
||||
fontFamily: 'Times New Roman',
|
||||
textAllowOverlap: true
|
||||
});
|
||||
scene.addLayer(textLayer2);
|
||||
|
||||
});
|
|
@ -13,7 +13,26 @@
|
|||
"filename": "polygon_text.js",
|
||||
"title": "面数据标注",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*rCFqRp3iQosAAAAAAAAAAABkARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "iconfont.js",
|
||||
"title": "图标标注",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*8PfqQ6-lQ0EAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "iconfonts.js",
|
||||
"title": "天气图标标注",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*JAhxTaabap4AAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "temperture.js",
|
||||
"title": "气温图标标注",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*36umQaf_hVEAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "updown.js",
|
||||
"title": "走势图标标注",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*P5plS5ZsYZkAAAAAAAAAAAAAARQnAQ"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { GaodeMap } from '@antv/l7-maps';
|
|||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
center: [ 120.19382669582967, 30.258134 ],
|
||||
center: [ 110, 36 ],
|
||||
pitch: 0,
|
||||
style: 'light',
|
||||
zoom: 3
|
||||
|
@ -40,4 +40,5 @@ scene.on('loaded', () => {
|
|||
|
||||
scene.addLayer(pointLayer);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
import { Scene, PointLayer, PolygonLayer, LineLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
style: 'dark',
|
||||
pitch: 40,
|
||||
center: [ 118.8, 32.056 ],
|
||||
zoom: 12.5
|
||||
})
|
||||
});
|
||||
const fontFamily = 'iconfont';
|
||||
const fontPath =
|
||||
'//at.alicdn.com/t/font_2534097_x6rsov3i1g.woff2?t=1622107341225';
|
||||
scene.addIconFont('icon', '');
|
||||
scene.addFontFace(fontFamily, fontPath);
|
||||
|
||||
const colors = [
|
||||
'#87CEFA',
|
||||
'#00BFFF',
|
||||
|
||||
'#7FFFAA',
|
||||
'#00FF7F',
|
||||
'#32CD32',
|
||||
|
||||
'#F0E68C',
|
||||
'#FFD700',
|
||||
|
||||
'#FF7F50',
|
||||
'#FF6347',
|
||||
'#FF0000'
|
||||
];
|
||||
|
||||
scene.on('loaded', () => {
|
||||
fetch('https://gw.alipayobjects.com/os/bmw-prod/94763191-2816-4c1a-8d0d-8bcf4181056a.json')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
|
||||
const filllayer = new PolygonLayer({
|
||||
name: 'fill',
|
||||
zIndex: 3
|
||||
})
|
||||
.source(data)
|
||||
.shape('fill')
|
||||
.color('count', [ '#f2f0f7', '#dadaeb', '#bcbddc', '#9e9ac8', '#756bb1', '#54278f' ])
|
||||
.style({
|
||||
opacity: 0.6
|
||||
});
|
||||
scene.addLayer(filllayer);
|
||||
|
||||
const linelayer = new LineLayer({
|
||||
zIndex: 5,
|
||||
name: 'line2'
|
||||
})
|
||||
.source(data)
|
||||
.shape('line')
|
||||
.size(1)
|
||||
.color('#fff')
|
||||
.style({
|
||||
opacity: 0.3
|
||||
});
|
||||
scene.addLayer(linelayer);
|
||||
|
||||
const pointLayer = new PointLayer({
|
||||
zIndex: 10
|
||||
})
|
||||
.source(data)
|
||||
.shape('icon', 'text')
|
||||
.size(30)
|
||||
.color('count', t => {
|
||||
const c = Number(t.replace('℃', ''));
|
||||
return colors[Math.floor(((c - 18) / 16) * 10)];
|
||||
})
|
||||
.style({
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [ 30, 5 ],
|
||||
padding: [ 2, 2 ],
|
||||
fontFamily,
|
||||
iconfont: true
|
||||
// textAllowOverlap: true
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
|
||||
const tempertureLayer = new PointLayer({
|
||||
zIndex: 10
|
||||
})
|
||||
.source(data)
|
||||
.shape('count', 'text')
|
||||
.size(12)
|
||||
.color('count', t => {
|
||||
const c = Number(t.replace('℃', ''));
|
||||
return colors[Math.floor(((c - 18) / 16) * 10)];
|
||||
})
|
||||
.style({
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [ 35, 30 ],
|
||||
padding: [ 1, 1 ]
|
||||
});
|
||||
scene.addLayer(tempertureLayer);
|
||||
|
||||
});
|
||||
});
|
|
@ -0,0 +1,83 @@
|
|||
import { Scene, PointLayer, PolygonLayer, LineLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
style: 'dark',
|
||||
pitch: 40,
|
||||
center: [ 118.8, 32.056 ],
|
||||
zoom: 12.5
|
||||
})
|
||||
});
|
||||
const fontFamily = 'iconfont';
|
||||
const fontPath =
|
||||
'//at.alicdn.com/t/font_2534097_bl34aphh10n.woff2?t=1622180820063';
|
||||
scene.addIconFont('up', '');
|
||||
scene.addIconFont('down', '');
|
||||
scene.addFontFace(fontFamily, fontPath);
|
||||
|
||||
|
||||
scene.on('loaded', () => {
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/bmw-prod/41802695-0f7e-4a81-ab16-539c4e39df0d.json'
|
||||
)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
const filllayer = new PolygonLayer({
|
||||
name: 'fill',
|
||||
zIndex: 3
|
||||
})
|
||||
.source(data)
|
||||
.shape('fill')
|
||||
.color('count', [ '#f2f0f7', '#dadaeb', '#bcbddc', '#9e9ac8', '#756bb1', '#54278f' ])
|
||||
.style({
|
||||
opacity: 0.6
|
||||
});
|
||||
scene.addLayer(filllayer);
|
||||
|
||||
const linelayer = new LineLayer({
|
||||
zIndex: 5,
|
||||
name: 'line2'
|
||||
})
|
||||
.source(data)
|
||||
.shape('line')
|
||||
.size(1)
|
||||
.color('#fff')
|
||||
.style({
|
||||
opacity: 0.3
|
||||
});
|
||||
scene.addLayer(linelayer);
|
||||
|
||||
const pointLayer = new PointLayer({
|
||||
zIndex: 10
|
||||
})
|
||||
.source(data)
|
||||
.shape('icon', 'text')
|
||||
.size(15)
|
||||
.color('count', n => (n > 0 ? '#0f0' : '#f00'))
|
||||
.style({
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [ 30, 5 ],
|
||||
padding: [ 2, 2 ],
|
||||
fontFamily,
|
||||
iconfont: true
|
||||
// textAllowOverlap: true
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
|
||||
const textLayer = new PointLayer({
|
||||
zIndex: 10
|
||||
})
|
||||
.source(data)
|
||||
.shape('count', 'text')
|
||||
.size(12)
|
||||
.color('count', n => (n > 0 ? '#0f0' : '#f00'))
|
||||
.style({
|
||||
textAnchor: 'center', // 文本相对锚点的位置 center|left|right|top|bottom|top-left
|
||||
textOffset: [ 40, 10 ],
|
||||
padding: [ 1, 1 ]
|
||||
});
|
||||
scene.addLayer(textLayer);
|
||||
});
|
||||
});
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: COVID-19 地图
|
||||
title: COVID-19(新冠肺炎)地图
|
||||
order: 0
|
||||
---
|
||||
[![github](https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*Nk9mQ48ZoZMAAAAAAAAAAABkARQnAQ)](https://github.com/antvis/L7)
|
||||
|
|
|
@ -42,13 +42,15 @@ const World = React.memo(function Map() {
|
|||
options={{
|
||||
autoFit: true,
|
||||
}}
|
||||
|
||||
source={{
|
||||
data,
|
||||
// @ts-ignore
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'longitude',
|
||||
y: 'latitude',
|
||||
},
|
||||
}
|
||||
}}
|
||||
shape={{
|
||||
field: 'name',
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
"demos": [
|
||||
{
|
||||
"filename": "Point_image.tsx",
|
||||
"title": "点标注图",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*HQShTKuKq6wAAAAAAAAAAABkARQnAQ"
|
||||
"title": "图片标注图",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*w-8iQpR1NEQAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "marker.tsx",
|
||||
|
@ -18,6 +18,6 @@
|
|||
"filename": "popup.tsx",
|
||||
"title": "信息窗",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*RWngRL7rZKQAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -96,6 +96,7 @@ const World = React.memo(function Map() {
|
|||
{popupInfo && (
|
||||
<Popup
|
||||
key="popup"
|
||||
// @ts-ignore
|
||||
lnglat={popupInfo.lngLat}
|
||||
option={{ closeButton: false, offsets: [0, 10] }}
|
||||
>
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
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);
|
||||
});
|
|
@ -5,14 +5,9 @@
|
|||
},
|
||||
"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"
|
||||
"filename": "layer_highlight.js",
|
||||
"title": "交互高亮图层",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*jBzZRp_umUoAAAAAAAAAAAAAARQnAQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -52,7 +52,8 @@ window.onLoad = function() {
|
|||
});
|
||||
};
|
||||
|
||||
const url = 'https://webapi.amap.com/maps?v=1.4.15&key=15cd8a57710d40c9b7c0e3cc120f1200&callback=onLoad';
|
||||
// const url = 'https://webapi.amap.com/maps?v=1.4.15&key=15cd8a57710d40c9b7c0e3cc120f1200&callback=onLoad';
|
||||
const url = 'https://webapi.amap.com/maps?v=2.0&key=ff533602d57df6f8ab3b0fea226ae52f&callback=onLoad';
|
||||
const jsapi = document.createElement('script');
|
||||
jsapi.charset = 'utf-8';
|
||||
jsapi.src = url;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { Scene, PointLayer } from '@antv/l7';
|
||||
import { GaodeMap } from '@antv/l7-maps';
|
||||
|
||||
window.onLoad = function() {
|
||||
const map = new AMap.Map('map', {
|
||||
pitch: 0,
|
||||
mapStyle: 'amap://styles/darkblue',
|
||||
center: [ 121.435159, 31.256971 ],
|
||||
zoom: 14.89,
|
||||
minZoom: 10
|
||||
});
|
||||
const scene = new Scene({
|
||||
id: 'map',
|
||||
map: new GaodeMap({
|
||||
mapInstance: map
|
||||
})
|
||||
});
|
||||
scene.on('loaded', () => {
|
||||
fetch(
|
||||
'https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json'
|
||||
)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
const pointLayer = new PointLayer()
|
||||
.source(data, {
|
||||
parser: {
|
||||
type: 'json',
|
||||
x: 'longitude',
|
||||
y: 'latitude'
|
||||
}
|
||||
})
|
||||
.shape('name', [
|
||||
'circle',
|
||||
'triangle',
|
||||
'square',
|
||||
'pentagon',
|
||||
'hexagon',
|
||||
'octogon',
|
||||
'hexagram',
|
||||
'rhombus',
|
||||
'vesica'
|
||||
])
|
||||
.size('unit_price', [ 10, 25 ])
|
||||
.color('name', [ '#5B8FF9', '#5CCEA1', '#5D7092', '#F6BD16', '#E86452' ])
|
||||
.style({
|
||||
opacity: 0.3,
|
||||
strokeWidth: 2
|
||||
});
|
||||
scene.addLayer(pointLayer);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const url = 'https://webapi.amap.com/maps?v=2.0&key=ff533602d57df6f8ab3b0fea226ae52f&callback=onLoad';
|
||||
const jsapi = document.createElement('script');
|
||||
jsapi.charset = 'utf-8';
|
||||
jsapi.src = url;
|
||||
document.head.appendChild(jsapi);
|
|
@ -17,7 +17,12 @@
|
|||
{
|
||||
"filename": "amapInstance.js",
|
||||
"title": "通过高德地图实例化",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*_SIYR50bbcoAAAAAAAAAAABkARQnAQ"
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*C5d2RJ08hOkAAAAAAAAAAAAAARQnAQ"
|
||||
},
|
||||
{
|
||||
"filename": "amapInstance2d.js",
|
||||
"title": "通过高德地图实例化(2d)",
|
||||
"screenshot": "https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*C5d2RJ08hOkAAAAAAAAAAAAAARQnAQ"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ export default class Control extends EventEmitter {
|
|||
name: `${controlId++}`,
|
||||
};
|
||||
}
|
||||
public setPosition(position: PositionName = "bottomright") {
|
||||
public setPosition(position: PositionName = 'bottomright') {
|
||||
// 考虑组件的自动布局,需要销毁重建
|
||||
const controlService = this.controlService;
|
||||
if (controlService) {
|
||||
|
|
|
@ -474,5 +474,3 @@
|
|||
.amap-logo{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -56,7 +56,8 @@ export default class Marker extends EventEmitter {
|
|||
// this.sceneSerive.getSceneContainer().appendChild(element as HTMLElement);
|
||||
this.mapsService.getMarkerContainer().appendChild(element as HTMLElement);
|
||||
this.registerMarkerEvent(element as HTMLElement);
|
||||
this.mapsService.on('camerachange', this.update);
|
||||
this.mapsService.on('camerachange', this.update); // 注册高德1.x 的地图事件监听
|
||||
this.mapsService.on('viewchange', this.update); // 注册高德2.0 的地图事件监听
|
||||
this.update();
|
||||
this.added = true;
|
||||
this.emit('added');
|
||||
|
|
|
@ -32,6 +32,7 @@ const VALID_PROPS = [
|
|||
'cutoff',
|
||||
'radius',
|
||||
];
|
||||
|
||||
function getDefaultCharacterSet() {
|
||||
const charSet = [];
|
||||
for (let i = 32; i < 128; i++) {
|
||||
|
@ -51,6 +52,7 @@ function setTextStyle(
|
|||
ctx.textBaseline = 'middle';
|
||||
// ctx.textAlign = 'left';
|
||||
}
|
||||
|
||||
function populateAlphaChannel(alphaChannel: number[], imageData: ImageData) {
|
||||
// populate distance value from tinySDF to image alpha channel
|
||||
for (let i = 0; i < alphaChannel.length; i++) {
|
||||
|
@ -60,7 +62,23 @@ function populateAlphaChannel(alphaChannel: number[], imageData: ImageData) {
|
|||
|
||||
@injectable()
|
||||
export default class FontService implements IFontService {
|
||||
public get scale() {
|
||||
return HEIGHT_SCALE;
|
||||
}
|
||||
|
||||
public get canvas(): HTMLCanvasElement {
|
||||
const data = this.cache.get(this.key);
|
||||
return data && data.data;
|
||||
}
|
||||
|
||||
public get mapping(): IFontMapping {
|
||||
const data = this.cache.get(this.key);
|
||||
return data && data.mapping;
|
||||
}
|
||||
public fontAtlas: IFontAtlas;
|
||||
|
||||
// iconFontMap 记录用户设置的 iconfont unicode 和名称的键值关系
|
||||
public iconFontMap: Map<string, string>;
|
||||
private iconFontGlyphs: {
|
||||
[key: string]: string;
|
||||
} = {};
|
||||
|
@ -79,46 +97,52 @@ export default class FontService implements IFontService {
|
|||
sdf: true,
|
||||
cutoff: DEFAULT_CUTOFF,
|
||||
radius: DEFAULT_RADIUS,
|
||||
iconfont: false,
|
||||
};
|
||||
this.key = '';
|
||||
this.iconFontMap = new Map();
|
||||
}
|
||||
public addIconGlyphs(glyphs: IIconFontGlyph[]): void {
|
||||
glyphs.forEach((glyph) => {
|
||||
this.iconFontGlyphs[glyph.name] = glyph.unicode;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加对 iconfont unicode 的映射
|
||||
* @param fontUnicode
|
||||
* @param name
|
||||
*/
|
||||
public addIconFont(name: string, fontUnicode: string): void {
|
||||
this.iconFontMap.set(name, fontUnicode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自定义 iconfont 别称对应的 unicode 编码,若是当前的 map 中没有对应的键值对,那么就返回原值
|
||||
* @param name
|
||||
* @returns
|
||||
*/
|
||||
public getIconFontKey(name: string): string {
|
||||
return this.iconFontMap.get(name) || name;
|
||||
}
|
||||
|
||||
public getGlyph(name: string): string {
|
||||
if (this.iconFontGlyphs[name]) {
|
||||
return String.fromCharCode(parseInt(this.iconFontGlyphs[name], 16));
|
||||
}
|
||||
return '';
|
||||
}
|
||||
public get scale() {
|
||||
return HEIGHT_SCALE;
|
||||
}
|
||||
|
||||
public get canvas(): HTMLCanvasElement {
|
||||
const data = this.cache.get(this.key);
|
||||
return data && data.data;
|
||||
}
|
||||
|
||||
public get mapping(): IFontMapping {
|
||||
const data = this.cache.get(this.key);
|
||||
return data && data.mapping;
|
||||
}
|
||||
|
||||
public setFontOptions(option: Partial<IFontOptions>) {
|
||||
this.fontOptions = {
|
||||
...this.fontOptions,
|
||||
...option,
|
||||
};
|
||||
|
||||
// const oldKey = this.key;
|
||||
this.key = this.getKey();
|
||||
|
||||
const charSet = this.getNewChars(this.key, this.fontOptions.characterSet);
|
||||
const cachedFontAtlas = this.cache.get(this.key);
|
||||
|
||||
if (cachedFontAtlas && charSet.length === 0) {
|
||||
// update texture with cached fontAtlas
|
||||
return;
|
||||
|
@ -137,6 +161,7 @@ export default class FontService implements IFontService {
|
|||
|
||||
public destroy(): void {
|
||||
this.cache.clear();
|
||||
this.iconFontMap.clear();
|
||||
}
|
||||
|
||||
private generateFontAtlas(
|
||||
|
@ -152,6 +177,7 @@ export default class FontService implements IFontService {
|
|||
sdf,
|
||||
radius,
|
||||
cutoff,
|
||||
iconfont,
|
||||
} = this.fontOptions;
|
||||
let canvas = cachedFontAtlas && cachedFontAtlas.data;
|
||||
if (!canvas) {
|
||||
|
@ -197,7 +223,22 @@ export default class FontService implements IFontService {
|
|||
// tinySDF.size equals `fontSize + buffer * 2`
|
||||
const imageData = ctx.getImageData(0, 0, tinySDF.size, tinySDF.size);
|
||||
for (const char of characterSet) {
|
||||
if (iconfont) {
|
||||
// @ts-ignore
|
||||
// const icon = eval(
|
||||
// '("' + char.replace('&#x', '\\u').replace(';', '') + '")',
|
||||
// );
|
||||
|
||||
const icon = String.fromCharCode(
|
||||
parseInt(char.replace('&#x', '').replace(';', ''), 16),
|
||||
);
|
||||
const iconData = tinySDF.draw(icon);
|
||||
populateAlphaChannel(iconData, imageData);
|
||||
} else {
|
||||
populateAlphaChannel(tinySDF.draw(char), imageData);
|
||||
}
|
||||
// populateAlphaChannel(tinySDF.draw(char), imageData);
|
||||
|
||||
// 考虑到描边,需要保留 sdf 的 buffer,不能像 deck.gl 一样直接减去
|
||||
ctx.putImageData(imageData, mapping[char].x, mapping[char].y);
|
||||
}
|
||||
|
@ -221,6 +262,7 @@ export default class FontService implements IFontService {
|
|||
}
|
||||
|
||||
private getKey() {
|
||||
return 'key';
|
||||
const {
|
||||
fontFamily,
|
||||
fontWeight,
|
||||
|
@ -236,6 +278,13 @@ export default class FontService implements IFontService {
|
|||
return `${fontFamily} ${fontWeight} ${fontSize} ${buffer}`;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param characterSet
|
||||
* @returns
|
||||
* 若是相同的 key,那么将字符存储到同同一个字符列表中
|
||||
*/
|
||||
private getNewChars(key: string, characterSet: string[]): string[] {
|
||||
const cachedFontAtlas = this.cache.get(key);
|
||||
if (!cachedFontAtlas) {
|
||||
|
|
|
@ -7,6 +7,7 @@ export interface IFontOptions {
|
|||
sdf: boolean;
|
||||
cutoff: number;
|
||||
radius: number;
|
||||
iconfont: boolean;
|
||||
}
|
||||
export interface IFontMappingOption {
|
||||
characterSet: string[];
|
||||
|
@ -29,6 +30,10 @@ export interface IFontMapping {
|
|||
[key: string]: IFontMappingItem;
|
||||
[key: number]: IFontMappingItem;
|
||||
}
|
||||
|
||||
export interface IFontIconFontMapItem {
|
||||
[key: string]: string;
|
||||
}
|
||||
export interface IFontAtlas {
|
||||
xOffset: number;
|
||||
yOffset: number;
|
||||
|
@ -44,11 +49,14 @@ export interface IIconFontGlyph {
|
|||
}
|
||||
export interface IFontService {
|
||||
mapping: IFontMapping;
|
||||
iconFontMap: Map<string, string>;
|
||||
fontAtlas: IFontAtlas;
|
||||
canvas: HTMLCanvasElement;
|
||||
scale: number;
|
||||
init(): void;
|
||||
addIconGlyphs(glyphs: IIconFontGlyph[]): void;
|
||||
addIconFont(name: string, fontUnicode: string): void;
|
||||
getIconFontKey(name: string): string;
|
||||
getGlyph(name: string): string;
|
||||
setFontOptions(option: Partial<IFontOptions>): void;
|
||||
destroy(): void;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// @ts-ignore
|
||||
import TinySDF from '@mapbox/tiny-sdf';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { TYPES } from '../../types';
|
||||
|
@ -96,6 +98,9 @@ export default class IconService extends EventEmitter implements IIconService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将新增的 icon 图像存储到画布上(正方形)
|
||||
*/
|
||||
private updateIconAtlas() {
|
||||
this.canvas.width = MAX_CANVAS_WIDTH;
|
||||
this.canvas.height = this.canvasHeight;
|
||||
|
@ -117,6 +122,9 @@ export default class IconService extends EventEmitter implements IIconService {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算 icon 在画布上的排布(是否需要换行)
|
||||
*/
|
||||
private updateIconMap() {
|
||||
const { mapping, canvasHeight } = buildIconMaping(
|
||||
this.iconData,
|
||||
|
|
|
@ -24,7 +24,8 @@ export default class CameraService implements ICameraService {
|
|||
/**
|
||||
* ViewMatrix 逆矩阵,用于计算相机位置
|
||||
*/
|
||||
private viewMatrixInverse: number[];
|
||||
// private viewMatrixInverse: number[];
|
||||
private viewMatrixInverse: mat4;
|
||||
|
||||
/**
|
||||
* 相机位置
|
||||
|
@ -42,10 +43,12 @@ export default class CameraService implements ICameraService {
|
|||
this.viewport = viewport;
|
||||
|
||||
// 计算逆矩阵
|
||||
this.viewMatrixInverse = (mat4.invert(
|
||||
mat4.create(),
|
||||
(this.getViewMatrix() as unknown) as mat4,
|
||||
) as unknown) as number[];
|
||||
// this.viewMatrixInverse = (mat4.invert(
|
||||
// mat4.create(), (this.getViewMatrix() as unknown) as mat4,
|
||||
// ) as unknown) as number[];
|
||||
|
||||
this.viewMatrixInverse = mat4.create();
|
||||
mat4.invert(this.viewMatrixInverse, viewport.getViewMatrix() as mat4);
|
||||
|
||||
this.cameraPosition = [
|
||||
this.viewMatrixInverse[12],
|
||||
|
|
|
@ -79,6 +79,7 @@ const defaultLayerConfig: Partial<ILayerConfig> = {
|
|||
duration: 4,
|
||||
trailLength: 0.15,
|
||||
},
|
||||
forward: true, // 默认是正方向
|
||||
};
|
||||
|
||||
// @see https://github.com/epoberezkin/ajv#options
|
||||
|
|
|
@ -3,6 +3,7 @@ import { inject, injectable } from 'inversify';
|
|||
import { TYPES } from '../../types';
|
||||
import { getDistanceScales } from '../../utils/project';
|
||||
import { ICameraService } from '../camera/ICameraService';
|
||||
// import { IMapService } from '../map/IMapService'
|
||||
import {
|
||||
CoordinateSystem,
|
||||
ICoordinateSystemService,
|
||||
|
@ -17,6 +18,10 @@ export default class CoordinateSystemService
|
|||
@inject(TYPES.ICameraService)
|
||||
private readonly cameraService: ICameraService;
|
||||
|
||||
// map.getCenter
|
||||
// @inject(TYPES.IMapService)
|
||||
// private readonly mapService: IMapService
|
||||
|
||||
/**
|
||||
* 1. Web 墨卡托坐标系
|
||||
* 2. 偏移经纬度,用于解决高精度抖动问题
|
||||
|
|
|
@ -17,6 +17,7 @@ export enum CoordinateSystem {
|
|||
P20 = 5.0,
|
||||
P20_OFFSET = 6.0,
|
||||
METER_OFFSET = 7.0,
|
||||
P20_2 = 8.0,
|
||||
}
|
||||
|
||||
// 后续传入 Shader 的变量
|
||||
|
@ -27,6 +28,8 @@ export const CoordinateUniform = {
|
|||
PixelsPerDegree: 'u_PixelsPerDegree',
|
||||
PixelsPerDegree2: 'u_PixelsPerDegree2',
|
||||
PixelsPerMeter: 'u_PixelsPerMeter',
|
||||
|
||||
Mvp: 'u_Mvp',
|
||||
};
|
||||
|
||||
export interface ICoordinateSystemService {
|
||||
|
|
|
@ -130,6 +130,7 @@ export interface ILayer {
|
|||
scale(field: string | number | IScaleOptions, cfg?: IScale): ILayer;
|
||||
size(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
color(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
texture(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
shape(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
label(field: StyleAttrField, value?: StyleAttributeOption): ILayer;
|
||||
animate(option: Partial<IAnimateOption> | boolean): ILayer;
|
||||
|
@ -244,6 +245,8 @@ export interface ILayerConfig {
|
|||
enableMultiPassRenderer: boolean;
|
||||
passes: Array<string | [string, { [key: string]: unknown }]>;
|
||||
|
||||
forward: boolean; // 正方向
|
||||
|
||||
/**
|
||||
* 开启拾取
|
||||
*/
|
||||
|
@ -274,6 +277,10 @@ export interface ILayerConfig {
|
|||
*/
|
||||
enableLighting: boolean;
|
||||
animateOption: Partial<IAnimateOption>;
|
||||
/**
|
||||
* layer point text 是否是 iconfont 模式
|
||||
*/
|
||||
iconfont: boolean;
|
||||
onHover(pickedFeature: IPickedFeature): void;
|
||||
onClick(pickedFeature: IPickedFeature): void;
|
||||
}
|
||||
|
|
|
@ -30,8 +30,10 @@ export interface IMapWrapper {
|
|||
}
|
||||
|
||||
export interface IMapService<RawMap = {}> {
|
||||
version: string;
|
||||
map: RawMap;
|
||||
init(): void;
|
||||
initViewPort?(): void;
|
||||
destroy(): void;
|
||||
onCameraChanged(callback: (viewport: IViewport) => void): void;
|
||||
// init map
|
||||
|
@ -85,6 +87,12 @@ export interface IMapService<RawMap = {}> {
|
|||
scale: [number, number, number],
|
||||
origin: IMercator,
|
||||
): number[];
|
||||
lngLatToCoord?(lnglat: [number, number]): [number, number];
|
||||
lngLatToCoords?(
|
||||
lnglatArray: number[][][] | number[][],
|
||||
): number[][][] | number[][] | number[][][] | number[][];
|
||||
// lngLatToCoords?(lnglatArray: any): any;
|
||||
getCustomCoordCenter?(): [number, number];
|
||||
exportMap(type: 'jpg' | 'png'): string;
|
||||
}
|
||||
|
||||
|
@ -178,6 +186,9 @@ export interface IMapCamera {
|
|||
center: [number, number];
|
||||
// 相机高度
|
||||
cameraHeight: number;
|
||||
cameraPosition?: [number, number, number];
|
||||
up?: [number, number, number];
|
||||
lookAt?: [number, number, number];
|
||||
// 偏移原点,例如 P20 坐标系下
|
||||
offsetOrigin: [number, number];
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import { IRenderConfig } from '../renderer/IRendererService';
|
|||
export interface ISceneService {
|
||||
destroyed: boolean;
|
||||
loaded: boolean;
|
||||
fontFamily: string;
|
||||
loadFont: boolean;
|
||||
on(type: string, handle: (...args: any[]) => void): void;
|
||||
off(type: string, handle: (...args: any[]) => void): void;
|
||||
removeAllListeners(event?: string): this;
|
||||
|
@ -16,6 +18,7 @@ export interface ISceneService {
|
|||
getSceneContainer(): HTMLDivElement;
|
||||
getMarkerContainer(): HTMLElement;
|
||||
exportPng(type?: 'png' | 'jpg'): string;
|
||||
addFontFace(fontname: string, fontpath: string): void;
|
||||
destroy(): void;
|
||||
}
|
||||
// scene 事件
|
||||
|
|
|
@ -35,6 +35,10 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
public destroyed: boolean = false;
|
||||
|
||||
public loaded: boolean = false;
|
||||
// loadFont 判断用户当前是否添加自定义字体
|
||||
public loadFont: boolean = false;
|
||||
// fontFamily 用户当前自己添加的字体的名称
|
||||
public fontFamily: string = '';
|
||||
|
||||
@inject(TYPES.SceneID)
|
||||
private readonly id: string;
|
||||
|
@ -139,15 +143,32 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
*/
|
||||
this.hooks.init.tapPromise('initMap', async () => {
|
||||
// 等待首次相机同步
|
||||
await new Promise((resolve) => {
|
||||
await new Promise<void>((resolve) => {
|
||||
this.map.onCameraChanged((viewport: IViewport) => {
|
||||
this.cameraService.init();
|
||||
this.cameraService.update(viewport);
|
||||
if (this.map.version !== 'GAODE2.x') {
|
||||
// not amap2
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
if (this.map.version !== 'GAODE2.x') {
|
||||
// not amap2
|
||||
this.map.init();
|
||||
} else {
|
||||
// amap2
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
if (this.map.version === 'GAODE2.x' && this.map.initViewPort) {
|
||||
// amap2
|
||||
await this.map.init();
|
||||
this.map.initViewPort();
|
||||
}
|
||||
// this.controlService.addControls();
|
||||
|
||||
// 重新绑定非首次相机更新事件
|
||||
this.map.onCameraChanged(this.handleMapCameraChanged);
|
||||
this.map.addMarkerContainer();
|
||||
|
@ -208,7 +229,6 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
// 执行异步并行初始化任务
|
||||
// @ts-ignore
|
||||
this.initPromise = this.hooks.init.promise();
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
@ -222,15 +242,20 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
if (this.rendering || this.destroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rendering = true;
|
||||
// 首次初始化,或者地图的容器被强制销毁的需要重新初始化
|
||||
if (!this.inited) {
|
||||
// 还未初始化完成需要等待
|
||||
|
||||
await this.initPromise;
|
||||
if (this.destroyed) {
|
||||
this.destroy();
|
||||
}
|
||||
// @ts-ignore
|
||||
if (this.loadFont && document.fonts) {
|
||||
// @ts-ignore
|
||||
await document.fonts.load(`24px ${this.fontFamily}`, 'L7text');
|
||||
}
|
||||
// FIXME: 初始化 marker 容器,可以放到 map 初始化方法中?
|
||||
this.logger.info(' render inited');
|
||||
this.layerService.initLayers();
|
||||
|
@ -243,12 +268,30 @@ export default class Scene extends EventEmitter implements ISceneService {
|
|||
// 尝试初始化未初始化的图层
|
||||
this.layerService.renderLayers();
|
||||
// 组件需要等待layer 初始化完成之后添加
|
||||
|
||||
this.logger.debug(`scene ${this.id} render`);
|
||||
|
||||
this.rendering = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户自定义添加第三方字体 (用户使用 layer/point/text/iconfont 的前提需要加载第三方字体文件)
|
||||
* @param fontFamily
|
||||
* @param fontPath
|
||||
*/
|
||||
public addFontFace(fontFamily: string, fontPath: string): void {
|
||||
this.fontFamily = fontFamily;
|
||||
const style = document.createElement('style');
|
||||
style.type = 'text/css';
|
||||
style.innerText = `
|
||||
@font-face{
|
||||
font-family: '${fontFamily}';
|
||||
src: url('${fontPath}') format('woff2'),
|
||||
url('${fontPath}') format('woff'),
|
||||
url('${fontPath}') format('truetype');
|
||||
}`;
|
||||
document.getElementsByTagName('head')[0].appendChild(style);
|
||||
this.loadFont = true;
|
||||
}
|
||||
|
||||
public getSceneContainer(): HTMLDivElement {
|
||||
return this.$container as HTMLDivElement;
|
||||
}
|
||||
|
|
|
@ -38,3 +38,33 @@ float pixelDistance(vec2 from, vec2 to) {
|
|||
vec2 b1 = ProjectFlat(to);
|
||||
return distance(a1, b1);
|
||||
}
|
||||
|
||||
// gaode2.0
|
||||
vec2 customProject(vec2 lnglat) { // 经纬度 => 平面坐标
|
||||
float t = lnglat.x;
|
||||
float e = lnglat.y;
|
||||
float Sm = 180.0 / PI;
|
||||
float Tm = 6378137.0;
|
||||
float Rm = PI / 180.0;
|
||||
float r = 85.0511287798;
|
||||
e = max(min(r, e), -r);
|
||||
t *= Rm;
|
||||
e *= Rm;
|
||||
e = log(tan(PI / 4.0 + e / 2.0));
|
||||
return vec2(t * Tm, e * Tm);
|
||||
}
|
||||
|
||||
vec2 unProjCustomCoord(vec2 point) { // 平面坐标 => 经纬度
|
||||
float Sm = 57.29577951308232; //180 / Math.PI
|
||||
float Tm = 6378137.0;
|
||||
float t = point.x;
|
||||
float e = point.y;
|
||||
return vec2(t / Tm * Sm, (2.0 * atan(exp(e / Tm)) - PI / 2.0) * Sm);
|
||||
}
|
||||
|
||||
|
||||
float customPixelDistance(vec2 from, vec2 to) {
|
||||
vec2 a1 = ProjectFlat(from);
|
||||
vec2 b1 = ProjectFlat(to);
|
||||
return distance(a1, b1);
|
||||
}
|
|
@ -10,6 +10,8 @@
|
|||
#define COORDINATE_SYSTEM_P20_OFFSET 6.0
|
||||
#define COORDINATE_SYSTEM_METER_OFFSET 7.0
|
||||
|
||||
#define COORDINATE_SYSTEM_P20_2 8.0
|
||||
|
||||
uniform mat4 u_ViewMatrix;
|
||||
uniform mat4 u_ProjectionMatrix;
|
||||
uniform mat4 u_ViewProjectionMatrix;
|
||||
|
@ -28,6 +30,8 @@ uniform float u_DevicePixelRatio;
|
|||
uniform float u_FocalDistance;
|
||||
uniform vec3 u_CameraPosition;
|
||||
|
||||
// uniform mat4 u_Mvp;
|
||||
|
||||
// web mercator coords -> world coords
|
||||
vec2 project_mercator(vec2 lnglat) {
|
||||
float x = lnglat.x;
|
||||
|
@ -69,6 +73,10 @@ vec3 reverse_offset_normal(vec3 vector) {
|
|||
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20 ||u_CoordinateSystem == COORDINATE_SYSTEM_P20_OFFSET ) {
|
||||
return vector * vec3(1.0, -1.0, 1.0);
|
||||
}
|
||||
|
||||
if (u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.0
|
||||
return vector;
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
|
@ -97,6 +105,18 @@ vec4 project_position(vec4 position) {
|
|||
position.w
|
||||
);
|
||||
}
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) {
|
||||
// return vec4(
|
||||
// (position.xy * WORLD_SCALE * u_ZoomScale) * vec2(1., -1.),
|
||||
// project_scale(position.z),
|
||||
// position.w);
|
||||
|
||||
return vec4(
|
||||
position.xy,
|
||||
project_scale(position.z),
|
||||
position.w);
|
||||
}
|
||||
return position;
|
||||
|
||||
// TODO: 瓦片坐标系 & 常规世界坐标系
|
||||
|
@ -111,6 +131,10 @@ float project_pixel(float pixel) {
|
|||
// P20 坐标系下,为了和 Web 墨卡托坐标系统一,zoom 默认减1
|
||||
return pixel * pow(2.0, (19.0 - u_Zoom));
|
||||
}
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) {
|
||||
// P20_2 坐标系下,为了和 Web 墨卡托坐标系统一,zoom 默认减3
|
||||
return pixel * pow(2.0, (19.0 - 3.0 - u_Zoom));
|
||||
}
|
||||
return pixel;
|
||||
}
|
||||
vec2 project_pixel(vec2 pixel) {
|
||||
|
@ -118,6 +142,10 @@ vec2 project_pixel(vec2 pixel) {
|
|||
// P20 坐标系下,为了和 Web 墨卡托坐标系统一,zoom 默认减1
|
||||
return pixel * pow(2.0, (19.0 - u_Zoom));
|
||||
}
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) {
|
||||
// P20_2 坐标系下,为了和 Web 墨卡托坐标系统一,zoom 默认减3
|
||||
return pixel * pow(2.0, (19.0 - 3.0 - u_Zoom));
|
||||
}
|
||||
return pixel * -1.;
|
||||
}
|
||||
|
||||
|
@ -127,6 +155,7 @@ vec4 project_common_position_to_clipspace(vec4 position, mat4 viewProjectionMatr
|
|||
// Needs to be divided with project_uCommonUnitsPerMeter
|
||||
position.w *= u_PixelsPerMeter.z;
|
||||
}
|
||||
|
||||
return viewProjectionMatrix * position + center;
|
||||
}
|
||||
|
||||
|
@ -154,4 +183,3 @@ vec4 unproject_clipspace_to_position(vec4 clipspacePos, mat4 u_InverseViewProjec
|
|||
bool isEqual( float a, float b) {
|
||||
return a< b + 0.001 && a > b - 0.001;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ export function buildMapping({
|
|||
});
|
||||
|
||||
const rowHeight = fontHeight + buffer * 2;
|
||||
|
||||
return {
|
||||
mapping,
|
||||
xOffset: x,
|
||||
|
|
|
@ -14,6 +14,7 @@ attribute vec2 a_Uv;
|
|||
varying vec2 v_texCoord;
|
||||
|
||||
varying vec4 v_Color;
|
||||
uniform mat4 u_Mvp;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "light"
|
||||
|
@ -23,7 +24,12 @@ void main() {
|
|||
vec4 pos = vec4(a_Position.xy, a_Position.z * a_Size, 1.0);
|
||||
vec4 project_pos = project_position(pos);
|
||||
v_texCoord = a_Uv;
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xyz, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
}
|
||||
|
||||
float lightWeight = calc_lighting(pos);
|
||||
// v_Color = a_Color;
|
||||
|
|
|
@ -375,6 +375,16 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
return this;
|
||||
}
|
||||
|
||||
// 为对应的图层传入纹理的编号名称(point/image 在 shape 方法中传入纹理名称的方法并不通用)
|
||||
public texture(
|
||||
field: StyleAttributeField,
|
||||
values?: StyleAttributeOption,
|
||||
updateOptions?: Partial<IStyleAttributeUpdateOptions>,
|
||||
) {
|
||||
this.updateStyleAttribute('texture', field, values, updateOptions);
|
||||
return this;
|
||||
}
|
||||
|
||||
public rotate(
|
||||
field: StyleAttributeField,
|
||||
values?: StyleAttributeOption,
|
||||
|
@ -482,7 +492,6 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
...this.rawConfig,
|
||||
...rest,
|
||||
};
|
||||
|
||||
if (this.container) {
|
||||
this.updateLayerConfig(this.rawConfig);
|
||||
this.styleNeedUpdate = true;
|
||||
|
@ -500,6 +509,7 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
|
|||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public render(): ILayer {
|
||||
// if (
|
||||
// this.needPick() &&
|
||||
|
|
|
@ -8,4 +8,7 @@ export interface ILineLayerStyleOptions {
|
|||
lineType?: keyof typeof lineStyleType;
|
||||
dashArray?: [number, number];
|
||||
segmentNumber: number;
|
||||
forward?: boolean;
|
||||
lineTexture?: boolean;
|
||||
iconStep?: number;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ export function PointFillTriangulation(feature: IEncodeFeature) {
|
|||
*/
|
||||
export function PointExtrudeTriangulation(feature: IEncodeFeature) {
|
||||
const { shape } = feature;
|
||||
// console.log('PointExtrudeTriangulation', feature)
|
||||
const { positions, index, normals } = getGeometry(
|
||||
shape as ShapeType3D,
|
||||
false,
|
||||
|
@ -69,19 +70,45 @@ export function PointImageTriangulation(feature: IEncodeFeature) {
|
|||
* @param feature 映射feature
|
||||
*/
|
||||
export function LineTriangulation(feature: IEncodeFeature) {
|
||||
const { coordinates } = feature;
|
||||
const { coordinates, originCoordinates, version } = feature;
|
||||
// let path = coordinates as number[][][] | number[][];
|
||||
// if (!Array.isArray(path[0][0])) {
|
||||
// path = [coordinates] as number[][][];
|
||||
// }
|
||||
|
||||
const line = new ExtrudePolyline({
|
||||
dash: true,
|
||||
join: 'bevel',
|
||||
});
|
||||
|
||||
if (version === 'GAODE2.x') {
|
||||
// 处理高德2.0几何体构建
|
||||
let path1 = coordinates as number[][][] | number[][]; // 计算位置
|
||||
if (!Array.isArray(path1[0][0])) {
|
||||
path1 = [coordinates] as number[][][];
|
||||
}
|
||||
let path2 = originCoordinates as number[][][] | number[][]; // 计算法线
|
||||
if (!Array.isArray(path2[0][0])) {
|
||||
path2 = [originCoordinates] as number[][][];
|
||||
}
|
||||
|
||||
for (let i = 0; i < path1.length; i++) {
|
||||
// 高德2.0在计算线时,需要使用经纬度计算发现,使用 customCoords.lnglatToCoords 计算的数据来计算顶点的位置
|
||||
const item1 = path1[i];
|
||||
const item2 = path2[i];
|
||||
line.extrude_gaode2(item1 as number[][], item2 as number[][]);
|
||||
}
|
||||
} else {
|
||||
// 处理非高德2.0的几何体构建
|
||||
let path = coordinates as number[][][] | number[][];
|
||||
if (!Array.isArray(path[0][0])) {
|
||||
path = [coordinates] as number[][][];
|
||||
}
|
||||
const line = new ExtrudePolyline({
|
||||
dash: true,
|
||||
join: 'bevel', //
|
||||
});
|
||||
path.forEach((item: any) => {
|
||||
// 处理带洞的多边形
|
||||
line.extrude(item as number[][]);
|
||||
});
|
||||
}
|
||||
|
||||
const linebuffer = line.complex;
|
||||
return {
|
||||
vertices: linebuffer.positions, // [ x,y,z, distance, miter,total ]
|
||||
|
@ -199,6 +226,7 @@ export function LineArcTriangulation(feature: IEncodeFeature) {
|
|||
coordinates[1][0],
|
||||
coordinates[1][1],
|
||||
);
|
||||
|
||||
if (i !== segNum - 1) {
|
||||
indexArray.push(
|
||||
...[0, 1, 2, 1, 3, 2].map((v) => {
|
||||
|
@ -214,6 +242,11 @@ export function LineArcTriangulation(feature: IEncodeFeature) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建热力图密度图的顶点
|
||||
* @param feature
|
||||
* @returns
|
||||
*/
|
||||
export function HeatmapTriangulation(feature: IEncodeFeature) {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
if (coordinates.length === 2) {
|
||||
|
@ -256,6 +289,7 @@ function getGeometry(shape: ShapeType3D, needFlat = false): IExtrudeGeomety {
|
|||
: geometryShape.cylinder();
|
||||
const geometry = extrude_PolygonNormal([path], needFlat);
|
||||
GeometryCache[shape] = geometry;
|
||||
// console.log('geometry', geometry)
|
||||
return geometry;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,10 @@ export default class GridModel extends BaseModel {
|
|||
},
|
||||
size: 3,
|
||||
update: (feature: IEncodeFeature, featureIdx: number) => {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
// const coordinates = feature.coordinates as number[];
|
||||
const coordinates = (feature.version === 'GAODE2.x'
|
||||
? feature.originCoordinates
|
||||
: feature.coordinates) as number[];
|
||||
return [coordinates[0], coordinates[1], 0];
|
||||
},
|
||||
},
|
||||
|
|
|
@ -5,11 +5,11 @@ import {
|
|||
IModel,
|
||||
IModelUniform,
|
||||
} from '@antv/l7-core';
|
||||
import { aProjectFlat, Satistics, unProjectFlat } from '@antv/l7-utils';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import { PointExtrudeTriangulation } from '../../core/triangulation';
|
||||
import heatmapGrid3dVert from '../shaders/hexagon_3d_vert.glsl';
|
||||
import heatmapGridFrag from '../shaders/hexagon_frag.glsl';
|
||||
|
||||
interface IHeatMapLayerStyleOptions {
|
||||
opacity: number;
|
||||
coverage: number;
|
||||
|
@ -112,7 +112,11 @@ export default class Grid3DModel extends BaseModel {
|
|||
},
|
||||
size: 3,
|
||||
update: (feature: IEncodeFeature, featureIdx: number) => {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
const coordinates = (feature.version === 'GAODE2.x'
|
||||
? feature.originCoordinates
|
||||
: feature.coordinates) as number[];
|
||||
// const coordinates = feature.coordinates as number[];
|
||||
// const coordinates = feature.originCoordinates as number[];
|
||||
return [coordinates[0], coordinates[1], 0];
|
||||
},
|
||||
},
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from '@antv/l7-core';
|
||||
import { generateColorRamp, IColorRamp } from '@antv/l7-utils';
|
||||
import { mat4 } from 'gl-matrix';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
import { HeatmapTriangulation } from '../../core/triangulation';
|
||||
import heatmap3DFrag from '../shaders/heatmap_3d_frag.glsl';
|
||||
|
@ -25,7 +26,7 @@ interface IHeatMapLayerStyleOptions {
|
|||
angle: number;
|
||||
rampColors: IColorRamp;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export default class HeatMapModel extends BaseModel {
|
||||
protected texture: ITexture2D;
|
||||
protected colorTexture: ITexture2D;
|
||||
|
@ -256,13 +257,20 @@ export default class HeatMapModel extends BaseModel {
|
|||
const {
|
||||
opacity,
|
||||
} = this.layer.getLayerConfig() as IHeatMapLayerStyleOptions;
|
||||
const invert = mat4.invert(
|
||||
mat4.create(),
|
||||
mat4.fromValues(
|
||||
// @ts-ignore
|
||||
...this.cameraService.getViewProjectionMatrixUncentered(),
|
||||
),
|
||||
) as mat4;
|
||||
|
||||
// const invert = mat4.invert(
|
||||
// mat4.create(),
|
||||
// mat4.fromValues(
|
||||
// // @ts-ignore
|
||||
// ...this.cameraService.getViewProjectionMatrixUncentered(),
|
||||
// ),
|
||||
// ) as mat4;
|
||||
const invert = mat4.create();
|
||||
mat4.invert(
|
||||
invert,
|
||||
this.cameraService.getViewProjectionMatrixUncentered() as mat4,
|
||||
);
|
||||
|
||||
this.colorModel.draw({
|
||||
uniforms: {
|
||||
u_opacity: opacity || 1.0,
|
||||
|
|
|
@ -65,7 +65,12 @@ export default class HexagonModel extends BaseModel {
|
|||
},
|
||||
size: 3,
|
||||
update: (feature: IEncodeFeature, featureIdx: number) => {
|
||||
const coordinates = feature.coordinates as number[];
|
||||
// const coordinates = (feature.verison==='GAODE2.x'?feature.originoordinates:feature.coordinates) as number[];
|
||||
const coordinates = (feature.version === 'GAODE2.x'
|
||||
? feature.originCoordinates
|
||||
: feature.coordinates) as number[];
|
||||
// const coordinates = feature.coordinates as number[];
|
||||
// const coordinates = feature.originCoordinates as number[];
|
||||
return [coordinates[0], coordinates[1], 0];
|
||||
},
|
||||
},
|
||||
|
|
|
@ -9,8 +9,11 @@ uniform vec2 u_radius;
|
|||
uniform float u_coverage: 0.9;
|
||||
uniform float u_angle: 0;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
varying vec4 v_color;
|
||||
|
||||
uniform vec2 u_SceneCenterMKT;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "picking"
|
||||
|
@ -20,9 +23,20 @@ void main() {
|
|||
|
||||
mat2 rotationMatrix = mat2(cos(u_angle), sin(u_angle), -sin(u_angle), cos(u_angle));
|
||||
vec2 offset = a_Position.xy * u_radius * rotationMatrix * u_coverage ;
|
||||
// vec2 lnglat = unProjectFlat(a_Pos.xy + offset);
|
||||
// vec4 project_pos = project_position(vec4(lnglat, 0, 1.0));
|
||||
// gl_Position = project_common_position_to_clipspace(project_pos);
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
vec2 lnglat = unProjectFlat(a_Pos.xy + offset);
|
||||
vec2 customLnglat = customProject(lnglat) - u_SceneCenterMKT; // 将经纬度转换为高德2.0需要的平面坐标
|
||||
vec4 project_pos = project_position(vec4(customLnglat, 0, 1.0));
|
||||
gl_Position = u_Mvp * (project_pos);
|
||||
} else {
|
||||
vec2 lnglat = unProjectFlat(a_Pos.xy + offset);
|
||||
vec4 project_pos = project_position(vec4(lnglat, 0, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(project_pos);
|
||||
}
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -11,5 +11,4 @@ void main(){
|
|||
gl_FragColor = color;
|
||||
// gl_FragColor.a = color.a * smoothstep(0.1,0.2,intensity)* u_opacity;
|
||||
gl_FragColor.a = color.a * smoothstep(0.,0.1,intensity) * u_opacity;
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ uniform mat4 u_InverseViewProjectionMatrix;
|
|||
uniform mat4 u_ViewProjectionMatrixUncentered;
|
||||
varying float v_intensity;
|
||||
|
||||
|
||||
vec2 toBezier(float t, vec2 P0, vec2 P1, vec2 P2, vec2 P3) {
|
||||
float t2 = t * t;
|
||||
float one_minus_t = 1.0 - t;
|
||||
|
@ -21,22 +22,21 @@ vec2 toBezier(float t, vec4 p){
|
|||
void main() {
|
||||
v_texCoord = a_Uv;
|
||||
|
||||
vec2 pos =(a_Uv * vec2(2.0) - vec2(1.0));
|
||||
vec2 pos = a_Uv * vec2(2.0) - vec2(1.0); // 将原本 0 -> 1 的 uv 转换为 -1 -> 1 的标准坐标空间(NDC)
|
||||
|
||||
vec4 p1 = vec4(pos, 0.0, 1.0); // x/y 平面上的点(z == 0)可以认为是三维上的点被投影到平面后的点
|
||||
vec4 p2 = vec4(pos, 1.0, 1.0); // 平行于x/y平面、z==1 的平面上的点
|
||||
|
||||
vec4 p1 = vec4(pos, 0.0, 1.0);
|
||||
vec4 p2 = vec4(pos, 1.0, 1.0);
|
||||
|
||||
vec4 inverseP1 = u_InverseViewProjectionMatrix * p1;
|
||||
vec4 inverseP1 = u_InverseViewProjectionMatrix * p1; // 根据视图投影矩阵的逆矩阵平面上的反算出三维空间中的点(p1平面上的点)
|
||||
vec4 inverseP2 = u_InverseViewProjectionMatrix * p2;
|
||||
|
||||
inverseP1 = inverseP1 / inverseP1.w;
|
||||
inverseP1 = inverseP1 / inverseP1.w; // 归一化操作(归一化后为世界坐标)
|
||||
inverseP2 = inverseP2 / inverseP2.w;
|
||||
|
||||
float zPos = (0.0 - inverseP1.z) / (inverseP2.z - inverseP1.z);
|
||||
float zPos = (0.0 - inverseP1.z) / (inverseP2.z - inverseP1.z); // ??
|
||||
vec4 position = inverseP1 + zPos * (inverseP2 - inverseP1);
|
||||
|
||||
vec4 b= vec4(0.5000, 0, 1, 0.5000);
|
||||
vec4 b= vec4(0.5000, 0.0, 1.0, 0.5000);
|
||||
float fh;
|
||||
|
||||
v_intensity = texture2D(u_texture, v_texCoord).r;
|
||||
|
|
|
@ -7,6 +7,7 @@ uniform float u_radius;
|
|||
varying vec2 v_extrude;
|
||||
varying float v_weight;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
|
||||
#define GAUSS_COEF 0.3989422804014327
|
||||
|
||||
|
@ -24,5 +25,11 @@ void main(){
|
|||
vec2 offset = project_pixel(v_extrude * u_radius);
|
||||
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xy + offset, 0.0, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,21 +11,54 @@ uniform vec2 u_radius;
|
|||
uniform float u_coverage: 0.9;
|
||||
uniform float u_angle: 0;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
varying vec4 v_color;
|
||||
|
||||
uniform vec2 u_SceneCenterMKT;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "light"
|
||||
#pragma include "picking"
|
||||
|
||||
|
||||
void main() {
|
||||
mat2 rotationMatrix = mat2(cos(u_angle), sin(u_angle), -sin(u_angle), cos(u_angle));
|
||||
vec2 offset =(vec2(a_Position.xy * u_radius * rotationMatrix * u_coverage));
|
||||
vec2 lnglat = unProjectFlat(a_Pos.xy + offset);
|
||||
// vec2 lnglat = unProjectFlat(a_Pos.xy + offset); // 实际的经纬度
|
||||
// vec2 lnglat = (a_Pos.xy + offset);
|
||||
// vec4 project_pos = project_position(vec4(lnglat, a_Position.z * a_Size, 1.0));
|
||||
// gl_Position = project_common_position_to_clipspace(project_pos);
|
||||
// float lightWeight = calc_lighting(project_pos);
|
||||
// v_color =vec4(a_Color.rgb*lightWeight, a_Color.w);
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
// vec2 lnglat = (a_Pos.xy + offset);
|
||||
// vec4 project_pos = project_position(vec4(lnglat, a_Position.z * a_Size, 1.0));
|
||||
|
||||
// float lightWeight = calc_lighting(project_pos);
|
||||
// v_color =vec4(a_Color.rgb*lightWeight, a_Color.w);
|
||||
|
||||
// gl_Position = u_Mvp * vec4(lnglat , a_Position.z * a_Size, 1.0);
|
||||
vec2 lnglat = unProjectFlat(a_Pos.xy + offset); // 经纬度
|
||||
vec2 customLnglat = customProject(lnglat) - u_SceneCenterMKT; // 将经纬度转换为高德2.0需要的平面坐标
|
||||
vec4 project_pos = project_position(vec4(customLnglat, a_Position.z * a_Size, 1.0));
|
||||
|
||||
float lightWeight = calc_lighting(project_pos);
|
||||
v_color =vec4(a_Color.rgb*lightWeight, a_Color.w);
|
||||
|
||||
gl_Position = u_Mvp * vec4(customLnglat , a_Position.z * a_Size, 1.0);
|
||||
} else {
|
||||
vec2 lnglat = unProjectFlat(a_Pos.xy + offset); // 实际的经纬度
|
||||
vec4 project_pos = project_position(vec4(lnglat, a_Position.z * a_Size, 1.0));
|
||||
|
||||
float lightWeight = calc_lighting(project_pos);
|
||||
v_color =vec4(a_Color.rgb*lightWeight, a_Color.w);
|
||||
|
||||
gl_Position = project_common_position_to_clipspace(project_pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -9,8 +9,11 @@ uniform vec2 u_radius;
|
|||
uniform float u_coverage: 0.9;
|
||||
uniform float u_angle: 0;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
varying vec4 v_color;
|
||||
|
||||
uniform vec2 u_SceneCenterMKT;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "picking"
|
||||
|
@ -21,7 +24,18 @@ void main() {
|
|||
mat2 rotationMatrix = mat2(cos(u_angle), sin(u_angle), -sin(u_angle), cos(u_angle));
|
||||
vec2 offset =(vec2(a_Position.xy * u_radius * rotationMatrix * u_coverage));
|
||||
vec2 lnglat = unProjectFlat(a_Pos.xy + offset);
|
||||
|
||||
// vec4 project_pos = project_position(vec4(lnglat, 0, 1.0));
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy, 0., 1.0));
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
// gl_Position = u_Mvp * (vec4(project_pos.xy, 0., 1.0));
|
||||
// gl_Position = u_Mvp * (vec4(a_Pos.xy + offset, 0., 1.0));
|
||||
vec2 customLnglat = customProject(lnglat) - u_SceneCenterMKT;
|
||||
vec4 project_pos = project_position(vec4(customLnglat, 0, 1.0));
|
||||
gl_Position = u_Mvp * vec4(project_pos.xy, 0.0, 1.0);
|
||||
} else {
|
||||
vec4 project_pos = project_position(vec4(lnglat, 0, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy, 0., 1.0));
|
||||
}
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
precision highp float;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec2 a_Uv;
|
||||
varying vec2 v_texCoord;
|
||||
|
@ -7,5 +8,10 @@ varying vec2 v_texCoord;
|
|||
void main() {
|
||||
v_texCoord = a_Uv;
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy,0., 1.0));
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xy,0., 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy,0., 1.0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ export default class ArcModel extends BaseModel {
|
|||
opacity,
|
||||
lineType = 'solid',
|
||||
dashArray = [10, 5],
|
||||
forward = true,
|
||||
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
|
||||
if (dashArray.length === 2) {
|
||||
dashArray.push(0, 0);
|
||||
|
@ -33,6 +34,7 @@ export default class ArcModel extends BaseModel {
|
|||
u_line_type: lineStyleObj[lineType || 'solid'],
|
||||
u_dash_array: dashArray,
|
||||
u_blur: 0.9,
|
||||
u_lineDir: forward ? 1 : -1,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,11 @@ import {
|
|||
gl,
|
||||
IAnimateOption,
|
||||
IEncodeFeature,
|
||||
IImage,
|
||||
ILayerConfig,
|
||||
IModel,
|
||||
IModelUniform,
|
||||
ITexture2D,
|
||||
} from '@antv/l7-core';
|
||||
|
||||
import BaseModel from '../../core/BaseModel';
|
||||
|
@ -18,19 +20,32 @@ const lineStyleObj: { [key: string]: number } = {
|
|||
dash: 1.0,
|
||||
};
|
||||
export default class LineModel extends BaseModel {
|
||||
protected texture: ITexture2D;
|
||||
public getUninforms(): IModelUniform {
|
||||
const {
|
||||
opacity,
|
||||
lineType = 'solid',
|
||||
dashArray = [10, 5, 0, 0],
|
||||
lineTexture = false,
|
||||
iconStep = 100,
|
||||
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
|
||||
if (dashArray.length === 2) {
|
||||
dashArray.push(0, 0);
|
||||
}
|
||||
|
||||
if (this.rendererService.getDirty()) {
|
||||
this.texture.bind();
|
||||
}
|
||||
|
||||
return {
|
||||
u_opacity: opacity || 1.0,
|
||||
u_line_type: lineStyleObj[lineType],
|
||||
u_dash_array: dashArray,
|
||||
|
||||
u_texture: this.texture, // 贴图
|
||||
u_line_texture: lineTexture ? 1.0 : 0.0, // 传入线的标识
|
||||
u_icon_step: iconStep,
|
||||
u_textSize: [1024, this.iconService.canvasHeight || 128],
|
||||
};
|
||||
}
|
||||
public getAnimateUniforms(): IModelUniform {
|
||||
|
@ -42,9 +57,33 @@ export default class LineModel extends BaseModel {
|
|||
}
|
||||
|
||||
public initModels(): IModel[] {
|
||||
// const { createTexture2D } = this.rendererService;
|
||||
// this.texture = createTexture2D({
|
||||
// height: 0,
|
||||
// width: 0,
|
||||
// });
|
||||
// let url = 'https://gw-office.alipayobjects.com/bmw-prod/e91c3630-b79e-45a3-a2b9-feee4b4ccd41.svg'
|
||||
// this.loadImage(url).then((img) => {
|
||||
// this.texture = createTexture2D({
|
||||
// data: img as HTMLImageElement,
|
||||
// width: (img as HTMLImageElement).width,
|
||||
// height: (img as HTMLImageElement).height,
|
||||
// });
|
||||
// this.layerService.renderLayers();
|
||||
// })
|
||||
this.updateTexture();
|
||||
this.iconService.on('imageUpdate', this.updateTexture);
|
||||
|
||||
return this.buildModels();
|
||||
}
|
||||
|
||||
public clearModels() {
|
||||
if (this.texture) {
|
||||
this.texture.destroy();
|
||||
}
|
||||
this.iconService.off('imageUpdate', this.updateTexture);
|
||||
}
|
||||
|
||||
public buildModels(): IModel[] {
|
||||
return [
|
||||
this.layer.buildLayerModel({
|
||||
|
@ -182,5 +221,68 @@ export default class LineModel extends BaseModel {
|
|||
},
|
||||
},
|
||||
});
|
||||
|
||||
this.styleAttributeService.registerStyleAttribute({
|
||||
name: 'uv',
|
||||
type: AttributeType.Attribute,
|
||||
descriptor: {
|
||||
name: 'a_iconMapUV',
|
||||
buffer: {
|
||||
// give the WebGL driver a hint that this buffer may change
|
||||
usage: gl.DYNAMIC_DRAW,
|
||||
data: [],
|
||||
type: gl.FLOAT,
|
||||
},
|
||||
size: 2,
|
||||
update: (
|
||||
feature: IEncodeFeature,
|
||||
featureIdx: number,
|
||||
vertex: number[],
|
||||
attributeIdx: number,
|
||||
) => {
|
||||
const iconMap = this.iconService.getIconMap();
|
||||
const { texture } = feature;
|
||||
const { x, y } = iconMap[texture as string] || { x: 0, y: 0 };
|
||||
return [x, y];
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private loadImage(url: IImage) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (url instanceof HTMLImageElement) {
|
||||
resolve(url);
|
||||
return;
|
||||
}
|
||||
const image = new Image();
|
||||
image.crossOrigin = 'anonymous';
|
||||
image.onload = () => {
|
||||
resolve(image);
|
||||
};
|
||||
image.onerror = () => {
|
||||
reject(new Error('Could not load image at ' + url));
|
||||
};
|
||||
image.src = url instanceof File ? URL.createObjectURL(url) : url;
|
||||
});
|
||||
}
|
||||
|
||||
private updateTexture = () => {
|
||||
const { createTexture2D } = this.rendererService;
|
||||
if (this.texture) {
|
||||
this.texture.update({
|
||||
data: this.iconService.getCanvas(),
|
||||
});
|
||||
this.layer.render();
|
||||
return;
|
||||
}
|
||||
this.texture = createTexture2D({
|
||||
data: this.iconService.getCanvas(),
|
||||
mag: gl.NEAREST,
|
||||
min: gl.NEAREST,
|
||||
premultiplyAlpha: false,
|
||||
width: 1024,
|
||||
height: this.iconService.canvasHeight || 128,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ attribute vec4 a_Color;
|
|||
attribute float a_Size;
|
||||
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
uniform float segmentNumber;
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
varying vec4 v_color;
|
||||
|
@ -85,6 +86,11 @@ void main() {
|
|||
vec2 offset = getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(curr.xy + project_pixel(offset), curr.z, 1.0));
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(curr.xy + project_pixel(offset), curr.z, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + project_pixel(offset), curr.z, 1.0));
|
||||
}
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -35,5 +35,16 @@ void main() {
|
|||
alpha = smoothstep(0., 1., alpha);
|
||||
gl_FragColor.a *= alpha;
|
||||
}
|
||||
|
||||
// if(u_line_texture == LineTexture) { // while load texture
|
||||
// //v_u; // 水平
|
||||
// float v = length(v_offset)/(v_a); // 横向
|
||||
// vec2 uv= v_iconMapUV / u_textSize + vec2(v_u, v) / u_textSize * 64.;
|
||||
// // gl_FragColor = vec4(v_u, v, 0.0, 1.0);
|
||||
// // gl_FragColor = vec4(1.0, 0.0, 0.0, v_u);
|
||||
// gl_FragColor = filterColor(gl_FragColor + texture2D(u_texture, uv));
|
||||
// } else {
|
||||
// gl_FragColor = filterColor(gl_FragColor);
|
||||
// }
|
||||
gl_FragColor = filterColor(gl_FragColor);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ attribute vec3 a_Position;
|
|||
attribute vec4 a_Instance;
|
||||
attribute float a_Size;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
uniform float segmentNumber;
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
varying vec4 v_color;
|
||||
|
@ -68,8 +69,30 @@ float getAngularDist (vec2 source, vec2 target) {
|
|||
sin_half_delta.x * sin_half_delta.x;
|
||||
return 2.0 * atan(sqrt(a), sqrt(1.0 - a));
|
||||
}
|
||||
|
||||
vec2 midPoint(vec2 source, vec2 target) {
|
||||
vec2 center = target - source;
|
||||
float r = length(center);
|
||||
float theta = atan(center.y, center.x);
|
||||
float thetaOffset = 0.314;
|
||||
float r2 = r / 2.0 / cos(thetaOffset);
|
||||
float theta2 = theta + thetaOffset;
|
||||
vec2 mid = vec2(r2*cos(theta2) + source.x, r2*sin(theta2) + source.y);
|
||||
return mid;
|
||||
}
|
||||
float bezier3(vec3 arr, float t) {
|
||||
float ut = 1. - t;
|
||||
return (arr.x * ut + arr.y * t) * ut + (arr.y * ut + arr.z * t) * t;
|
||||
}
|
||||
|
||||
vec2 interpolate (vec2 source, vec2 target, float angularDist, float t) {
|
||||
// if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
vec2 mid = midPoint(source, target);
|
||||
vec3 x = vec3(source.x, mid.x, target.x);
|
||||
vec3 y = vec3(source.y, mid.y, target.y);
|
||||
return vec2(bezier3(x ,t), bezier3(y,t));
|
||||
}else {
|
||||
if(abs(angularDist - PI) < 0.001) {
|
||||
return (1.0 - t) * source + t * target;
|
||||
}
|
||||
|
@ -84,6 +107,7 @@ vec2 interpolate (vec2 source, vec2 target, float angularDist, float t) {
|
|||
float z = a * sin_source.y + b * sin_target.y;
|
||||
return vec2(atan(y, x), atan(z, sqrt(x * x + y * y)));
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
|
@ -108,7 +132,13 @@ void main() {
|
|||
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y));
|
||||
// vec4 project_pos = project_position(vec4(curr.xy, 0, 1.0));
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, curr.z, 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(curr.xy + offset, curr.z, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, curr.z, 1.0));
|
||||
}
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
#define LineTypeSolid 0.0
|
||||
#define LineTypeDash 1.0
|
||||
#define Animate 0.0
|
||||
// #define LineTexture 1.0
|
||||
attribute vec4 a_Color;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec4 a_Instance;
|
||||
attribute float a_Size;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
uniform float segmentNumber;
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
varying vec4 v_color;
|
||||
|
@ -14,7 +16,17 @@ varying vec2 v_normal;
|
|||
varying float v_distance_ratio;
|
||||
uniform float u_line_type: 0.0;
|
||||
uniform vec4 u_dash_array: [10.0, 5., 0, 0];
|
||||
uniform float u_lineDir: 1.0;
|
||||
varying vec4 v_dash_array;
|
||||
|
||||
// uniform float u_icon_step: 100;
|
||||
// uniform float u_line_texture;
|
||||
// varying float v_u;
|
||||
// varying vec2 v_offset;
|
||||
// varying float v_a;
|
||||
// attribute vec2 a_iconMapUV;
|
||||
// varying vec2 v_iconMapUV;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "project"
|
||||
#pragma include "picking"
|
||||
|
@ -31,7 +43,14 @@ vec2 midPoint(vec2 source, vec2 target) {
|
|||
float r2 = r / 2.0 / cos(thetaOffset);
|
||||
float theta2 = theta + thetaOffset;
|
||||
vec2 mid = vec2(r2*cos(theta2) + source.x, r2*sin(theta2) + source.y);
|
||||
if(u_lineDir == 1.0) { // 正向
|
||||
return mid;
|
||||
} else { // 逆向
|
||||
// (mid + vmin)/2 = (s + t)/2
|
||||
vec2 vmid = source + target - mid;
|
||||
return vmid;
|
||||
}
|
||||
// return mid;
|
||||
}
|
||||
float getSegmentRatio(float index) {
|
||||
return smoothstep(0.0, 1.0, index / (segmentNumber - 1.));
|
||||
|
@ -61,10 +80,12 @@ vec2 getNormal(vec2 line_clipspace, float offset_direction) {
|
|||
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
|
||||
vec2 source = a_Instance.rg;
|
||||
vec2 target = a_Instance.ba;
|
||||
float segmentIndex = a_Position.x;
|
||||
float segmentRatio = getSegmentRatio(segmentIndex);
|
||||
|
||||
float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
|
||||
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
|
||||
if(u_line_type == LineTypeDash) {
|
||||
|
@ -74,12 +95,40 @@ void main() {
|
|||
}
|
||||
if(u_aimate.x == Animate) {
|
||||
v_distance_ratio = segmentIndex / segmentNumber;
|
||||
if(u_lineDir != 1.0) {
|
||||
v_distance_ratio = 1.0 - v_distance_ratio;
|
||||
}
|
||||
}
|
||||
vec4 curr = project_position(vec4(interpolate(source, target, segmentRatio), 0.0, 1.0));
|
||||
vec4 next = project_position(vec4(interpolate(source, target, nextSegmentRatio), 0.0, 1.0));
|
||||
v_normal = getNormal((next.xy - curr.xy) * indexDir, a_Position.y);
|
||||
|
||||
vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y));
|
||||
|
||||
// if(LineTexture == u_line_texture) { // 开启贴图模式
|
||||
// v_iconMapUV = a_iconMapUV;
|
||||
|
||||
// float arctotal_Distance = length(source - target);
|
||||
// float pixelLen = project_pixel(u_icon_step);
|
||||
// v_u = fract(segmentRatio * (floor(arctotal_Distance/pixelLen)));
|
||||
// // v_u = fract(segmentIndex/(segmentNumber) * (2.0));
|
||||
// // v_u = fract(segmentIndex/(segmentNumber - 1.0) * 1.0 + 0.3);
|
||||
// // v_u = fract(mod(1.0- v_distance_ratio, 0.2)* (1.0/ 0.5));
|
||||
// // v_u = fract(clamp(v_u, 0.0, 1.0)*2.0);
|
||||
// // v_u = fract(((segmentIndex * indexDir) / (segmentNumber - 1.)) * (floor(arctotal_Distance/pixelLen)));
|
||||
// // float s = 6.0;
|
||||
// // float l = segmentNumber/s;
|
||||
// // v_u = mod(segmentIndex, l) / (segmentNumber/s);
|
||||
// v_a = project_pixel(a_Size);
|
||||
// v_offset = offset + offset * sign(a_Position.y);
|
||||
// }
|
||||
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(curr.xy + offset, 0, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(curr.xy + offset, 0, 1.0));
|
||||
}
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
#define LineTypeSolid 0.0
|
||||
#define LineTypeDash 1.0
|
||||
#define Animate 0.0
|
||||
#define LineTexture 1.0
|
||||
uniform float u_blur : 0.99;
|
||||
uniform float u_line_type: 0.0;
|
||||
uniform float u_opacity : 1.0;
|
||||
varying vec4 v_color;
|
||||
varying vec2 v_normal;
|
||||
|
||||
// line texture
|
||||
uniform float u_line_texture;
|
||||
uniform sampler2D u_texture;
|
||||
uniform vec2 u_textSize;
|
||||
|
||||
// dash
|
||||
uniform float u_dash_offset : 0.0;
|
||||
|
@ -15,19 +20,27 @@ varying float v_distance_ratio;
|
|||
varying vec4 v_dash_array;
|
||||
varying float v_side;
|
||||
|
||||
varying float v_distance;
|
||||
varying vec2 v_offset;
|
||||
varying float v_a;
|
||||
varying float v_pixelLen;
|
||||
varying vec2 v_iconMapUV;
|
||||
varying float v_strokeWidth;
|
||||
|
||||
#pragma include "picking"
|
||||
|
||||
uniform float u_time;
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ]; // 控制运动
|
||||
// [animate, duration, interval, trailLength],
|
||||
void main() {
|
||||
float animateSpeed = 0.0; // 运动速度
|
||||
gl_FragColor = v_color;
|
||||
// anti-alias
|
||||
// float blur = 1.0 - smoothstep(u_blur, 1., length(v_normal.xy));
|
||||
gl_FragColor.a *= u_opacity;
|
||||
gl_FragColor.a *= u_opacity; // 全局透明度
|
||||
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);
|
||||
animateSpeed = u_time / u_aimate.y;
|
||||
float alpha =1.0 - fract( mod(1.0- v_distance_ratio, u_aimate.z)* (1.0/ u_aimate.z) + animateSpeed);
|
||||
alpha = (alpha + u_aimate.w -1.0) / u_aimate.w;
|
||||
alpha = smoothstep(0., 1., alpha);
|
||||
gl_FragColor.a *= alpha;
|
||||
|
@ -43,5 +56,28 @@ void main() {
|
|||
// gl_FragColor.a *=(1.0- step(v_dash_array.x, mod(v_distance_ratio, dashLength)));
|
||||
}
|
||||
|
||||
if(u_line_texture == LineTexture) { // while load texture
|
||||
float u = fract(mod(v_distance, v_pixelLen)/v_pixelLen - animateSpeed);
|
||||
float v = length(v_offset)/(v_a*2.0);
|
||||
v = max(smoothstep(0.95, 1.0, v), v);
|
||||
vec2 uv= v_iconMapUV / u_textSize + vec2(u, v) / u_textSize * 64.;
|
||||
// gl_FragColor = filterColor(gl_FragColor + texture2D(u_texture, vec2(u, v)));
|
||||
gl_FragColor = filterColor(gl_FragColor + texture2D(u_texture, uv));
|
||||
} else {
|
||||
gl_FragColor = filterColor(gl_FragColor);
|
||||
}
|
||||
// gl_FragColor = filterColor(vec4(1.0, 0.0, 0.0, 1.0));
|
||||
|
||||
// float r = max(smoothstep( 0.95, 1.0, v_strokeWidth/(v_a*2.0)), v_strokeWidth/(v_a*2.0));
|
||||
// if(rV < r || rV > 1.0 - r) {
|
||||
// gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
// }
|
||||
// float v = length(v_offset)/(v_a*2.0);
|
||||
// if(v > 0.9) {
|
||||
// gl_FragColor = vec4(0.17647, 0.43921568, 0.2, 1.0);
|
||||
// } else if(v < 0.1) {
|
||||
// gl_FragColor = vec4(0.17647, 0.43921568, 0.2, 1.0);
|
||||
// }
|
||||
|
||||
// gl_FragColor = filterColor(gl_FragColor);
|
||||
}
|
||||
|
|
|
@ -8,14 +8,18 @@ attribute vec2 a_Size;
|
|||
attribute vec3 a_Normal;
|
||||
attribute vec3 a_Position;
|
||||
|
||||
attribute vec2 a_iconMapUV;
|
||||
|
||||
// dash line
|
||||
attribute float a_Total_Distance;
|
||||
attribute float a_Distance;
|
||||
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
uniform float u_line_type: 0.0;
|
||||
uniform vec4 u_dash_array: [10.0, 5.,0, 0];
|
||||
uniform vec4 u_dash_array: [10.0, 5., 0, 0];
|
||||
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
|
||||
uniform float u_icon_step: 100;
|
||||
|
||||
#pragma include "projection"
|
||||
#pragma include "picking"
|
||||
|
@ -26,23 +30,52 @@ varying vec2 v_normal;
|
|||
varying float v_distance_ratio;
|
||||
varying float v_side;
|
||||
|
||||
varying float v_distance;
|
||||
varying vec2 v_offset;
|
||||
varying float v_size;
|
||||
varying float v_a;
|
||||
varying float v_pixelLen;
|
||||
varying vec2 v_iconMapUV;
|
||||
// varying float v_strokeWidth;
|
||||
|
||||
void main() {
|
||||
|
||||
v_iconMapUV = a_iconMapUV;
|
||||
v_distance = a_Distance;
|
||||
v_pixelLen = project_pixel(u_icon_step);
|
||||
|
||||
if(u_line_type == LineTypeDash) {
|
||||
v_distance_ratio = a_Distance / a_Total_Distance;
|
||||
// v_distance_ratio = 0.01;
|
||||
v_dash_array = pow(2.0, 20.0 - u_Zoom) * u_dash_array / a_Total_Distance;
|
||||
}
|
||||
if(u_aimate.x == Animate) {
|
||||
v_distance_ratio = a_Distance / a_Total_Distance;
|
||||
}
|
||||
v_normal = vec2(reverse_offset_normal(a_Normal) * sign(a_Miter));
|
||||
|
||||
|
||||
v_color = a_Color;
|
||||
v_a = project_pixel(a_Size.x);
|
||||
|
||||
vec3 size = a_Miter * setPickingSize(a_Size.x) * reverse_offset_normal(a_Normal);
|
||||
|
||||
vec2 offset = project_pixel(size.xy);
|
||||
// v_strokeWidth = project_pixel(2.0);
|
||||
|
||||
v_offset = offset + offset * sign(a_Miter);
|
||||
|
||||
v_side = a_Miter * a_Size.x;
|
||||
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, a_Size.y, 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
// gl_Position = u_Mvp * (vec4(project_pos.xy + offset, a_Size.y, 1.0));
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xy + offset, a_Size.y / 10.0, 1.0)); // 额外除 10.0 是为了和gaode1.x的高度兼容
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, a_Size.y, 1.0));
|
||||
}
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
import {
|
||||
IEncodeFeature,
|
||||
IFontService,
|
||||
IGlobalConfigService,
|
||||
ILayer,
|
||||
ILayerPlugin,
|
||||
ILngLat,
|
||||
ILogService,
|
||||
IMapService,
|
||||
IParseDataItem,
|
||||
IStyleAttribute,
|
||||
IStyleAttributeService,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import { rgb2arr } from '@antv/l7-utils';
|
||||
import { rgb2arr, unProjectFlat } from '@antv/l7-utils';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
@injectable()
|
||||
export default class DataMappingPlugin implements ILayerPlugin {
|
||||
|
@ -20,6 +24,12 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
@inject(TYPES.ILogService)
|
||||
private readonly logger: ILogService;
|
||||
|
||||
@inject(TYPES.IMapService)
|
||||
private readonly mapService: IMapService;
|
||||
|
||||
@inject(TYPES.IFontService)
|
||||
private readonly fontService: IFontService;
|
||||
|
||||
public apply(
|
||||
layer: ILayer,
|
||||
{
|
||||
|
@ -99,13 +109,15 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
data: IParseDataItem[],
|
||||
predata?: IEncodeFeature[],
|
||||
): IEncodeFeature[] {
|
||||
return data.map((record: IParseDataItem, i) => {
|
||||
// console.log('data', data[0])
|
||||
const mappedData = data.map((record: IParseDataItem, i) => {
|
||||
const preRecord = predata ? predata[i] : {};
|
||||
const encodeRecord: IEncodeFeature = {
|
||||
id: record._id,
|
||||
coordinates: record.coordinates,
|
||||
...preRecord,
|
||||
};
|
||||
|
||||
attributes
|
||||
.filter((attribute) => attribute.scale !== undefined)
|
||||
.forEach((attribute: IStyleAttribute) => {
|
||||
|
@ -121,9 +133,44 @@ export default class DataMappingPlugin implements ILayerPlugin {
|
|||
// @ts-ignore
|
||||
encodeRecord[attribute.name] =
|
||||
Array.isArray(values) && values.length === 1 ? values[0] : values;
|
||||
|
||||
// 增加对 layer/text/iconfont unicode 映射的解析
|
||||
if (attribute.name === 'shape') {
|
||||
encodeRecord.shape = this.fontService.getIconFontKey(
|
||||
encodeRecord[attribute.name] as string,
|
||||
);
|
||||
}
|
||||
});
|
||||
return encodeRecord;
|
||||
}) as IEncodeFeature[];
|
||||
// console.log('mappedData', mappedData[0])
|
||||
|
||||
// 根据地图的类型判断是否需要对点位数据进行处理, 若是高德2.0则需要对坐标进行相对偏移
|
||||
if (mappedData.length > 0 && this.mapService.version === 'GAODE2.x') {
|
||||
if (typeof mappedData[0].coordinates[0] === 'number') {
|
||||
// 单个的点数据
|
||||
// @ts-ignore
|
||||
mappedData.map((d) => {
|
||||
d.version = 'GAODE2.x';
|
||||
// @ts-ignore
|
||||
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
|
||||
// @ts-ignore
|
||||
d.coordinates = this.mapService.lngLatToCoord(d.coordinates);
|
||||
// d.coordinates = this.mapService.lngLatToCoord(unProjectFlat(d.coordinates));
|
||||
});
|
||||
} else {
|
||||
// 连续的线、面数据
|
||||
// @ts-ignore
|
||||
mappedData.map((d) => {
|
||||
d.version = 'GAODE2.x';
|
||||
// @ts-ignore
|
||||
d.originCoordinates = cloneDeep(d.coordinates); // 为了兼容高德1.x 需要保存一份原始的经纬度坐标数据(许多上层逻辑依赖经纬度数据)
|
||||
// @ts-ignore
|
||||
d.coordinates = this.mapService.lngLatToCoords(d.coordinates);
|
||||
});
|
||||
}
|
||||
}
|
||||
return mappedData;
|
||||
}
|
||||
|
||||
private applyAttributeMapping(
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
import { ILayer, ILayerPlugin, IMapService, TYPES } from '@antv/l7-core';
|
||||
import {
|
||||
ILayer,
|
||||
ILayerPlugin,
|
||||
ILngLat,
|
||||
IMapService,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
import Source from '@antv/l7-source';
|
||||
import { injectable } from 'inversify';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
@injectable()
|
||||
export default class DataSourcePlugin implements ILayerPlugin {
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
ICoordinateSystemService,
|
||||
ILayer,
|
||||
ILayerPlugin,
|
||||
IMapService,
|
||||
IRendererService,
|
||||
TYPES,
|
||||
} from '@antv/l7-core';
|
||||
|
@ -29,13 +30,28 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
|
|||
@inject(TYPES.IRendererService)
|
||||
private readonly rendererService: IRendererService;
|
||||
|
||||
@inject(TYPES.IMapService)
|
||||
private readonly mapService: IMapService;
|
||||
|
||||
public apply(layer: ILayer) {
|
||||
const version = this.mapService.version;
|
||||
|
||||
let mvp = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]; // default matrix (for gaode2.x)
|
||||
let sceneCenterMKT = [0, 0];
|
||||
layer.hooks.beforeRender.tap('ShaderUniformPlugin', () => {
|
||||
// 重新计算坐标系参数
|
||||
this.coordinateSystemService.refresh();
|
||||
|
||||
if (version === 'GAODE2.x') {
|
||||
// @ts-ignore
|
||||
mvp = this.mapService.map.customCoords.getMVPMatrix();
|
||||
// mvp = amapCustomCoords.getMVPMatrix()
|
||||
// @ts-ignore
|
||||
sceneCenterMKT = this.mapService.getCustomCoordCenter();
|
||||
}
|
||||
|
||||
const { width, height } = this.rendererService.getViewportSize();
|
||||
layer.models.forEach((model) =>
|
||||
layer.models.forEach((model) => {
|
||||
model.addUniforms({
|
||||
// 相机参数,包含 VP 矩阵、缩放等级
|
||||
[CameraUniform.ProjectionMatrix]: this.cameraService.getProjectionMatrix(),
|
||||
|
@ -52,13 +68,16 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
|
|||
[CoordinateUniform.PixelsPerDegree]: this.coordinateSystemService.getPixelsPerDegree(),
|
||||
[CoordinateUniform.PixelsPerDegree2]: this.coordinateSystemService.getPixelsPerDegree2(),
|
||||
[CoordinateUniform.PixelsPerMeter]: this.coordinateSystemService.getPixelsPerMeter(),
|
||||
// 坐标系是高德2.0的时候单独计算
|
||||
[CoordinateUniform.Mvp]: mvp,
|
||||
u_SceneCenterMKT: sceneCenterMKT,
|
||||
// 其他参数,例如视口大小、DPR 等
|
||||
u_ViewportSize: [width, height],
|
||||
u_DevicePixelRatio: window.devicePixelRatio,
|
||||
u_ModelMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
||||
u_PickingBuffer: layer.getLayerConfig().pickingBuffer || 0,
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// TODO:脏检查,决定是否需要渲染
|
||||
});
|
||||
|
|
|
@ -11,7 +11,6 @@ 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() {
|
||||
|
|
|
@ -108,7 +108,6 @@ export default class ImageModel extends BaseModel {
|
|||
attributeIdx: number,
|
||||
) => {
|
||||
const iconMap = this.iconService.getIconMap();
|
||||
|
||||
const { shape } = feature;
|
||||
const { x, y } = iconMap[shape as string] || { x: 0, y: 0 };
|
||||
return [x, y];
|
||||
|
|
|
@ -292,7 +292,7 @@ export default class TextModel extends BaseModel {
|
|||
return padBounds(bounds, 0.5);
|
||||
}
|
||||
/**
|
||||
* 生成文字纹理
|
||||
* 生成文字纹理(生成文字纹理字典)
|
||||
*/
|
||||
private initTextFont() {
|
||||
const {
|
||||
|
@ -315,12 +315,39 @@ export default class TextModel extends BaseModel {
|
|||
characterSet,
|
||||
fontWeight,
|
||||
fontFamily,
|
||||
iconfont: false,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文字布局
|
||||
* 生成 iconfont 纹理字典
|
||||
*/
|
||||
private generateGlyphLayout() {
|
||||
private initIconFontTex() {
|
||||
const {
|
||||
fontWeight = '400',
|
||||
fontFamily = 'sans-serif',
|
||||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
const data = this.layer.getEncodedData();
|
||||
const characterSet: string[] = [];
|
||||
data.forEach((item: IEncodeFeature) => {
|
||||
let { shape = '' } = item;
|
||||
shape = shape.toString();
|
||||
if (characterSet.indexOf(shape) === -1) {
|
||||
characterSet.push(shape);
|
||||
}
|
||||
});
|
||||
this.fontService.setFontOptions({
|
||||
characterSet,
|
||||
fontWeight,
|
||||
fontFamily,
|
||||
iconfont: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成文字布局(对照文字纹理字典提取对应文字的位置很好信息)
|
||||
*/
|
||||
private generateGlyphLayout(iconfont: boolean) {
|
||||
// TODO:更新文字布局
|
||||
const { mapping } = this.fontService;
|
||||
const {
|
||||
|
@ -330,7 +357,7 @@ export default class TextModel extends BaseModel {
|
|||
} = this.layer.getLayerConfig() as IPointTextLayerStyleOptions;
|
||||
const data = this.layer.getEncodedData();
|
||||
this.glyphInfo = data.map((feature: IEncodeFeature) => {
|
||||
const { shape = '', coordinates, id, size = 1 } = feature;
|
||||
const { shape = '', id, size = 1 } = feature;
|
||||
|
||||
const shaping = shapeText(
|
||||
shape.toString(),
|
||||
|
@ -341,21 +368,31 @@ export default class TextModel extends BaseModel {
|
|||
'center',
|
||||
spacing,
|
||||
textOffset,
|
||||
iconfont,
|
||||
);
|
||||
const glyphQuads = getGlyphQuads(shaping, textOffset, false);
|
||||
feature.shaping = shaping;
|
||||
feature.glyphQuads = glyphQuads;
|
||||
feature.centroid = calculteCentroid(coordinates);
|
||||
// feature.centroid = calculteCentroid(coordinates);
|
||||
|
||||
feature.centroid = calculteCentroid(feature.coordinates);
|
||||
|
||||
// 此时地图高德2.0 originCentroid == centroid
|
||||
feature.originCentroid =
|
||||
feature.version === 'GAODE2.x'
|
||||
? calculteCentroid(feature.originCoordinates)
|
||||
: (feature.originCentroid = feature.centroid);
|
||||
|
||||
this.glyphInfoMap[id as number] = {
|
||||
shaping,
|
||||
glyphQuads,
|
||||
centroid: calculteCentroid(coordinates),
|
||||
centroid: calculteCentroid(feature.coordinates),
|
||||
};
|
||||
return feature;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 文字避让
|
||||
* 文字避让 depend on originCentorid
|
||||
*/
|
||||
private filterGlyphs() {
|
||||
const {
|
||||
|
@ -374,7 +411,11 @@ export default class TextModel extends BaseModel {
|
|||
const collisionIndex = new CollisionIndex(width, height);
|
||||
const filterData = this.glyphInfo.filter((feature: IEncodeFeature) => {
|
||||
const { shaping, id = 0 } = feature;
|
||||
const centroid = feature.centroid as [number, number];
|
||||
// const centroid = feature.centroid as [number, number];
|
||||
// const centroid = feature.originCentroid as [number, number];
|
||||
const centroid = (feature.version === 'GAODE2.x'
|
||||
? feature.originCentroid
|
||||
: feature.centroid) as [number, number];
|
||||
const size = feature.size as number;
|
||||
const fontScale: number = size / 24;
|
||||
const pixels = this.mapService.lngLatToContainer(centroid);
|
||||
|
@ -404,10 +445,13 @@ export default class TextModel extends BaseModel {
|
|||
* 初始化文字布局
|
||||
*/
|
||||
private initGlyph() {
|
||||
// 1.生成文字纹理
|
||||
this.initTextFont();
|
||||
const { iconfont = false } = this.layer.getLayerConfig();
|
||||
// 1.生成文字纹理(或是生成 iconfont)
|
||||
iconfont ? this.initIconFontTex() : this.initTextFont();
|
||||
// this.initTextFont();
|
||||
|
||||
// 2.生成文字布局
|
||||
this.generateGlyphLayout();
|
||||
this.generateGlyphLayout(iconfont);
|
||||
}
|
||||
/**
|
||||
* 更新文字纹理
|
||||
|
|
|
@ -11,6 +11,7 @@ attribute vec3 a_Size;
|
|||
attribute vec3 a_Normal;
|
||||
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
uniform vec2 u_offsets;
|
||||
varying vec4 v_color;
|
||||
|
||||
|
@ -30,6 +31,12 @@ void main() {
|
|||
float lightWeight = calc_lighting(pos);
|
||||
v_color =vec4(a_Color.rgb * lightWeight, a_Color.w);
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(pos);
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * pos;
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(pos);
|
||||
}
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ attribute vec2 a_Extrude;
|
|||
attribute float a_Size;
|
||||
attribute float a_Shape;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
|
||||
uniform float u_stroke_width : 2;
|
||||
uniform vec2 u_offsets;
|
||||
|
@ -16,24 +17,16 @@ varying float v_radius;
|
|||
#pragma include "picking"
|
||||
|
||||
void main() {
|
||||
vec2 extrude = a_Extrude;
|
||||
float shape_type = a_Shape;
|
||||
float newSize = setPickingSize(a_Size);
|
||||
|
||||
// unpack color(vec2)
|
||||
v_color = a_Color;
|
||||
vec2 extrude = a_Extrude;
|
||||
|
||||
float shape_type = a_Shape;
|
||||
|
||||
float newSize = setPickingSize(a_Size);
|
||||
|
||||
// radius(16-bit)
|
||||
v_radius = newSize;
|
||||
|
||||
vec2 offset = project_pixel(extrude * (newSize + u_stroke_width) + u_offsets);
|
||||
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO: billboard
|
||||
// anti-alias
|
||||
float antialiasblur = 1.0 / u_DevicePixelRatio / (newSize + u_stroke_width);
|
||||
|
@ -41,8 +34,17 @@ void main() {
|
|||
// construct point coords
|
||||
v_data = vec4(extrude, antialiasblur,shape_type);
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
|
||||
vec2 offset = project_pixel(extrude * (newSize + u_stroke_width) + u_offsets);
|
||||
vec4 project_pos = project_position(vec4(a_Position.xy, 0.0, 1.0));
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, project_pixel(setPickingOrder(0.0)), 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * vec4(project_pos.xy + offset, 0.0, 1.0);
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, project_pixel(setPickingOrder(0.0)), 1.0));
|
||||
}
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy + offset, 0.0, 1.0));
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ attribute float a_Size;
|
|||
varying vec4 v_color;
|
||||
varying vec2 v_uv;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
uniform float u_stroke_width : 1;
|
||||
uniform vec2 u_offsets;
|
||||
varying float v_size;
|
||||
|
@ -19,7 +20,14 @@ void main() {
|
|||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
v_size = a_Size;
|
||||
vec2 offset = project_pixel(u_offsets);
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy + offset),project_pos.z, 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * vec4(vec2(project_pos.xy + offset),project_pos.z, 1.0);
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy + offset),project_pos.z, 1.0));
|
||||
}
|
||||
gl_PointSize = a_Size * 2.0 * u_DevicePixelRatio;
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
attribute vec3 a_Position;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
attribute float a_Size;
|
||||
attribute vec4 a_Color;
|
||||
varying vec4 v_color;
|
||||
|
@ -11,9 +12,18 @@ uniform vec2 u_offsets;
|
|||
#pragma include "picking"
|
||||
void main() {
|
||||
v_color = a_Color;
|
||||
// vec2 offset = project_pixel(u_offsets);
|
||||
// vec4 project_pos = project_position(vec4(a_Position, 1.0)) + vec4(a_Size / 2.,-a_Size /2.,0.,0.);
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy+offset),project_pos.z,project_pos.w));\
|
||||
//
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * vec4(a_Position, 1.0);
|
||||
} else { // else
|
||||
vec2 offset = project_pixel(u_offsets);
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0)) + vec4(a_Size / 2.,-a_Size /2.,0.,0.);
|
||||
gl_Position = project_common_position_to_clipspace(vec4(vec2(project_pos.xy+offset),project_pos.z,project_pos.w));
|
||||
}
|
||||
|
||||
gl_PointSize = a_Size * 2.0 * u_DevicePixelRatio;
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ attribute float a_Rotate;
|
|||
|
||||
uniform vec2 u_sdf_map_size;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
|
||||
varying vec2 v_uv;
|
||||
varying float v_gamma_scale;
|
||||
|
@ -26,14 +27,24 @@ void main() {
|
|||
// 文本缩放比例
|
||||
float fontScale = a_Size / FONT_SIZE;
|
||||
v_fontScale = fontScale;
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
|
||||
vec4 projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
// vec4 projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
|
||||
highp float angle_sin = sin(a_Rotate);
|
||||
highp float angle_cos = cos(a_Rotate);
|
||||
mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos);
|
||||
gl_Position = vec4(projected_position.xy / projected_position.w
|
||||
+ rotation_matrix * a_textOffsets * fontScale / u_ViewportSize * 2.0 * u_DevicePixelRatio, 0.0, 1.0);
|
||||
|
||||
// gl_Position = vec4(projected_position.xy / projected_position.w + rotation_matrix * a_textOffsets * fontScale / u_ViewportSize * 2.0 * u_DevicePixelRatio, 0.0, 1.0);
|
||||
|
||||
vec4 projected_position;
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
projected_position = u_Mvp * (vec4(a_Position.xyz, 1.0));
|
||||
} else { // else
|
||||
projected_position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
}
|
||||
|
||||
gl_Position = vec4(projected_position.xy / projected_position.w + rotation_matrix * a_textOffsets * fontScale / u_ViewportSize * 2.0 * u_DevicePixelRatio, 0.0, 1.0);
|
||||
v_gamma_scale = gl_Position.w;
|
||||
setPickingColor(a_PickingColor);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ attribute vec3 a_Position;
|
|||
attribute vec3 a_Normal;
|
||||
attribute float a_Size;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
|
||||
varying vec4 v_Color;
|
||||
|
||||
|
@ -20,7 +21,14 @@ void main() {
|
|||
vec4 pos = vec4(a_Position.xy, a_Position.z * a_Size, 1.0);
|
||||
vec4 project_pos = project_position(pos);
|
||||
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
// gl_Position = u_Mvp * (vec4(project_pos.xyz * vec3(1.0, 1.0, -1.0), 1.0));
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xyz, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
}
|
||||
|
||||
float lightWeight = calc_lighting(pos);
|
||||
// v_Color = a_Color;
|
||||
|
|
|
@ -3,6 +3,7 @@ attribute vec3 a_Position;
|
|||
attribute vec3 a_Normal;
|
||||
attribute float a_Size;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
|
||||
varying vec4 v_Color;
|
||||
|
||||
|
@ -12,7 +13,13 @@ varying vec4 v_Color;
|
|||
void main() {
|
||||
v_Color = a_Color;
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xyz, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xyz, 1.0));
|
||||
}
|
||||
|
||||
setPickingColor(a_PickingColor);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ interface IRasterLayerStyleOptions {
|
|||
|
||||
export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
||||
public type: string = 'RasterLayer';
|
||||
protected texture: ITexture2D;
|
||||
protected rasterTexture: ITexture2D;
|
||||
protected colorTexture: ITexture2D;
|
||||
|
||||
public getAnimateUniforms(): IModelUniform {
|
||||
|
@ -39,7 +39,7 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
public buildModels() {
|
||||
const parserDataItem = this.getSource().data.dataArray[0];
|
||||
const { createTexture2D } = this.rendererService;
|
||||
this.texture = createTexture2D({
|
||||
this.rasterTexture = createTexture2D({
|
||||
data: parserDataItem.data,
|
||||
width: parserDataItem.width,
|
||||
height: parserDataItem.height,
|
||||
|
@ -65,7 +65,7 @@ export default class RasterLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
model.draw({
|
||||
uniforms: {
|
||||
u_opacity: opacity || 1,
|
||||
u_texture: this.texture,
|
||||
u_texture: this.rasterTexture,
|
||||
u_min: min,
|
||||
u_width: width,
|
||||
u_height: height,
|
||||
|
|
|
@ -13,7 +13,7 @@ interface IRasterLayerStyleOptions {
|
|||
|
||||
export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
||||
public type: string = 'RasterLayer';
|
||||
protected texture: ITexture2D;
|
||||
protected rasterTexture: ITexture2D;
|
||||
protected colorTexture: ITexture2D;
|
||||
|
||||
public buildModels() {
|
||||
|
@ -21,7 +21,7 @@ export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
const source = this.getSource();
|
||||
const { createTexture2D } = this.rendererService;
|
||||
const parserDataItem = this.getSource().data.dataArray[0];
|
||||
this.texture = createTexture2D({
|
||||
this.rasterTexture = createTexture2D({
|
||||
data: parserDataItem.data,
|
||||
width: parserDataItem.width,
|
||||
height: parserDataItem.height,
|
||||
|
@ -61,12 +61,12 @@ export default class Raster2dLayer extends BaseLayer<IRasterLayerStyleOptions> {
|
|||
const { opacity } = this.getLayerConfig();
|
||||
const parserDataItem = this.getSource().data.dataArray[0];
|
||||
const { min, max } = parserDataItem;
|
||||
if (this.texture) {
|
||||
if (this.rasterTexture) {
|
||||
this.models.forEach((model) =>
|
||||
model.draw({
|
||||
uniforms: {
|
||||
u_opacity: opacity || 1,
|
||||
u_texture: this.texture,
|
||||
u_texture: this.rasterTexture,
|
||||
u_min: min,
|
||||
u_max: max,
|
||||
u_colorTexture: this.colorTexture,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
precision highp float;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
attribute vec3 a_Position;
|
||||
attribute vec2 a_Uv;
|
||||
varying vec2 v_texCoord;
|
||||
|
@ -8,4 +9,10 @@ void main() {
|
|||
v_texCoord = a_Uv;
|
||||
vec4 project_pos = project_position(vec4(a_Position, 1.0));
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy,0., 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(project_pos.xy,0., 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(project_pos.xy,0., 1.0));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
precision highp float;
|
||||
attribute vec3 a_Position;
|
||||
uniform mat4 u_ModelMatrix;
|
||||
uniform mat4 u_Mvp;
|
||||
uniform vec4 u_extent;
|
||||
uniform sampler2D u_texture;
|
||||
uniform sampler2D u_colorTexture;
|
||||
|
@ -32,6 +33,12 @@ void main() {
|
|||
|
||||
// vec2 range = u_extent.zw - u_extent.xy;
|
||||
// vec4 project_pos = project_position(vec4(pos, 0, 1.0));
|
||||
// gl_Position = project_common_position_to_clipspace(vec4(pos.xy, project_scale(value) * u_heightRatio, 1.0));
|
||||
|
||||
if(u_CoordinateSystem == COORDINATE_SYSTEM_P20_2) { // gaode2.x
|
||||
gl_Position = u_Mvp * (vec4(pos.xy, project_scale(value) * u_heightRatio, 1.0));
|
||||
} else {
|
||||
gl_Position = project_common_position_to_clipspace(vec4(pos.xy, project_scale(value) * u_heightRatio, 1.0));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -87,6 +87,51 @@ export default class ExtrudePolyline {
|
|||
startIndex: 0,
|
||||
};
|
||||
}
|
||||
|
||||
public extrude_gaode2(points: number[][], originPoints: number[][]) {
|
||||
const complex = this.complex;
|
||||
if (points.length <= 1) {
|
||||
return complex;
|
||||
}
|
||||
this.lastFlip = -1;
|
||||
this.started = false;
|
||||
this.normal = null;
|
||||
this.totalDistance = 0;
|
||||
// 去除数组里重复的点
|
||||
// points = getArrayUnique(points);
|
||||
const total = points.length;
|
||||
let count = complex.startIndex;
|
||||
for (let i = 1; i < total; i++) {
|
||||
const last = points[i - 1] as vec2;
|
||||
const originLast = originPoints[i - 1] as vec2;
|
||||
|
||||
const cur = points[i] as vec2;
|
||||
const originCur = originPoints[i] as vec2;
|
||||
|
||||
const next = i < points.length - 1 ? points[i + 1] : null;
|
||||
const originNext =
|
||||
i < originPoints.length - 1 ? originPoints[i + 1] : null;
|
||||
|
||||
const amt = this.segment_gaode2(
|
||||
complex,
|
||||
count,
|
||||
last,
|
||||
cur,
|
||||
next as vec2,
|
||||
originLast,
|
||||
originCur,
|
||||
originNext as vec2,
|
||||
);
|
||||
count += amt;
|
||||
}
|
||||
if (this.dash) {
|
||||
for (let i = 0; i < complex.positions.length / 6; i++) {
|
||||
complex.positions[i * 6 + 5] = this.totalDistance;
|
||||
}
|
||||
}
|
||||
complex.startIndex = complex.positions.length / 6;
|
||||
return complex;
|
||||
}
|
||||
public extrude(points: number[][]) {
|
||||
const complex = this.complex;
|
||||
if (points.length <= 1) {
|
||||
|
@ -115,6 +160,222 @@ export default class ExtrudePolyline {
|
|||
complex.startIndex = complex.positions.length / 6;
|
||||
return complex;
|
||||
}
|
||||
private segment_gaode2(
|
||||
complex: any,
|
||||
index: number,
|
||||
last: vec2,
|
||||
cur: vec2,
|
||||
next: vec2,
|
||||
originLast: vec2,
|
||||
originCur: vec2,
|
||||
originNext: 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([originCur[0], originCur[1]]) as [
|
||||
number,
|
||||
number,
|
||||
];
|
||||
const flatLast = aProjectFlat([originLast[0], originLast[1]]) as [
|
||||
number,
|
||||
number,
|
||||
];
|
||||
direction(lineA, cur, last);
|
||||
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,
|
||||
);
|
||||
} 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) {
|
||||
const out1 = vec2.create();
|
||||
const out2 = vec2.create();
|
||||
vec2.sub(out2, lineA, this.normal);
|
||||
vec2.add(out1, lineA, this.normal);
|
||||
|
||||
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,
|
||||
);
|
||||
}
|
||||
indices.push(
|
||||
...(this.lastFlip === 1
|
||||
? [index, index + 2, index + 3]
|
||||
: [index + 2, index + 1, index + 3]),
|
||||
);
|
||||
count += 2;
|
||||
} else {
|
||||
if (isPointEqual(cur, next)) {
|
||||
vec2.add(
|
||||
next,
|
||||
cur,
|
||||
vec2.normalize(next, vec2.subtract(next, cur, last)),
|
||||
);
|
||||
}
|
||||
direction(lineB, next, cur);
|
||||
// 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 segment(
|
||||
complex: any,
|
||||
index: number,
|
||||
|
@ -329,7 +590,6 @@ export default class ExtrudePolyline {
|
|||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private extrusions(
|
||||
positions: number[],
|
||||
normals: number[],
|
||||
|
|
|
@ -197,6 +197,81 @@ function shapeLines(
|
|||
shaping.right = shaping.left + maxLineLength;
|
||||
}
|
||||
|
||||
function shapeIconFont(
|
||||
shaping: any,
|
||||
glyphMap: any,
|
||||
iconfonts: any[],
|
||||
lineHeight: number,
|
||||
textAnchor: anchorType,
|
||||
textJustify: string,
|
||||
spacing: number,
|
||||
) {
|
||||
// buffer 为 4
|
||||
const yOffset = -8;
|
||||
|
||||
let x = 0;
|
||||
let y = yOffset;
|
||||
|
||||
let maxLineLength = 0;
|
||||
const positionedGlyphs = shaping.positionedGlyphs;
|
||||
|
||||
const justify =
|
||||
textJustify === 'right' ? 1 : textJustify === 'left' ? 0 : 0.5;
|
||||
|
||||
const lineStartIndex = positionedGlyphs.length;
|
||||
iconfonts.forEach((iconfont) => {
|
||||
const glyph = glyphMap[iconfont];
|
||||
const baselineOffset = 0;
|
||||
|
||||
if (glyph) {
|
||||
positionedGlyphs.push({
|
||||
glyph: iconfont,
|
||||
x,
|
||||
y: y + baselineOffset,
|
||||
vertical: false, // TODO:目前只支持水平方向
|
||||
scale: 1,
|
||||
metrics: glyph,
|
||||
});
|
||||
x += glyph.advance + spacing;
|
||||
}
|
||||
|
||||
// 左右对齐
|
||||
if (positionedGlyphs.length !== lineStartIndex) {
|
||||
const lineLength = x - spacing;
|
||||
maxLineLength = Math.max(lineLength, maxLineLength);
|
||||
justifyLine(
|
||||
positionedGlyphs,
|
||||
glyphMap,
|
||||
lineStartIndex,
|
||||
positionedGlyphs.length - 1,
|
||||
justify,
|
||||
);
|
||||
}
|
||||
|
||||
x = 0;
|
||||
y += lineHeight;
|
||||
});
|
||||
|
||||
const { horizontalAlign, verticalAlign } = getAnchorAlignment(textAnchor);
|
||||
align(
|
||||
positionedGlyphs,
|
||||
justify,
|
||||
horizontalAlign,
|
||||
verticalAlign,
|
||||
maxLineLength,
|
||||
lineHeight,
|
||||
iconfonts.length,
|
||||
);
|
||||
|
||||
// 计算包围盒
|
||||
const height = y - yOffset;
|
||||
|
||||
shaping.top += -verticalAlign * height;
|
||||
shaping.bottom = shaping.top + height;
|
||||
shaping.left += -horizontalAlign * maxLineLength;
|
||||
shaping.right = shaping.left + maxLineLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算文本中每个独立字符相对锚点的位置
|
||||
*
|
||||
|
@ -207,6 +282,7 @@ function shapeLines(
|
|||
* @param {string} textJustify 左右对齐
|
||||
* @param {number} spacing 字符间距
|
||||
* @param {[number, number]} translate 文本水平 & 垂直偏移量
|
||||
* @param {[boolean]} isIconFont 是否是 iconfont
|
||||
* @return {boolean|shaping} 每个字符相对于锚点的位置
|
||||
*/
|
||||
export function shapeText(
|
||||
|
@ -217,6 +293,7 @@ export function shapeText(
|
|||
textJustify: string,
|
||||
spacing: number,
|
||||
translate: [number, number] = [0, 0],
|
||||
isIconFont: boolean,
|
||||
) {
|
||||
// TODO:处理换行
|
||||
const lines = text.split('\n');
|
||||
|
@ -231,8 +308,17 @@ export function shapeText(
|
|||
lineCount: lines.length,
|
||||
text,
|
||||
};
|
||||
|
||||
shapeLines(
|
||||
isIconFont
|
||||
? shapeIconFont(
|
||||
shaping,
|
||||
glyphs,
|
||||
lines,
|
||||
lineHeight,
|
||||
textAnchor,
|
||||
textJustify,
|
||||
spacing,
|
||||
)
|
||||
: shapeLines(
|
||||
shaping,
|
||||
glyphs,
|
||||
lines,
|
||||
|
|
|
@ -33,7 +33,6 @@ export default class Viewport implements IViewport {
|
|||
|
||||
// 计算透视投影矩阵 projectionMatrix
|
||||
mat4.perspective(this.projectionMatrix, fov, aspect, near, far);
|
||||
|
||||
// 计算相机矩阵 viewMatrix
|
||||
const eye = vec3.fromValues(
|
||||
cameraHeight * Math.sin(pitchInRadians) * Math.sin(rotationInRadians),
|
||||
|
@ -46,7 +45,6 @@ export default class Viewport implements IViewport {
|
|||
Math.sin(pitchInRadians),
|
||||
);
|
||||
mat4.lookAt(this.viewMatrix, eye, vec3.fromValues(0, 0, 0), up);
|
||||
|
||||
this.viewUncenteredMatrix = mat4.clone(this.viewMatrix);
|
||||
|
||||
// 移动相机位置
|
||||
|
|
|
@ -25,6 +25,7 @@ import { mat4, vec2, vec3 } from 'gl-matrix';
|
|||
import { inject, injectable } from 'inversify';
|
||||
import { IAMapEvent, IAMapInstance } from '../../typings/index';
|
||||
import { toPaddingOptions } from '../utils';
|
||||
import { Version } from '../version';
|
||||
import './logo.css';
|
||||
import { MapTheme } from './theme';
|
||||
import Viewport from './Viewport';
|
||||
|
@ -54,6 +55,7 @@ const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12; // 暂时关闭 fix 统一不同坐标
|
|||
@injectable()
|
||||
export default class AMapService
|
||||
implements IMapService<AMap.Map & IAMapInstance> {
|
||||
public version: string = Version['GAODE1.x'];
|
||||
/**
|
||||
* 原始地图实例
|
||||
*/
|
||||
|
@ -328,7 +330,7 @@ export default class AMapService
|
|||
} = this.config;
|
||||
// 高德地图创建独立的container;
|
||||
// tslint:disable-next-line:typedef
|
||||
await new Promise((resolve) => {
|
||||
await new Promise<void>((resolve) => {
|
||||
const resolveMap = () => {
|
||||
if (mapInstance) {
|
||||
this.map = mapInstance as AMap.Map & IAMapInstance;
|
||||
|
@ -442,6 +444,10 @@ export default class AMapService
|
|||
const { lng, lat } = this.getCenter();
|
||||
if (this.cameraChangedCallback) {
|
||||
// resync viewport
|
||||
// console.log('cameraHeight', height)
|
||||
// console.log('pitch', pitch)
|
||||
// console.log('rotation', rotation)
|
||||
// console.log('zoom', this.map.getZoom())
|
||||
this.viewport.syncWithMapCamera({
|
||||
aspect,
|
||||
// AMap 定义 rotation 为顺时针方向,而 Mapbox 为逆时针
|
||||
|
@ -458,7 +464,7 @@ export default class AMapService
|
|||
offsetOrigin: [position.x, position.y],
|
||||
});
|
||||
const { offsetZoom = LNGLAT_OFFSET_ZOOM_THRESHOLD } = this.config;
|
||||
|
||||
// console.log('this.viewport', this.viewport)
|
||||
// set coordinate system
|
||||
if (this.viewport.getZoom() > offsetZoom) {
|
||||
this.coordinateSystemService.setCoordinateSystem(
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue