This commit is contained in:
lzxue 2021-11-01 19:26:23 +08:00
commit b89cedca5b
110 changed files with 4500 additions and 301 deletions

22
beta.sh
View File

@ -1,11 +1,11 @@
npm dist-tag add @antv/l7-component@2.5.17 beta
npm dist-tag add @antv/l7-core@2.5.17 beta
npm dist-tag add @antv/l7@2.5.17 beta
npm dist-tag add @antv/l7-layers@2.5.17 beta
npm dist-tag add @antv/l7-map@2.5.17 beta
npm dist-tag add @antv/l7-maps@2.5.17 beta
npm dist-tag add @antv/l7-renderer@2.5.17 beta
npm dist-tag add @antv/l7-scene@2.5.17 beta
npm dist-tag add @antv/l7-source@2.5.17 beta
npm dist-tag add @antv/l7-three@2.5.17 beta
npm dist-tag add @antv/l7-utils@2.5.17 beta
npm dist-tag add @antv/l7-component@2.5.36 beta
npm dist-tag add @antv/l7-core@2.5.36 beta
npm dist-tag add @antv/l7@2.5.36 beta
npm dist-tag add @antv/l7-layers@2.5.36 beta
npm dist-tag add @antv/l7-map@2.5.36 beta
npm dist-tag add @antv/l7-maps@2.5.36 beta
npm dist-tag add @antv/l7-renderer@2.5.36 beta
npm dist-tag add @antv/l7-scene@2.5.36 beta
npm dist-tag add @antv/l7-source@2.5.36 beta
npm dist-tag add @antv/l7-three@2.5.36 beta
npm dist-tag add @antv/l7-utils@2.5.36 beta

View File

@ -36,13 +36,13 @@ DrillDownLayer 提供默认提供通过 Layer 的交互事件,实现上钻下
向下钻取的触发事件 ⛔customTrigger 为 true 时不生效
### drillDownEvent
### drillDownEvent
根据drillDownTriggerEvent类型下钻触发的回调事件 属性
根据 drillDownTriggerEvent 类型下钻触发的回调事件 属性
### drillUpEvent
根据drillUpTriggleEvent类型上钻触发的回调事件 属性
根据 drillUpTriggleEvent 类型上钻触发的回调事件 属性
### drillUpTriggleEvent

View File

@ -0,0 +1,6 @@
---
title: Earth Mode
order: 1
---
`markdown:docs/api/earth/earth.zh.md`

134
docs/api/earth/earth.zh.md Normal file
View File

@ -0,0 +1,134 @@
---
title: 地球模式
order: 1
---
`markdown:docs/common/style.md`
## 简介
L7Earth 相较于高德地图、mapbox 地图,是完全不同的一种表现形式,提供了全球视角下的可视化展示能力,为用户提供了更多的地理信息可视化表现形式。
✨ 为了区别普通的地图L7Earth 提供了全新的 Earth 地图类型以及对应的 EarthLayer 图层
## 使用
```javascript
// 1、引入对应模块
import { Earth } from '@antv/l7-maps';
import { EarthLayer } from '@antv/l7-layers';
...
// 2、构建 Earth Map
const scene = new Scene({
id: 'map',
map: new Earth({}),
});
...
// 3、构建地球图层当前的 shape 为 base表示基础球体
const earthlayer = new EarthLayer()
.source(
// 地球表面的纹理
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*3-3NSpqRqUoAAAAAAAAAAAAAARQnAQ',
{
parser: {
type: 'image',
extent: [121.168, 30.2828, 121.384, 30.421],
},
},
)
.color('#f00')
.shape('base')
.style({
opacity: 1.0,
radius: 40,
globelOtions: {
ambientRatio: 0.6, // 环境光
diffuseRatio: 0.4, // 漫反射
specularRatio: 0.1, // 高光反射
earthTime: 0.1,
},
})
.animate(true);
// 4、添加基础地球球体
scene.addLayer(earthlayer);
// 经过上述的步骤,我们就可以在场景中添加一个基础的地球了
```
## 独立的地图类型 Earth
### 构造函数 Earth(args)
作为 L7Earth 的基础地图类型Earth 提供了地球系统的相机系统,目前只需要传入一个空对象。
- args: {}
### rotateY(option: { force: boolean; regScale: number})
提供了简单的方法控制地球系统的旋转(实际上控制的是相机的旋转)
- force: false 判断是否强制生效,默认该方法的优先级比用户鼠标操作要低,当用户操作相机的时候,该方法会失效
- regScale: 0.01 旋转的角度(视觉上地球的旋转角度), regScale 表示的并不是实际的旋转角度,而是单位旋转角度的比例
🌟 单位旋转角度 = Math.min(this.earthCameraZoom \* this.earthCameraZoom, 1)
## 地图图层 EarthLayer
地球图层区别于普通高德地图和 Mapbox 地图的图层,只在地球模式下可以被使用,用于表示地球的球体、大气层、辉光等效果。
🌟 使用不同的 shape 参数表示区别不同的地球图层
### 地球球体图层 baseLayer
- source(map, parser)
map: 地球表面纹理贴图的地址
parser: 解析器,目前只需要写固定的对象值即可 { parser: { type: "image" } }
- shape: 'base'
🌟 目前支持的 shape 类型有 base、atomSphere、bloomSphere当用户的 shape 参数不被识别时,自动降级为 base 类型
- globelOtions: style 方法中的参数 ambientRatio: 环境光、diffuseRatio: 漫反射、specularRatio: 高光反射
```javascript
const earthlayer = new EarthLayer()
.source(
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*3-3NSpqRqUoAAAAAAAAAAAAAARQnAQ',
{
parser: {
type: 'image',
},
},
)
.shape('base')
.style({
globelOtions: {
ambientRatio: 0.6, // 环境光
diffuseRatio: 0.4, // 漫反射
specularRatio: 0.1, // 高光反射
},
});
```
### 地球内发光/大气图层 atomLayer
atomLayer 作为地球的效果图层,不需要传入数据,所以可以不调用 source 方法
```javascript
const atomLayer = new EarthLayer()
.color('#2E8AE6')
.shape('atomSphere')
.style({
// 可以控制发光程度
opacity: 1,
});
```
### 地球内外发光/辉光图层 bloomLayer
bloomLayer 作为地球的效果图层,不需要传入数据,所以可以不调用 source 方法
```javascript
const bloomLayer = new EarthLayer()
.color('#fff')
.shape('bloomSphere')
.style({
opacity: 0.5,
});
```

View File

@ -0,0 +1,6 @@
---
title: Earth Flyline
order: 3
---
`markdown:docs/api/earth/flyline.zh.md`

View File

@ -0,0 +1,41 @@
---
title: 飞线
order: 3
---
`markdown:docs/common/style.md`
## 简介
用户在地球模式下使用飞线图层无需做额外的操作L7 会自动识别地球模式并相关的转化
## 使用
```javascript
// 1、引入对应模块
const flyLine = new LineLayer({ blend: 'normal' })
.source(flydata, {
parser: {
type: 'json',
coordinates: 'coord',
},
})
.color('#b97feb')
.shape('arc3d')
.size(0.5)
.active(true)
.animate({
interval: 2,
trailLength: 2,
duration: 1,
})
.style({
opacity: 1,
segmentNumber: 60,
globalArcHeight: 20,
});
...
// 2、注册服务
scene.addLayer(flyLine);
```

View File

@ -0,0 +1,6 @@
---
title: Earth Point
order: 3
---
`markdown:docs/api/earth/point.zh.md`

View File

@ -0,0 +1,36 @@
---
title: 点图层
order: 3
---
`markdown:docs/common/style.md`
## 简介
用户在地球模式下使用点图层无需做额外的操作L7 会自动识别地球模式并相关的转化
## 使用
```javascript
// 1、构建 pointlayer
const pointlayer = new PointLayer()
.source(
data,
{
parser: {
type: 'json',
x: 'lng',
y: 'lat',
},
},
)
// .shape('circle') // cylinder
.color('#f00')
.size(20) // .size('', () => [1, 1, 10])
...
// 2、添加 pointlayer 图层对象
scene.addLayer(pointlayer);
```

View File

@ -136,6 +136,10 @@ L7 将 threejs 的引用封装成一个特殊的图层对象,在使用上与
用户通过该方法管理加载模型的动画
### getRenderCamera(): THREE.Camera
返回根据当前地图场景参数下对应的 THREEJS 相机
## 加载模型
用户可以使用 threejs 提供的能力加载其支持的任意模型

View File

@ -0,0 +1,76 @@
import { Scene, EarthLayer, LineLayer } from '@antv/l7';
import { Earth } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new Earth({})
});
// TODO: 地球模式下背景色默认为 #000 通过 setBgColor 方法我们可以设置可视化层的背景色
scene.setBgColor('#333');
const flydata = [{ coord: [[ 104.195397, 35.86166 ], [ 100.992541, 15.870032 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 114.727669, 4.535277 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 9.501785, 56.26392 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -66.590149, 18.220833 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 174.885971, -40.900557 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 104.990963, 12.565679 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 6.129582999999999, 49.815273 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 8.468945999999999, 60.47202399999999 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 108.277199, 14.058324 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -95.712891, 37.09024 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 121.49917, 25.12653 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -9.429499000000002, 6.428055 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 127.766922, 35.907757 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 10.451526, 51.165691 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 23.881275, 55.169438 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 34.851612, 31.046051 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 53.847818, 23.424076 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 102.495496, 19.85627 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 21.824312, 39.074208 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 25.48583, 42.733883 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 15.472962, 49.81749199999999 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 78.96288, 20.593684 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -3.435973, 55.378051 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 33.429859, 35.126413 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 8.227511999999999, 46.818188 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 114.066662, 22.588638 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 14.550072, 47.516231 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 2.213749, 46.227638 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 12.56738, 41.87194 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 105.318756, 61.52401 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 80.77179699999999, 7.873053999999999 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 5.291265999999999, 52.132633 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 35.243322, 38.963745 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 18.643501, 60.12816100000001 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 25.748151, 61.92410999999999 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -3.74922, 40.46366700000001 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 113.551538, 22.109432 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 4.469936, 50.503887 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -106.346771, 56.130366 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 138.252924, 36.204824 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 17.679076, 43.915886 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -88.49765, 17.189877 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 25.013607, 58.595272 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 101.975766, 4.210484 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -8.24389, 53.41291 ]] }, { coord: [[ 104.195397, 35.86166 ], [ -8.224454, 39.39987199999999 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 133.775136, -25.274398 ]] }, { coord: [[ 104.195397, 35.86166 ], [ 121.774017, 12.879721 ]] }];
const flyLine = new LineLayer({ blend: 'normal' })
.source(flydata, {
parser: {
type: 'json',
coordinates: 'coord'
}
})
.color('#b97feb')
.shape('arc3d')
.size(0.5)
.active(true)
.animate({
interval: 2,
trailLength: 2,
duration: 1
})
.style({
opacity: 1,
segmentNumber: 60,
globalArcHeight: 20
});
const earthlayer = new EarthLayer()
.source(
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*3-3NSpqRqUoAAAAAAAAAAAAAARQnAQ',
{
parser: {
type: 'image'
}
}
)
.color('#2E8AE6')
.shape('fill')
.style({
globelOtions: {
ambientRatio: 0.6, // 环境光
diffuseRatio: 0.4, // 漫反射
specularRatio: 0.1 // 高光反射
}
})
.animate(true);
const atomLayer = new EarthLayer()
.color('#2E8AE6')
.shape('atomSphere')
.style({
opacity: 1
});
const bloomLayer = new EarthLayer().color('#fff').shape('bloomSphere')
.style({
opacity: 0.7
});
scene.on('loaded', () => {
scene.addLayer(earthlayer);
scene.addLayer(atomLayer);
scene.addLayer(bloomLayer);
scene.addLayer(flyLine);
earthlayer.setEarthTime(4.0);
});

View File

@ -0,0 +1,13 @@
{
"title": {
"zh": "地球模式 - arc3d图层",
"en": "Earth Mode - lineLayer/arc3d"
},
"demos": [
{
"filename": "flyline.js",
"title": "飞线",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*ZrpHTKS1_FsAAAAAAAAAAAAAARQnAQ"
}
]
}

View File

@ -0,0 +1,4 @@
---
title: flyline
order: 0
---

View File

@ -0,0 +1,4 @@
---
title: 飞线
order: 0
---

View File

@ -0,0 +1,320 @@
import { Scene, PointLayer, EarthLayer } from '@antv/l7';
import { Earth } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new Earth({})
});
const d = [
{ lng: 121.61865234375, lat: 25.29437116258816 },
{ lng: 121.058349609375, lat: 25.015928763367857 },
{ lng: 120.7177734375, lat: 24.587090339209634 },
{ lng: 120.28930664062499, lat: 23.936054914599815 },
{ lng: 120.12451171875, lat: 23.553916518321625 },
{ lng: 120.08056640625, lat: 23.120153621695614 },
{ lng: 120.234375, lat: 22.867317960075614 },
{ lng: 120.43212890625, lat: 22.52270570348246 },
{ lng: 120.65185546875, lat: 22.370396344320053 },
{ lng: 120.750732421875, lat: 21.922663209325922 },
{ lng: 120.948486328125, lat: 22.268764039073968 },
{ lng: 121.124267578125, lat: 22.806567100271522 },
{ lng: 121.56372070312499, lat: 23.915970370510227 },
{ lng: 121.88232421875, lat: 24.557116164309626 },
{ lng: 121.95922851562501, lat: 25.075648445630527 },
{ lng: 109.97314453125, lat: 20.076570104545173 },
{ lng: 108.896484375, lat: 19.663280219987662 },
{ lng: 108.61083984375, lat: 18.979025953255267 },
{ lng: 108.80859375, lat: 18.47960905583197 },
{ lng: 109.599609375, lat: 18.35452552912664 },
{ lng: 110.32470703125, lat: 18.771115062337024 },
{ lng: 111.005859375, lat: 19.78738018198621 },
{ lng: 127.657407, lat: 49.76027 },
{ lng: 129.397818, lat: 49.4406 },
{ lng: 130.582293, lat: 48.729687 },
{ lng: 130.987282, lat: 47.790132 },
{ lng: 132.506672, lat: 47.78897 },
{ lng: 133.373596, lat: 48.183442 },
{ lng: 135.026311, lat: 48.47823 },
{ lng: 134.500814, lat: 47.57844 },
{ lng: 134.112362, lat: 47.212467 },
{ lng: 133.769644, lat: 46.116927 },
{ lng: 133.097127, lat: 45.144066 },
{ lng: 131.883454, lat: 45.321162 },
{ lng: 131.025212, lat: 44.967953 },
{ lng: 131.288555, lat: 44.11152 },
{ lng: 131.144688, lat: 42.92999 },
{ lng: 130.633866, lat: 42.903015 },
{ lng: 130.640016, lat: 42.395009 },
{ lng: 129.994267, lat: 42.985387 },
{ lng: 129.596669, lat: 42.424982 },
{ lng: 128.052215, lat: 41.994285 },
{ lng: 128.208433, lat: 41.466772 },
{ lng: 127.343783, lat: 41.503152 },
{ lng: 126.869083, lat: 41.816569 },
{ lng: 126.182045, lat: 41.107336 },
{ lng: 125.079942, lat: 40.569824 },
{ lng: 124.265625, lat: 39.928493 },
{ lng: 122.86757, lat: 39.637788 },
{ lng: 122.131388, lat: 39.170452 },
{ lng: 121.054554, lat: 38.897471 },
{ lng: 121.585995, lat: 39.360854 },
{ lng: 121.376757, lat: 39.750261 },
{ lng: 122.168595, lat: 40.422443 },
{ lng: 121.640359, lat: 40.94639 },
{ lng: 120.768629, lat: 40.593388 },
{ lng: 119.639602, lat: 39.898056 },
{ lng: 119.023464, lat: 39.252333 },
{ lng: 118.042749, lat: 39.204274 },
{ lng: 117.532702, lat: 38.737636 },
{ lng: 118.059699, lat: 38.061476 },
{ lng: 118.87815, lat: 37.897325 },
{ lng: 118.911636, lat: 37.448464 },
{ lng: 119.702802, lat: 37.156389 },
{ lng: 120.823457, lat: 37.870428 },
{ lng: 121.711259, lat: 37.481123 },
{ lng: 122.357937, lat: 37.454484 },
{ lng: 122.519995, lat: 36.930614 },
{ lng: 121.104164, lat: 36.651329 },
{ lng: 120.637009, lat: 36.11144 },
{ lng: 119.664562, lat: 35.609791 },
{ lng: 119.151208, lat: 34.909859 },
{ lng: 120.227525, lat: 34.360332 },
{ lng: 120.620369, lat: 33.376723 },
{ lng: 121.229014, lat: 32.460319 },
{ lng: 121.908146, lat: 31.692174 },
{ lng: 121.891919, lat: 30.949352 },
{ lng: 121.264257, lat: 30.676267 },
{ lng: 121.503519, lat: 30.142915 },
{ lng: 122.092114, lat: 29.83252 },
{ lng: 121.938428, lat: 29.018022 },
{ lng: 121.684439, lat: 28.225513 },
{ lng: 121.125661, lat: 28.135673 },
{ lng: 120.395473, lat: 27.053207 },
{ lng: 119.585497, lat: 25.740781 },
{ lng: 118.656871, lat: 24.547391 },
{ lng: 117.281606, lat: 23.624501 },
{ lng: 115.890735, lat: 22.782873 },
{ lng: 114.763827, lat: 22.668074 },
{ lng: 114.152547, lat: 22.22376 },
{ lng: 113.80678, lat: 22.54834 },
{ lng: 113.241078, lat: 22.051367 },
{ lng: 111.843592, lat: 21.550494 },
{ lng: 110.785466, lat: 21.397144 },
{ lng: 110.444039, lat: 20.341033 },
{ lng: 109.889861, lat: 20.282457 },
{ lng: 109.627655, lat: 21.008227 },
{ lng: 109.864488, lat: 21.395051 },
{ lng: 108.522813, lat: 21.715212 },
{ lng: 108.05018, lat: 21.55238 },
{ lng: 107.04342, lat: 21.811899 },
{ lng: 106.567273, lat: 22.218205 },
{ lng: 106.725403, lat: 22.794268 },
{ lng: 105.811247, lat: 22.976892 },
{ lng: 105.329209, lat: 23.352063 },
{ lng: 104.476858, lat: 22.81915 },
{ lng: 103.504515, lat: 22.703757 },
{ lng: 102.706992, lat: 22.708795 },
{ lng: 102.170436, lat: 22.464753 },
{ lng: 101.652018, lat: 22.318199 },
{ lng: 101.80312, lat: 21.174367 },
{ lng: 101.270026, lat: 21.201652 },
{ lng: 101.180005, lat: 21.436573 },
{ lng: 101.150033, lat: 21.849984 },
{ lng: 100.416538, lat: 21.558839 },
{ lng: 99.983489, lat: 21.742937 },
{ lng: 99.240899, lat: 22.118314 },
{ lng: 99.531992, lat: 22.949039 },
{ lng: 98.898749, lat: 23.142722 },
{ lng: 98.660262, lat: 24.063286 },
{ lng: 97.60472, lat: 23.897405 },
{ lng: 97.724609, lat: 25.083637 },
{ lng: 98.671838, lat: 25.918703 },
{ lng: 98.712094, lat: 26.743536 },
{ lng: 98.68269, lat: 27.508812 },
{ lng: 98.246231, lat: 27.747221 },
{ lng: 97.911988, lat: 28.335945 },
{ lng: 97.327114, lat: 28.261583 },
{ lng: 96.248833, lat: 28.411031 },
{ lng: 96.586591, lat: 28.83098 },
{ lng: 96.117679, lat: 29.452802 },
{ lng: 95.404802, lat: 29.031717 },
{ lng: 94.56599, lat: 29.277438 },
{ lng: 93.413348, lat: 28.640629 },
{ lng: 92.503119, lat: 27.896876 },
{ lng: 91.696657, lat: 27.771742 },
{ lng: 91.258854, lat: 28.040614 },
{ lng: 90.730514, lat: 28.064954 },
{ lng: 90.015829, lat: 28.296439 },
{ lng: 89.47581, lat: 28.042759 },
{ lng: 88.814248, lat: 27.299316 },
{ lng: 88.730326, lat: 28.086865 },
{ lng: 88.120441, lat: 27.876542 },
{ lng: 86.954517, lat: 27.974262 },
{ lng: 85.82332, lat: 28.203576 },
{ lng: 85.011638, lat: 28.642774 },
{ lng: 84.23458, lat: 28.839894 },
{ lng: 83.898993, lat: 29.320226 },
{ lng: 83.337115, lat: 29.463732 },
{ lng: 82.327513, lat: 30.115268 },
{ lng: 81.525804, lat: 30.422717 },
{ lng: 81.111256, lat: 30.183481 },
{ lng: 79.721367, lat: 30.882715 },
{ lng: 78.738894, lat: 31.515906 },
{ lng: 78.458446, lat: 32.618164 },
{ lng: 79.176129, lat: 32.48378 },
{ lng: 79.208892, lat: 32.994395 },
{ lng: 78.811086, lat: 33.506198 },
{ lng: 78.912269, lat: 34.321936 },
{ lng: 77.837451, lat: 35.49401 },
{ lng: 76.192848, lat: 35.898403 },
{ lng: 75.896897, lat: 36.666806 },
{ lng: 75.158028, lat: 37.133031 },
{ lng: 74.980002, lat: 37.41999 },
{ lng: 74.829986, lat: 37.990007 },
{ lng: 74.864816, lat: 38.378846 },
{ lng: 74.257514, lat: 38.606507 },
{ lng: 73.928852, lat: 38.505815 },
{ lng: 73.675379, lat: 39.431237 },
{ lng: 73.960013, lat: 39.660008 },
{ lng: 73.822244, lat: 39.893973 },
{ lng: 74.776862, lat: 40.366425 },
{ lng: 75.467828, lat: 40.562072 },
{ lng: 76.526368, lat: 40.427946 },
{ lng: 76.904484, lat: 41.066486 },
{ lng: 78.187197, lat: 41.185316 },
{ lng: 78.543661, lat: 41.582243 },
{ lng: 80.11943, lat: 42.123941 },
{ lng: 80.25999, lat: 42.349999 },
{ lng: 80.18015, lat: 42.920068 },
{ lng: 80.866206, lat: 43.180362 },
{ lng: 79.966106, lat: 44.917517 },
{ lng: 81.947071, lat: 45.317027 },
{ lng: 82.458926, lat: 45.53965 },
{ lng: 83.180484, lat: 47.330031 },
{ lng: 85.16429, lat: 47.000956 },
{ lng: 85.720484, lat: 47.452969 },
{ lng: 85.768233, lat: 48.455751 },
{ lng: 86.598776, lat: 48.549182 },
{ lng: 87.35997, lat: 49.214981 },
{ lng: 87.751264, lat: 49.297198 },
{ lng: 88.013832, lat: 48.599463 },
{ lng: 88.854298, lat: 48.069082 },
{ lng: 90.280826, lat: 47.693549 },
{ lng: 90.970809, lat: 46.888146 },
{ lng: 90.585768, lat: 45.719716 },
{ lng: 90.94554, lat: 45.286073 },
{ lng: 92.133891, lat: 45.115076 },
{ lng: 93.480734, lat: 44.975472 },
{ lng: 94.688929, lat: 44.352332 },
{ lng: 95.306875, lat: 44.241331 },
{ lng: 95.762455, lat: 43.319449 },
{ lng: 96.349396, lat: 42.725635 },
{ lng: 97.451757, lat: 42.74889 },
{ lng: 99.515817, lat: 42.524691 },
{ lng: 100.845866, lat: 42.663804 },
{ lng: 101.83304, lat: 42.514873 },
{ lng: 103.312278, lat: 41.907468 },
{ lng: 104.522282, lat: 41.908347 },
{ lng: 104.964994, lat: 41.59741 },
{ lng: 106.129316, lat: 42.134328 },
{ lng: 107.744773, lat: 42.481516 },
{ lng: 109.243596, lat: 42.519446 },
{ lng: 110.412103, lat: 42.871234 },
{ lng: 111.129682, lat: 43.406834 },
{ lng: 111.829588, lat: 43.743118 },
{ lng: 111.667737, lat: 44.073176 },
{ lng: 111.348377, lat: 44.457442 },
{ lng: 111.873306, lat: 45.102079 },
{ lng: 112.436062, lat: 45.011646 },
{ lng: 113.463907, lat: 44.808893 },
{ lng: 114.460332, lat: 45.339817 },
{ lng: 115.985096, lat: 45.727235 },
{ lng: 116.717868, lat: 46.388202 },
{ lng: 117.421701, lat: 46.672733 },
{ lng: 118.874326, lat: 46.805412 },
{ lng: 119.66327, lat: 46.69268 },
{ lng: 119.772824, lat: 47.048059 },
{ lng: 118.866574, lat: 47.74706 },
{ lng: 118.064143, lat: 48.06673 },
{ lng: 117.295507, lat: 47.697709 },
{ lng: 116.308953, lat: 47.85341 },
{ lng: 115.742837, lat: 47.726545 },
{ lng: 115.485282, lat: 48.135383 },
{ lng: 116.191802, lat: 49.134598 },
{ lng: 116.678801, lat: 49.888531 },
{ lng: 117.879244, lat: 49.510983 },
{ lng: 119.288461, lat: 50.142883 },
{ lng: 119.279366, lat: 50.582908 },
{ lng: 120.18205, lat: 51.643566 },
{ lng: 120.738191, lat: 51.964115 },
{ lng: 120.725789, lat: 52.516226 },
{ lng: 120.177089, lat: 52.753886 },
{ lng: 121.003085, lat: 53.251401 },
{ lng: 122.245748, lat: 53.431726 },
{ lng: 123.571507, lat: 53.458804 },
{ lng: 125.068211, lat: 53.161045 },
{ lng: 125.946349, lat: 52.792799 },
{ lng: 126.564399, lat: 51.784255 },
{ lng: 126.939157, lat: 51.353894 },
{ lng: 127.287456, lat: 50.739797 },
{ lng: 127.657407, lat: 49.76027 }
];
const pointlayer = new PointLayer()
.source(
d,
{
parser: {
type: 'json',
x: 'lng',
y: 'lat'
}
}
)
.shape('cylinder')
.color('#f00')
.size('', () => [ 1, 1, 10 ])
.active(true);
const earthlayer = new EarthLayer()
.source(
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*3-3NSpqRqUoAAAAAAAAAAAAAARQnAQ',
{
parser: {
type: 'image'
}
}
)
.shape('fill')
.style({
opacity: 1.0,
radius: 40,
globelOtions: {
ambientRatio: 0.6, // 环境光
diffuseRatio: 0.4, // 漫反射
specularRatio: 0.1 // 高光反射
}
})
.animate(true);
const atomLayer = new EarthLayer()
.color('#2E8AE6')
.shape('atomSphere')
.style({
opacity: 1
});
const bloomLayer = new EarthLayer().color('#fff').shape('bloomSphere')
.style({
opacity: 0.6
});
scene.on('loaded', () => {
scene.addLayer(earthlayer);
scene.addLayer(pointlayer);
scene.addLayer(atomLayer);
scene.addLayer(bloomLayer);
earthlayer.setEarthTime(4.0);
});

View File

@ -0,0 +1,18 @@
{
"title": {
"zh": "地球模式 - 点图层",
"en": "Earth Mode - pointLayer"
},
"demos": [
{
"filename": "point.js",
"title": "点图层",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*R5uPS4SIMi0AAAAAAAAAAAAAARQnAQ"
},
{
"filename": "cylinder.js",
"title": "圆柱图层",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*u2iWTrhJnL0AAAAAAAAAAAAAARQnAQ"
}
]
}

View File

@ -0,0 +1,320 @@
import { Scene, PointLayer, EarthLayer } from '@antv/l7';
import { Earth } from '@antv/l7-maps';
const scene = new Scene({
id: 'map',
map: new Earth({})
});
const d = [
{ lng: 121.61865234375, lat: 25.29437116258816 },
{ lng: 121.058349609375, lat: 25.015928763367857 },
{ lng: 120.7177734375, lat: 24.587090339209634 },
{ lng: 120.28930664062499, lat: 23.936054914599815 },
{ lng: 120.12451171875, lat: 23.553916518321625 },
{ lng: 120.08056640625, lat: 23.120153621695614 },
{ lng: 120.234375, lat: 22.867317960075614 },
{ lng: 120.43212890625, lat: 22.52270570348246 },
{ lng: 120.65185546875, lat: 22.370396344320053 },
{ lng: 120.750732421875, lat: 21.922663209325922 },
{ lng: 120.948486328125, lat: 22.268764039073968 },
{ lng: 121.124267578125, lat: 22.806567100271522 },
{ lng: 121.56372070312499, lat: 23.915970370510227 },
{ lng: 121.88232421875, lat: 24.557116164309626 },
{ lng: 121.95922851562501, lat: 25.075648445630527 },
{ lng: 109.97314453125, lat: 20.076570104545173 },
{ lng: 108.896484375, lat: 19.663280219987662 },
{ lng: 108.61083984375, lat: 18.979025953255267 },
{ lng: 108.80859375, lat: 18.47960905583197 },
{ lng: 109.599609375, lat: 18.35452552912664 },
{ lng: 110.32470703125, lat: 18.771115062337024 },
{ lng: 111.005859375, lat: 19.78738018198621 },
{ lng: 127.657407, lat: 49.76027 },
{ lng: 129.397818, lat: 49.4406 },
{ lng: 130.582293, lat: 48.729687 },
{ lng: 130.987282, lat: 47.790132 },
{ lng: 132.506672, lat: 47.78897 },
{ lng: 133.373596, lat: 48.183442 },
{ lng: 135.026311, lat: 48.47823 },
{ lng: 134.500814, lat: 47.57844 },
{ lng: 134.112362, lat: 47.212467 },
{ lng: 133.769644, lat: 46.116927 },
{ lng: 133.097127, lat: 45.144066 },
{ lng: 131.883454, lat: 45.321162 },
{ lng: 131.025212, lat: 44.967953 },
{ lng: 131.288555, lat: 44.11152 },
{ lng: 131.144688, lat: 42.92999 },
{ lng: 130.633866, lat: 42.903015 },
{ lng: 130.640016, lat: 42.395009 },
{ lng: 129.994267, lat: 42.985387 },
{ lng: 129.596669, lat: 42.424982 },
{ lng: 128.052215, lat: 41.994285 },
{ lng: 128.208433, lat: 41.466772 },
{ lng: 127.343783, lat: 41.503152 },
{ lng: 126.869083, lat: 41.816569 },
{ lng: 126.182045, lat: 41.107336 },
{ lng: 125.079942, lat: 40.569824 },
{ lng: 124.265625, lat: 39.928493 },
{ lng: 122.86757, lat: 39.637788 },
{ lng: 122.131388, lat: 39.170452 },
{ lng: 121.054554, lat: 38.897471 },
{ lng: 121.585995, lat: 39.360854 },
{ lng: 121.376757, lat: 39.750261 },
{ lng: 122.168595, lat: 40.422443 },
{ lng: 121.640359, lat: 40.94639 },
{ lng: 120.768629, lat: 40.593388 },
{ lng: 119.639602, lat: 39.898056 },
{ lng: 119.023464, lat: 39.252333 },
{ lng: 118.042749, lat: 39.204274 },
{ lng: 117.532702, lat: 38.737636 },
{ lng: 118.059699, lat: 38.061476 },
{ lng: 118.87815, lat: 37.897325 },
{ lng: 118.911636, lat: 37.448464 },
{ lng: 119.702802, lat: 37.156389 },
{ lng: 120.823457, lat: 37.870428 },
{ lng: 121.711259, lat: 37.481123 },
{ lng: 122.357937, lat: 37.454484 },
{ lng: 122.519995, lat: 36.930614 },
{ lng: 121.104164, lat: 36.651329 },
{ lng: 120.637009, lat: 36.11144 },
{ lng: 119.664562, lat: 35.609791 },
{ lng: 119.151208, lat: 34.909859 },
{ lng: 120.227525, lat: 34.360332 },
{ lng: 120.620369, lat: 33.376723 },
{ lng: 121.229014, lat: 32.460319 },
{ lng: 121.908146, lat: 31.692174 },
{ lng: 121.891919, lat: 30.949352 },
{ lng: 121.264257, lat: 30.676267 },
{ lng: 121.503519, lat: 30.142915 },
{ lng: 122.092114, lat: 29.83252 },
{ lng: 121.938428, lat: 29.018022 },
{ lng: 121.684439, lat: 28.225513 },
{ lng: 121.125661, lat: 28.135673 },
{ lng: 120.395473, lat: 27.053207 },
{ lng: 119.585497, lat: 25.740781 },
{ lng: 118.656871, lat: 24.547391 },
{ lng: 117.281606, lat: 23.624501 },
{ lng: 115.890735, lat: 22.782873 },
{ lng: 114.763827, lat: 22.668074 },
{ lng: 114.152547, lat: 22.22376 },
{ lng: 113.80678, lat: 22.54834 },
{ lng: 113.241078, lat: 22.051367 },
{ lng: 111.843592, lat: 21.550494 },
{ lng: 110.785466, lat: 21.397144 },
{ lng: 110.444039, lat: 20.341033 },
{ lng: 109.889861, lat: 20.282457 },
{ lng: 109.627655, lat: 21.008227 },
{ lng: 109.864488, lat: 21.395051 },
{ lng: 108.522813, lat: 21.715212 },
{ lng: 108.05018, lat: 21.55238 },
{ lng: 107.04342, lat: 21.811899 },
{ lng: 106.567273, lat: 22.218205 },
{ lng: 106.725403, lat: 22.794268 },
{ lng: 105.811247, lat: 22.976892 },
{ lng: 105.329209, lat: 23.352063 },
{ lng: 104.476858, lat: 22.81915 },
{ lng: 103.504515, lat: 22.703757 },
{ lng: 102.706992, lat: 22.708795 },
{ lng: 102.170436, lat: 22.464753 },
{ lng: 101.652018, lat: 22.318199 },
{ lng: 101.80312, lat: 21.174367 },
{ lng: 101.270026, lat: 21.201652 },
{ lng: 101.180005, lat: 21.436573 },
{ lng: 101.150033, lat: 21.849984 },
{ lng: 100.416538, lat: 21.558839 },
{ lng: 99.983489, lat: 21.742937 },
{ lng: 99.240899, lat: 22.118314 },
{ lng: 99.531992, lat: 22.949039 },
{ lng: 98.898749, lat: 23.142722 },
{ lng: 98.660262, lat: 24.063286 },
{ lng: 97.60472, lat: 23.897405 },
{ lng: 97.724609, lat: 25.083637 },
{ lng: 98.671838, lat: 25.918703 },
{ lng: 98.712094, lat: 26.743536 },
{ lng: 98.68269, lat: 27.508812 },
{ lng: 98.246231, lat: 27.747221 },
{ lng: 97.911988, lat: 28.335945 },
{ lng: 97.327114, lat: 28.261583 },
{ lng: 96.248833, lat: 28.411031 },
{ lng: 96.586591, lat: 28.83098 },
{ lng: 96.117679, lat: 29.452802 },
{ lng: 95.404802, lat: 29.031717 },
{ lng: 94.56599, lat: 29.277438 },
{ lng: 93.413348, lat: 28.640629 },
{ lng: 92.503119, lat: 27.896876 },
{ lng: 91.696657, lat: 27.771742 },
{ lng: 91.258854, lat: 28.040614 },
{ lng: 90.730514, lat: 28.064954 },
{ lng: 90.015829, lat: 28.296439 },
{ lng: 89.47581, lat: 28.042759 },
{ lng: 88.814248, lat: 27.299316 },
{ lng: 88.730326, lat: 28.086865 },
{ lng: 88.120441, lat: 27.876542 },
{ lng: 86.954517, lat: 27.974262 },
{ lng: 85.82332, lat: 28.203576 },
{ lng: 85.011638, lat: 28.642774 },
{ lng: 84.23458, lat: 28.839894 },
{ lng: 83.898993, lat: 29.320226 },
{ lng: 83.337115, lat: 29.463732 },
{ lng: 82.327513, lat: 30.115268 },
{ lng: 81.525804, lat: 30.422717 },
{ lng: 81.111256, lat: 30.183481 },
{ lng: 79.721367, lat: 30.882715 },
{ lng: 78.738894, lat: 31.515906 },
{ lng: 78.458446, lat: 32.618164 },
{ lng: 79.176129, lat: 32.48378 },
{ lng: 79.208892, lat: 32.994395 },
{ lng: 78.811086, lat: 33.506198 },
{ lng: 78.912269, lat: 34.321936 },
{ lng: 77.837451, lat: 35.49401 },
{ lng: 76.192848, lat: 35.898403 },
{ lng: 75.896897, lat: 36.666806 },
{ lng: 75.158028, lat: 37.133031 },
{ lng: 74.980002, lat: 37.41999 },
{ lng: 74.829986, lat: 37.990007 },
{ lng: 74.864816, lat: 38.378846 },
{ lng: 74.257514, lat: 38.606507 },
{ lng: 73.928852, lat: 38.505815 },
{ lng: 73.675379, lat: 39.431237 },
{ lng: 73.960013, lat: 39.660008 },
{ lng: 73.822244, lat: 39.893973 },
{ lng: 74.776862, lat: 40.366425 },
{ lng: 75.467828, lat: 40.562072 },
{ lng: 76.526368, lat: 40.427946 },
{ lng: 76.904484, lat: 41.066486 },
{ lng: 78.187197, lat: 41.185316 },
{ lng: 78.543661, lat: 41.582243 },
{ lng: 80.11943, lat: 42.123941 },
{ lng: 80.25999, lat: 42.349999 },
{ lng: 80.18015, lat: 42.920068 },
{ lng: 80.866206, lat: 43.180362 },
{ lng: 79.966106, lat: 44.917517 },
{ lng: 81.947071, lat: 45.317027 },
{ lng: 82.458926, lat: 45.53965 },
{ lng: 83.180484, lat: 47.330031 },
{ lng: 85.16429, lat: 47.000956 },
{ lng: 85.720484, lat: 47.452969 },
{ lng: 85.768233, lat: 48.455751 },
{ lng: 86.598776, lat: 48.549182 },
{ lng: 87.35997, lat: 49.214981 },
{ lng: 87.751264, lat: 49.297198 },
{ lng: 88.013832, lat: 48.599463 },
{ lng: 88.854298, lat: 48.069082 },
{ lng: 90.280826, lat: 47.693549 },
{ lng: 90.970809, lat: 46.888146 },
{ lng: 90.585768, lat: 45.719716 },
{ lng: 90.94554, lat: 45.286073 },
{ lng: 92.133891, lat: 45.115076 },
{ lng: 93.480734, lat: 44.975472 },
{ lng: 94.688929, lat: 44.352332 },
{ lng: 95.306875, lat: 44.241331 },
{ lng: 95.762455, lat: 43.319449 },
{ lng: 96.349396, lat: 42.725635 },
{ lng: 97.451757, lat: 42.74889 },
{ lng: 99.515817, lat: 42.524691 },
{ lng: 100.845866, lat: 42.663804 },
{ lng: 101.83304, lat: 42.514873 },
{ lng: 103.312278, lat: 41.907468 },
{ lng: 104.522282, lat: 41.908347 },
{ lng: 104.964994, lat: 41.59741 },
{ lng: 106.129316, lat: 42.134328 },
{ lng: 107.744773, lat: 42.481516 },
{ lng: 109.243596, lat: 42.519446 },
{ lng: 110.412103, lat: 42.871234 },
{ lng: 111.129682, lat: 43.406834 },
{ lng: 111.829588, lat: 43.743118 },
{ lng: 111.667737, lat: 44.073176 },
{ lng: 111.348377, lat: 44.457442 },
{ lng: 111.873306, lat: 45.102079 },
{ lng: 112.436062, lat: 45.011646 },
{ lng: 113.463907, lat: 44.808893 },
{ lng: 114.460332, lat: 45.339817 },
{ lng: 115.985096, lat: 45.727235 },
{ lng: 116.717868, lat: 46.388202 },
{ lng: 117.421701, lat: 46.672733 },
{ lng: 118.874326, lat: 46.805412 },
{ lng: 119.66327, lat: 46.69268 },
{ lng: 119.772824, lat: 47.048059 },
{ lng: 118.866574, lat: 47.74706 },
{ lng: 118.064143, lat: 48.06673 },
{ lng: 117.295507, lat: 47.697709 },
{ lng: 116.308953, lat: 47.85341 },
{ lng: 115.742837, lat: 47.726545 },
{ lng: 115.485282, lat: 48.135383 },
{ lng: 116.191802, lat: 49.134598 },
{ lng: 116.678801, lat: 49.888531 },
{ lng: 117.879244, lat: 49.510983 },
{ lng: 119.288461, lat: 50.142883 },
{ lng: 119.279366, lat: 50.582908 },
{ lng: 120.18205, lat: 51.643566 },
{ lng: 120.738191, lat: 51.964115 },
{ lng: 120.725789, lat: 52.516226 },
{ lng: 120.177089, lat: 52.753886 },
{ lng: 121.003085, lat: 53.251401 },
{ lng: 122.245748, lat: 53.431726 },
{ lng: 123.571507, lat: 53.458804 },
{ lng: 125.068211, lat: 53.161045 },
{ lng: 125.946349, lat: 52.792799 },
{ lng: 126.564399, lat: 51.784255 },
{ lng: 126.939157, lat: 51.353894 },
{ lng: 127.287456, lat: 50.739797 },
{ lng: 127.657407, lat: 49.76027 }
];
const pointlayer = new PointLayer()
.source(
d,
{
parser: {
type: 'json',
x: 'lng',
y: 'lat'
}
}
)
.shape('circle')
.color('#f00')
.size(10)
.active(true);
const earthlayer = new EarthLayer()
.source(
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*3-3NSpqRqUoAAAAAAAAAAAAAARQnAQ',
{
parser: {
type: 'image'
}
}
)
.shape('base')
.style({
opacity: 1.0,
radius: 40,
globelOtions: {
ambientRatio: 0.6, // 环境光
diffuseRatio: 0.4, // 漫反射
specularRatio: 0.1 // 高光反射
}
})
.animate(true);
const atomLayer = new EarthLayer()
.color('#2E8AE6')
.shape('atomSphere')
.style({
opacity: 1
});
const bloomLayer = new EarthLayer().color('#fff').shape('bloomSphere')
.style({
opacity: 0.6
});
scene.on('loaded', () => {
scene.addLayer(earthlayer);
scene.addLayer(pointlayer);
scene.addLayer(atomLayer);
scene.addLayer(bloomLayer);
earthlayer.setEarthTime(4.0);
});

View File

@ -0,0 +1,4 @@
---
title: PointLayer
order: 0
---

View File

@ -0,0 +1,4 @@
---
title: 点图层
order: 0
---

View File

@ -0,0 +1,111 @@
import { Scene } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
import { ThreeLayer, ThreeRender } from '@antv/l7-three';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [ 111.4453125, 32.84267363195431 ],
pitch: 45,
rotation: 30,
zoom: 12
})
});
scene.on('loaded', () => {
scene.registerRenderService(ThreeRender);
const threeJSLayer = new ThreeLayer({
enableMultiPassRenderer: false,
onAddMeshes: (threeScene, layer) => {
threeScene.add(new THREE.AmbientLight(0xffffff));
const sunlight = new THREE.DirectionalLight(0xffffff, 0.25);
sunlight.position.set(0, 80000000, 100000000);
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
const center = scene.getCenter();
const cubeGeometry = new THREE.BoxBufferGeometry(10000, 10000, 10000);
const cubeMaterial = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide });
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
layer.setObjectLngLat(cube, [ center.lng + 0.05, center.lat ], 0);
threeScene.add(cube);
// 使用 Three.js glTFLoader 加载模型
const loader = new GLTFLoader();
loader.load(
'https://gw.alipayobjects.com/os/bmw-prod/3ca0a546-92d8-4ba0-a89c-017c218d5bea.gltf',
gltf => {
// 根据 GeoJSON 数据放置模型
layer.getSource().data.dataArray.forEach(({ coordinates }) => {
const gltfScene = gltf.scene;
setDouble(gltfScene);
layer.adjustMeshToMap(gltfScene);
// gltfScene.scale.set(1000, 1000, 1000)
layer.setMeshScale(gltfScene, 1000, 1000, 1000);
layer.setObjectLngLat(
gltfScene,
[ coordinates[0] + 0.02, coordinates[1] ],
0
);
const animations = gltf.animations;
if (animations && animations.length) {
const mixer = new THREE.AnimationMixer(gltfScene);
const animation = animations[2];
const action = mixer.clipAction(animation);
action.play();
layer.addAnimateMixer(mixer);
}
// layer.setObjectLngLat(gltfScene, [center.lng + 0.05, center.lat] as ILngLat, 0)
let t = 0;
setInterval(() => {
t += 0.01;
layer.setObjectLngLat(
gltfScene,
[ center.lng, center.lat + Math.sin(t) * 0.1 ],
0
);
}, 16);
// 向场景中添加模型
threeScene.add(gltfScene);
});
// 重绘图层
layer.render();
}
);
}
})
.source({
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [ 111.4453125, 32.84267363195431 ]
}
}
]
})
.animate(true);
scene.addLayer(threeJSLayer);
});
function setDouble(object) {
if (object.children && object.children.length && object.children.length > 0) {
object.children.map(child => setDouble(child));
} else if (object.material) {
object.material.side = THREE.DoubleSide;
}
}

View File

@ -0,0 +1,226 @@
import { Scene, PolygonLayer } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
import { ThreeLayer, ThreeRender } from '@antv/l7-three';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { animate, easeInOut } from 'popmotion';
let isTravel = false;
function travel(
mesh,
path,
duration,
callback
) {
if (path.length < 2 || isTravel) return;
isTravel = true;
let startIndex = 0;
const len = path.length;
const currentP = path[0],
nextP = path[1];
const t = duration / len;
move(currentP, nextP);
function move(currentP, nextP) {
animate({
from: {
x: currentP.x,
y: currentP.y,
z: currentP.z
},
to: {
x: nextP.x,
y: nextP.y,
z: nextP.z
},
ease: easeInOut,
duration: t,
repeatType: 'loop',
onUpdate: o => {
mesh.position.set(o.x, o.y, o.z);
},
onComplete: () => {
startIndex++;
if (startIndex < len - 1) {
const currentP = path[startIndex],
nextP = path[startIndex + 1];
mesh.lookAt(nextP);
move(currentP, nextP);
} else {
isTravel = false;
callback && callback();
}
}
});
}
}
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [ 112, 35.39847 ],
pitch: 45,
rotation: 30,
zoom: 5
})
});
scene.on('loaded', () => {
scene.registerRenderService(ThreeRender);
fetch(
'https://gw.alipayobjects.com/os/basement_prod/d2e0e930-fd44-4fca-8872-c1037b0fee7b.json'
)
.then(d => d.json())
.then(data => {
const polygonlayer = new PolygonLayer({
name: '01',
zIndex: -1
})
.source(data)
.color('name', [
'#2E8AE6',
'#69D1AB',
'#DAF291',
'#FFD591',
'#FF7A45',
'#CF1D49'
])
.shape('fill')
.select(true)
.style({
opacity: 1.0
});
scene.addLayer(polygonlayer);
});
const threeJSLayer = new ThreeLayer({
enableMultiPassRenderer: false,
onAddMeshes: (threeScene, layer) => {
// 添加光
threeScene.add(new THREE.AmbientLight(0xffffff));
const sunlight = new THREE.DirectionalLight(0xffffff, 0.25);
sunlight.position.set(0, 80000000, 100000000);
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
const lineData = [
[ 116.71874999999999, 26.745610382199022 ],
[ 117.3779296875, 28.8831596093235 ],
[ 115.75195312499999, 31.466153715024294 ],
[ 113.466796875, 33.32134852669881 ],
[ 113.9501953125, 35.85343961959182 ],
[ 115.400390625, 38.272688535980976 ],
[ 116.5869140625, 40.3130432088809 ],
[ 115.6201171875, 42.261049162113856 ],
[ 112.236328125, 42.94033923363181 ],
[ 109.3798828125, 41.04621681452063 ],
[ 103.84277343749999, 39.80853604144591 ],
[ 98.9208984375, 39.842286020743394 ],
[ 95.2294921875, 40.713955826286046 ],
[ 91.7138671875, 39.87601941962116 ],
[ 90.8349609375, 37.125286284966805 ],
[ 90.3076171875, 35.88905007936091 ],
[ 90.703125, 33.284619968887675 ],
[ 92.94433593749999, 31.98944183792288 ],
[ 96.2841796875, 32.21280106801518 ],
[ 98.87695312499999, 32.0639555946604 ],
[ 102.919921875, 28.459033019728043 ],
[ 107.9736328125, 28.497660832963472 ],
[ 108.10546875, 24.206889622398023 ],
[ 109.072265625, 23.039297747769726 ],
[ 112.763671875, 24.44714958973082 ],
[ 116.54296874999999, 25.958044673317843 ]
];
const lineCoordData = lineData.map(d => {
return layer.lnglatToCoord(d);
});
const rawPoints = [];
lineCoordData.map(d => {
rawPoints.push(new THREE.Vector3(d[0], d[1], 0));
return '';
});
const curve = new THREE.CatmullRomCurve3(rawPoints);
const points = curve.getPoints(200);
const geometry = new THREE.BufferGeometry().setFromPoints(points);
const material = new THREE.LineBasicMaterial({ color: 0xff0000 });
const line = new THREE.LineLoop(geometry, material);
threeScene.add(line);
// 使用 Three.js glTFLoader 加载模型
const loader = new GLTFLoader();
loader.load(
'https://gw.alipayobjects.com/os/antvdemo/assets/gltf/truck/CesiumMilkTruck.gltf', // Truck
gltf => {
// 根据 GeoJSON 数据放置模型
const gltfScene = gltf.scene.clone();
setDouble(gltfScene);
layer.getSource().data.dataArray.forEach(() => {
layer.adjustMeshToMap(gltfScene);
gltfScene.scale.set(500000, 500000, 500000);
const animations = gltf.animations;
if (animations && animations.length) {
const mixer = new THREE.AnimationMixer(gltfScene);
// @ts-ignore
for (let i = 0; i < animations.length; i++) {
const animation = animations[i];
// There's .3333 seconds junk at the tail of the Monster animation that
// keeps it from looping cleanly. Clip it at 3 seconds
const action = mixer.clipAction(animation);
action.play();
}
layer.addAnimateMixer(mixer);
}
// 向场景中添加模型
threeScene.add(gltfScene);
});
travelLoop();
function travelLoop() {
travel(gltfScene, points, 5000, () => {
travelLoop();
});
}
// 重绘图层
layer.render();
}
);
}
})
.source({
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [ 112, 35.39847 ]
}
}
]
})
.animate(true);
scene.addLayer(threeJSLayer);
});
function setDouble(object) {
if (object.children && object.children.length && object.children.length > 0) {
object.children.map(child => setDouble(child));
} else if (object.material) {
object.material.side = THREE.DoubleSide;
}
}

View File

@ -0,0 +1,73 @@
import { Scene } from '@antv/l7';
import { Mapbox } from '@antv/l7-maps';
import { ThreeLayer, ThreeRender } from '@antv/l7-three';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
const scene = new Scene({
id: 'map',
map: new Mapbox({
center: [ 121.4, 31.258134 ],
pitch: 45,
rotation: 30,
zoom: 15
})
});
scene.on('loaded', () => {
scene.registerRenderService(ThreeRender);
const threeJSLayer = new ThreeLayer({
enableMultiPassRenderer: false,
onAddMeshes: (threeScene, layer) => {
threeScene.add(new THREE.AmbientLight(0xffffff));
const sunlight = new THREE.DirectionalLight(0xffffff, 0.25);
sunlight.position.set(0, 80000000, 100000000);
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
// 使用 Three.js glTFLoader 加载模型
const loader = new GLTFLoader();
loader.load(
'https://gw.alipayobjects.com/os/bmw-prod/3ca0a546-92d8-4ba0-a89c-017c218d5bea.gltf',
gltf => {
// 根据 GeoJSON 数据放置模型
layer.getSource().data.dataArray.forEach(() => {
const gltfScene = gltf.scene;
layer.adjustMeshToMap(gltfScene);
layer.setMeshScale(gltfScene, 10, 10, 10);
const animations = gltf.animations;
if (animations && animations.length) {
const mixer = new THREE.AnimationMixer(gltfScene);
const animation = animations[2];
const action = mixer.clipAction(animation);
action.play();
layer.addAnimateMixer(mixer);
}
// 向场景中添加模型
threeScene.add(gltfScene);
});
// 重绘图层
layer.render();
}
);
}
})
.source({
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [ 121.4, 31.258134 ]
}
}
]
})
.animate(true);
scene.addLayer(threeJSLayer);
});

View File

@ -0,0 +1,28 @@
{
"title": {
"zh": "第三方引擎",
"en": "other engine"
},
"demos": [
{
"filename": "amap_ant.js",
"title": "高德地图",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*1_W2SIR8swwAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "amap_car.js",
"title": "高德地图 car",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*C3JRTI_qlxEAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "mapbox_ant.js",
"title": "mapbox 地图",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*kflKRJvm3hYAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "space_click.js",
"title": "点击建筑",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*AY5vSIMeLy8AAAAAAAAAAAAAARQnAQ"
}
]
}

View File

@ -0,0 +1,437 @@
import { Scene } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
import { ThreeLayer, ThreeRender } from '@antv/l7-three';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
import { animate, easeInOut } from 'popmotion';
function changeValue(
startValue,
endValue,
duration = 500,
callback,
complete
) {
if (typeof startValue === 'number') {
animate({
from: {
v: startValue
},
to: {
v: endValue
},
ease: easeInOut,
duration,
onUpdate: o => {
callback(o.v);
return '';
},
onComplete: () => {
complete && complete();
return '';
}
});
} else {
animate({
from: {
lng: startValue.lng,
lat: startValue.lat,
pitch: startValue.pitch,
rotation: startValue.rotation,
zoom: startValue.zoom
},
to: {
lng: (endValue).lng,
lat: (endValue).lat,
pitch: (endValue).pitch,
rotation: (endValue).rotation,
zoom: (endValue).zoom
},
ease: easeInOut,
duration,
onUpdate: o => {
callback(o);
return '';
},
onComplete: () => {
complete && complete();
return '';
}
});
}
return '';
}
const raycaster = new THREE.Raycaster();
const lng = 120.1;
const lat = 30.265;
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [ lng, lat ],
pitch: 70,
rotation: 220,
zoom: 16
})
});
scene.on('loaded', () => {
const mouse = new THREE.Vector2();
let zspace,
aspace,
ASpaceTextMesh,
ZSpaceTextMesh;
scene.registerRenderService(ThreeRender);
const center = scene.getCenter();
const threeJSLayer = new ThreeLayer({
enableMultiPassRenderer: false,
// @ts-ignore
onAddMeshes: (threeScene, layer) => {
threeScene.add(new THREE.AmbientLight(0xffffff));
const sunlight = new THREE.DirectionalLight(0xffffff, 0.25);
sunlight.position.set(0, 80000000, 100000000);
sunlight.matrixWorldNeedsUpdate = true;
threeScene.add(sunlight);
// map
// https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*gA0NRbuOF5cAAAAAAAAAAAAAARQnAQ
// height
// https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*eYFaRYlnnOUAAAAAAAAAAAAAARQnAQ
const image = new Image();
image.crossOrigin = '';
image.src =
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*eYFaRYlnnOUAAAAAAAAAAAAAARQnAQ';
image.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0, image.width, image.height);
const heightData = ctx.getImageData(0, 0, image.width, image.height)
.data;
const s = 53000;
const geometry = new THREE.PlaneGeometry(s, s, 255, 255);
geometry.vertices.map((v, i) => {
const r = heightData[i * 4];
const g = heightData[i * 4 + 1];
const b = heightData[i * 4 + 2];
let h =
-10000.0 +
(r * 255.0 * 256.0 * 256.0 + g * 255.0 * 256.0 + b * 255.0) *
0.1;
h = h / 20 - 127600;
h = Math.max(0, h);
v.z = h;
return '';
});
const material = new THREE.MeshPhongMaterial({
transparent: true,
// opacity: 0.6,
map: new THREE.TextureLoader().load(
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*gA0NRbuOF5cAAAAAAAAAAAAAARQnAQ'
),
side: THREE.DoubleSide
});
const plane = new THREE.Mesh(geometry, material);
layer.setObjectLngLat(plane, [ 120.1008, 30.2573 ], 0);
plane.position.z = 10;
threeScene.add(plane);
return '';
};
// 使用 Three.js glTFLoader 加载模型
const loader = new GLTFLoader();
loader.load(
'https://gw.alipayobjects.com/os/bmw-prod/3ca0a546-92d8-4ba0-a89c-017c218d5bea.gltf',
gltf => {
const antModel = gltf.scene;
setDouble(antModel);
// antModel.children[0].material.side = THREE.DoubleSide
layer.adjustMeshToMap(antModel);
layer.setMeshScale(antModel, 20, 20, 20);
layer.setObjectLngLat(
antModel,
[ center.lng - 0.002, center.lat ],
0
);
const animations = gltf.animations;
if (animations && animations.length) {
const mixer = new THREE.AnimationMixer(antModel);
const animation = animations[1];
const action = mixer.clipAction(animation);
action.play();
layer.addAnimateMixer(mixer);
}
antModel.rotation.y = Math.PI;
// 向场景中添加模型
threeScene.add(antModel);
// 重绘图层
layer.render();
return '';
}
);
const v = `
varying vec2 vUv;
varying vec4 worldPosition;
void main() {
vUv = uv;
worldPosition = modelMatrix * vec4(position, 1.0);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}`;
const f = `
varying vec2 vUv;
varying vec4 worldPosition;
uniform vec3 color;
void main() {
gl_FragColor = vec4(color, fract(worldPosition.z / 50.0));
}`;
const shadermaterial = new THREE.ShaderMaterial({
uniforms: {
color: {
value: new THREE.Vector3(0.21372549, 0.34705882, 0.56470588)
}
},
vertexShader: v,
fragmentShader: f,
side: THREE.DoubleSide
});
const fbxLoaded = new FBXLoader();
// load ZSpace
fbxLoaded.load(
'https://gw.alipayobjects.com/os/bmw-prod/af1652c9-3c4f-4e73-ac4c-1f78fefbaf6a.fbx',
gltf => {
zspace = gltf;
layer.adjustMeshToMap(zspace);
// @ts-ignore
zspace.children[0].material = shadermaterial;
layer.setMeshScale(zspace, 10, 10, 10);
layer.setObjectLngLat(zspace, [ 120.1015, 30.2661 ], 0);
zspace.rotation.x = Math.PI * 2;
zspace.rotation.z = -Math.PI * (-2 / 15);
threeScene.add(zspace);
return '';
}
);
fbxLoaded.load(
'https://gw.alipayobjects.com/os/bmw-prod/11d6e4c1-bd5b-4dc1-bae5-ac51c14e9056.fbx',
model => {
aspace = model;
layer.adjustMeshToMap(aspace);
// @ts-ignore
aspace.children[0].material = shadermaterial;
layer.setMeshScale(aspace, 8, 8, 8);
layer.setObjectLngLat(aspace, [ 120.099, 30.261 ], 0);
aspace.rotation.x = Math.PI * 2;
aspace.rotation.z = -Math.PI * (3 / 15);
threeScene.add(aspace);
return '';
}
);
const textLoader = new THREE.FontLoader();
textLoader.load(
'https://gw.alipayobjects.com/os/bmw-prod/0a3f46eb-294e-4d95-87f2-052c26ad4bf1.json',
font => {
const fontOptions = {
size: 360, // 字号大小,一般为大写字母的高度
height: 50, // 文字的厚度
font, // 字体,默认是'helvetiker',需对应引用的字体文件
bevelThickness: 10, // 倒角厚度
bevelSize: 10, // 倒角宽度
curveSegments: 30, // 弧线分段数,使得文字的曲线更加光滑
bevelEnabled: true // 布尔值,是否使用倒角,意为在边缘处斜切
};
const aspaceGeo = new THREE.TextGeometry('ASpace', fontOptions);
aspaceGeo.center();
const zspaceGeo = new THREE.TextGeometry('ZSpace', fontOptions);
zspaceGeo.center();
const fontMat = new THREE.MeshPhongMaterial({
color: 0xcccccc,
shininess: 60,
specular: 0xcccccc,
side: THREE.DoubleSide
});
const testHeight = 900;
ASpaceTextMesh = new THREE.Mesh(aspaceGeo, fontMat);
ASpaceTextMesh.rotation.x = Math.PI / 2;
ASpaceTextMesh.rotation.y = (-Math.PI * 3) / 4;
layer.setObjectLngLat(
ASpaceTextMesh,
[ 120.099, 30.261 ],
testHeight
);
threeScene.add(ASpaceTextMesh);
ZSpaceTextMesh = new THREE.Mesh(zspaceGeo, fontMat);
ZSpaceTextMesh.rotation.x = Math.PI / 2;
ZSpaceTextMesh.rotation.y = (-Math.PI * 3) / 4;
layer.setObjectLngLat(
ZSpaceTextMesh,
[ 120.103, 30.2661 ],
testHeight
);
threeScene.add(ZSpaceTextMesh);
getH(0, 200);
function getH(h1, h2) {
changeValue(
h1,
h2,
1000,
h => {
ASpaceTextMesh.position.z = testHeight + h;
ZSpaceTextMesh.position.z = testHeight + h;
return '';
},
() => {
setTimeout(() => getH(h2, h1), 10);
return '';
}
);
}
return '';
}
);
}
})
.source({
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: {},
geometry: {
type: 'Point',
coordinates: [ 111.4453125, 32.84267363195431 ]
}
}
]
})
.animate(true);
scene.addLayer(threeJSLayer);
// @ts-ignore
let currentCamera = threeJSLayer.threeRenderService.getRenderCamera();
const currentView = {
lng: center.lng,
lat: center.lat,
pitch: 70,
rotation: 220,
zoom: 16
};
scene.on('zoom', () => {
const cen = scene.getCenter();
currentView.lng = cen.lng;
currentView.lat = cen.lat;
currentView.pitch = scene.getPitch();
currentView.zoom = scene.getZoom();
return '';
});
scene.getMapService().on('mapchange', () => {
// @ts-ignore
currentCamera = threeJSLayer.getRenderCamera();
currentView.pitch = scene.getPitch();
return '';
});
const ASpaceView = {
lng: 120.109509,
lat: 30.251529,
pitch: 83,
rotation: 225,
zoom: 16
};
const ZSpaceView = {
lng: 120.112026,
lat: 30.256881,
pitch: 80,
rotation: 220,
zoom: 16
};
scene.on('click', ev => {
// @ts-ignore
const size = scene?.map?.getSize();
mouse.x = (ev.pixel.x / size.width) * 2 - 1;
mouse.y = -(ev.pixel.y / size.height) * 2 + 1;
raycaster.setFromCamera(mouse, currentCamera);
const intersects = raycaster.intersectObjects([ zspace, aspace ], true);
if (intersects.length > 0) {
const object = intersects[0].object;
if (object.name === 'Z空间') {
selectSpace(currentView, ZSpaceView, ZSpaceTextMesh);
} else {
selectSpace(currentView, ASpaceView, ASpaceTextMesh);
}
}
return '';
});
function selectSpace(
currentView,
targetView,
spaceText
) {
if (spaceText) {
changeValue(
spaceText.rotation.y,
spaceText.rotation.y + Math.PI * 2,
500,
r => {
spaceText.rotation.y = r;
return '';
}
);
}
changeValue(currentView, targetView, 500, view => {
scene.setCenter([ view.lng, view.lat ]);
scene.setPitch(view.pitch);
scene.setRotation(view.rotation);
scene.setZoom(view.zoom);
currentView.lng = view.lng;
currentView.lat = view.lat;
currentView.pitch = view.pitch;
currentView.rotation = view.rotation;
currentView.zoom = view.zoom;
return '';
});
}
return '';
});
function setDouble(object) {
if (object.children && object.children.length && object.children.length > 0) {
object.children.map(child => setDouble(child));
} else if (object.material) {
object.material.side = THREE.DoubleSide;
}
}

View File

@ -0,0 +1,4 @@
---
title: Threejs
order: 0
---

View File

@ -0,0 +1,4 @@
---
title: Threejs
order: 0
---

View File

@ -9,6 +9,11 @@ window.l7Maps = require('@antv/l7-maps');
window.l7React = require('@antv/l7-react');
window.l7Draw = require('@antv/l7-draw');
window.l7District = require('@antv/l7-district');
window.l7Three = require('@antv/l7-three');
window.three = require('three');
window.GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader');
window.FBXLoader = require('three/examples/jsm/loaders/FBXLoader');
window.react = require('react');
window.popmotion = require('popmotion');
window.reactDom = require('react-dom');
window.antd = require('antd');

View File

@ -190,6 +190,14 @@ module.exports = {
en: 'import other gl'
},
order: 3
},
{
slug: 'api/earth',
title: {
zh: '地球模式',
en: 'Earth Mode'
},
order: 3
}
],
examples: [
@ -225,6 +233,22 @@ module.exports = {
en: 'L7 Draw'
}
},
{
slug: 'engine',
icon: 'map',
title: {
zh: '第三方引擎',
en: 'other engine'
}
},
{
slug: 'earth',
icon: 'map',
title: {
zh: '地球模式',
en: 'Earth Mode'
}
},
{
slug: 'point',
icon: 'point',

View File

@ -19,6 +19,7 @@ exports.onCreateWebpackConfig = ({ getConfig }) => {
'@antv/l7-renderer': path.resolve(__dirname, 'packages/renderer/src'),
'@antv/l7-scene': path.resolve(__dirname, 'packages/scene/src'),
'@antv/l7-source': path.resolve(__dirname, 'packages/source/src'),
'@antv/l7-utils': path.resolve(__dirname, 'packages/utils/src')
'@antv/l7-utils': path.resolve(__dirname, 'packages/utils/src'),
'@antv/l7-three': path.resolve(__dirname, 'packages/three/src')
}
};

View File

@ -1,11 +1,11 @@
npm dist-tag add @antv/l7-component@2.5.19 latest
npm dist-tag add @antv/l7-core@2.5.19 latest
npm dist-tag add @antv/l7@2.5.19 latest
npm dist-tag add @antv/l7-layers@2.5.19 latest
npm dist-tag add @antv/l7-map@2.5.19 latest
npm dist-tag add @antv/l7-maps@2.5.19 latest
npm dist-tag add @antv/l7-renderer@2.5.19 latest
npm dist-tag add @antv/l7-scene@2.5.19 latest
npm dist-tag add @antv/l7-source@2.5.19 latest
npm dist-tag add @antv/l7-three@2.5.19 latest
npm dist-tag add @antv/l7-utils@2.5.19 latest
npm dist-tag add @antv/l7-component@2.5.35 latest
npm dist-tag add @antv/l7-core@2.5.35 latest
npm dist-tag add @antv/l7@2.5.35 latest
npm dist-tag add @antv/l7-layers@2.5.35 latest
npm dist-tag add @antv/l7-map@2.5.35 latest
npm dist-tag add @antv/l7-maps@2.5.35 latest
npm dist-tag add @antv/l7-renderer@2.5.35 latest
npm dist-tag add @antv/l7-scene@2.5.35 latest
npm dist-tag add @antv/l7-source@2.5.35 latest
npm dist-tag add @antv/l7-three@2.5.35 latest
npm dist-tag add @antv/l7-utils@2.5.35 latest

View File

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

View File

@ -197,5 +197,7 @@
"tnpm": {
"mode": "yarn"
},
"dependencies": {}
"dependencies": {
"@antv/geo-coord": "^1.0.8"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-component",
"version": "2.5.30",
"version": "2.5.41",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
@ -25,8 +25,8 @@
"author": "lzxue",
"license": "ISC",
"dependencies": {
"@antv/l7-core": "^2.5.30",
"@antv/l7-utils": "^2.5.30",
"@antv/l7-core": "^2.5.41",
"@antv/l7-utils": "^2.5.41",
"@babel/runtime": "^7.7.7",
"eventemitter3": "^4.0.0",
"inversify": "^5.0.1",

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-core",
"version": "2.5.30",
"version": "2.5.41",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
@ -24,7 +24,7 @@
"license": "ISC",
"dependencies": {
"@antv/async-hook": "^2.1.0",
"@antv/l7-utils": "^2.5.30",
"@antv/l7-utils": "^2.5.41",
"@babel/runtime": "^7.7.7",
"@mapbox/tiny-sdf": "^1.1.1",
"ajv": "^6.10.2",

View File

@ -140,7 +140,14 @@ export default class PickingService implements IPickingService {
return features;
}
private async pickingAllLayer(target: IInteractionTarget) {
if (this.alreadyInPicking || this.layerService.alreadyInRendering) {
if (
// TODO: this.alreadyInPicking 避免多次重复拾取
this.alreadyInPicking ||
// TODO: this.layerService.alreadyInRendering 一个渲染序列中只进行一次拾取操作
this.layerService.alreadyInRendering ||
// TODO: this.layerService.isMapDragging() 如果地图正在拖拽 则不进行拾取操作
this.layerService.isMapDragging()
) {
return;
}
this.alreadyInPicking = true;

View File

@ -101,6 +101,8 @@ export interface ILayer {
layerModelNeedUpdate: boolean;
styleNeedUpdate: boolean;
layerModel: ILayerModel;
layerChildren: ILayer[]; // 在图层中添加子图层
sceneContainer: Container | undefined;
dataState: IDataState; // 数据流状态
pickedFeatureID: number | null;
hooks: {
@ -124,10 +126,20 @@ export interface ILayer {
options?: ISourceCFG;
};
multiPassRenderer: IMultiPassRenderer;
/**
* threejs
* @param lnglat
* @param altitude
* @param rotation
* @param scale
*/
threeRenderService?: any;
needPick(type: string): boolean;
getLayerConfig(): Partial<ILayerConfig & ISceneConfig>;
getContainer(): Container;
setContainer(container: Container): void;
setContainer(container: Container, sceneContainer: Container): void;
setCurrentPickId(id: number | null): void;
getCurrentPickId(): number | null;
setCurrentSelectedId(id: number | null): void;
@ -220,14 +232,6 @@ export interface ILayer {
setAnimateStartTime(): void;
getLayerAnimateTime(): number;
/**
* threejs
* @param lnglat
* @param altitude
* @param rotation
* @param scale
*/
// 获取对应地图的经纬度模型矩阵
getModelMatrix?(
lnglat: ILngLat,
@ -260,6 +264,9 @@ export interface ILayer {
// 增加加载模型的动画混合器
addAnimateMixer?(mixer: any): void;
// 返回当前的 threejs camera
getRenderCamera?(): any;
/**
*
*/
@ -372,10 +379,11 @@ export interface ILayerService {
getLayers(): ILayer[];
getLayer(id: string): ILayer | undefined;
getLayerByName(name: string): ILayer | undefined;
remove(layer: ILayer): void;
remove(layer: ILayer, parentLayer?: ILayer): void;
removeAllLayers(): void;
updateRenderOrder(): void;
renderLayers(type?: string): void;
getOESTextureFloat(): boolean;
isMapDragging(): boolean;
destroy(): void;
}

View File

@ -1,9 +1,11 @@
import { rgb2arr } from '@antv/l7-utils';
import { inject, injectable } from 'inversify';
import 'reflect-metadata';
import { ILayer } from '../..';
import { TYPES } from '../../types';
import Clock from '../../utils/clock';
import { IGlobalConfigService } from '../config/IConfigService';
import { IMapService } from '../map/IMapService';
import { IRendererService } from '../renderer/IRendererService';
import { ILayerModel, ILayerService } from './ILayerService';
@ -28,6 +30,9 @@ export default class LayerService implements ILayerService {
@inject(TYPES.IRendererService)
private readonly renderService: IRendererService;
@inject(TYPES.IMapService)
private readonly mapService: IMapService;
@inject(TYPES.IGlobalConfigService)
private readonly configService: IGlobalConfigService;
@ -59,11 +64,20 @@ export default class LayerService implements ILayerService {
return this.layers.find((layer) => layer.name === name);
}
public remove(layer: ILayer): void {
const layerIndex = this.layers.indexOf(layer);
if (layerIndex > -1) {
this.layers.splice(layerIndex, 1);
public remove(layer: ILayer, parentLayer?: ILayer): void {
// Tip: layer.layerChildren 当 layer 存在子图层的情况
if (parentLayer) {
const layerIndex = parentLayer.layerChildren.indexOf(layer);
if (layerIndex > -1) {
parentLayer.layerChildren.splice(layerIndex, 1);
}
} else {
const layerIndex = this.layers.indexOf(layer);
if (layerIndex > -1) {
this.layers.splice(layerIndex, 1);
}
}
layer.emit('remove', null);
layer.destroy();
this.renderLayers();
@ -86,17 +100,29 @@ export default class LayerService implements ILayerService {
this.alreadyInRendering = true;
this.clear();
this.updateRenderOrder();
this.layers
.filter((layer) => layer.inited)
.filter((layer) => layer.isVisible())
.forEach((layer) => {
// trigger hooks
layer.hooks.beforeRenderData.call();
layer.hooks.beforeRender.call();
layer.render();
layer.hooks.afterRender.call();
// Tip: 渲染 layer 的子图层 默认 layerChildren 为空数组 表示没有子图层 目前只有 ImageTileLayer 有子图层
renderLayerEvent(layer.layerChildren);
renderLayerEvent([layer]);
});
this.alreadyInRendering = false;
function renderLayerEvent(layers: ILayer[]) {
layers
.filter((layer) => layer.inited)
.filter((layer) => layer.isVisible())
.forEach((layer) => {
// trigger hooks
layer.hooks.beforeRenderData.call();
layer.hooks.beforeRender.call();
layer.render();
layer.hooks.afterRender.call();
});
}
}
public updateRenderOrder() {
@ -106,7 +132,14 @@ export default class LayerService implements ILayerService {
}
public destroy() {
this.layers.forEach((layer) => layer.destroy());
this.layers.forEach((layer) => {
// Tip: layer.layerChildren 当 layer 存在子图层的情况
if (layer.layerChildren) {
layer.layerChildren.forEach((child) => child.destroy());
layer.layerChildren = [];
}
layer.destroy();
});
this.layers = [];
this.renderLayers();
}
@ -129,6 +162,16 @@ export default class LayerService implements ILayerService {
return this.renderService.extensionObject.OES_texture_float;
}
// TODO: 判断地图是否正在被拖动
public isMapDragging() {
return this.mapService.dragging;
}
private runRender() {
this.renderLayers();
this.layerRenderID = requestAnimationFrame(this.runRender.bind(this));
}
// 渲染检测
private renderTest(renderType: string | undefined): boolean {
const now = new Date().getTime();
@ -141,8 +184,9 @@ export default class LayerService implements ILayerService {
if (renderType) {
switch (renderType) {
case 'picking':
// return false;
// TODO: picking 类型的渲染事件
// 若是上次触发为地图或动画触发的渲染,则认为是地图事件与拾取事件在同时触发,放弃此次渲染
// 若是上次触发为地图触发的渲染,则认为是地图事件与拾取事件在同时触发,放弃此次渲染
if (
this.lastRenderType === 'mapRender' ||
this.lastRenderType === 'animate'
@ -159,6 +203,7 @@ export default class LayerService implements ILayerService {
return true;
}
case 'animate':
// return false;
if (this.lastRenderType === 'mapRender') {
this.lastRenderType = 'animate';
return false;
@ -178,19 +223,20 @@ export default class LayerService implements ILayerService {
}
private clear() {
const color = rgb2arr(this.mapService.bgColor) as [
number,
number,
number,
number,
];
this.renderService.clear({
color: [0, 0, 0, 0],
color,
depth: 1,
stencil: 0,
framebuffer: null,
});
}
private runRender() {
this.renderLayers('animate');
this.layerRenderID = requestAnimationFrame(this.runRender.bind(this));
}
private stopRender() {
cancelAnimationFrame(this.layerRenderID);
}

View File

@ -32,6 +32,9 @@ export interface IMapWrapper {
export interface IMapService<RawMap = {}> {
version?: string;
map: RawMap;
dragging: boolean;
bgColor: string;
setBgColor(color: string): void;
init(): void;
initViewPort?(): void;
destroy(): void;
@ -106,7 +109,86 @@ export interface IMapService<RawMap = {}> {
): void;
}
export const MapServiceEvent = ['mapload'];
export interface IEarthService<RawMap = {}> {
version?: string;
map: RawMap;
bgColor: string;
setBgColor(color: string): void;
init(): void;
initViewPort?(): void;
destroy(): void;
onCameraChanged(callback: (viewport: IViewport) => void): void;
// init map
addMarkerContainer(): void;
getMarkerContainer(): HTMLElement;
// MapEvent // 定义事件类型
on(type: string, handler: (...args: any[]) => void): void;
off(type: string, handler: (...args: any[]) => void): void;
once(type: string, handler: (...args: any[]) => void): void;
// get dom
getContainer(): HTMLElement | null;
getSize(): [number, number];
// get map status method
getMinZoom(): number;
getMaxZoom(): number;
// get map params
getType(): string;
getZoom(): number;
getCenter(option?: ICameraOptions): ILngLat;
getPitch(): number;
getRotation(): number;
getBounds(): Bounds;
getMapContainer(): HTMLElement | null;
getMapCanvasContainer(): HTMLElement;
// control with raw map
setRotation(rotation: number): void;
zoomIn(option?: any, eventData?: any): void;
zoomOut(option?: any, eventData?: any): void;
panTo(p: Point): void;
panBy(x: number, y: number): void;
fitBounds(bound: Bounds, fitBoundsOptions?: unknown): void;
setZoomAndCenter(zoom: number, center: Point): void;
setCenter(center: [number, number], option?: ICameraOptions): void;
setPitch(pitch: number): void;
setZoom(zoom: number): void;
setMapStyle(style: any): void;
setMapStatus(option: Partial<IStatusOptions>): void;
// coordinates methods
pixelToLngLat(pixel: Point): ILngLat;
lngLatToPixel(lnglat: Point): IPoint;
containerToLngLat(pixel: Point): ILngLat;
lngLatToContainer(lnglat: Point): IPoint;
lngLatToMercator(lnglat: [number, number], altitude: number): IMercator;
getModelMatrix(
lnglat: [number, number],
altitude: number,
rotate: [number, number, number],
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;
// 地球模式下的地图方法/属性
rotateY?(
option:
| {
force?: boolean;
reg?: number;
}
| undefined,
): void;
}
export const MapServiceEvent = ['mapload', 'mapchange'];
/**
*

View File

@ -1,6 +1,7 @@
varying vec4 v_PickingResult;
uniform vec4 u_HighlightColor : [0, 0, 0, 0];
uniform float u_PickingStage : 0.0;
uniform float u_Dragging;
#define PICKING_NONE 0.0
#define PICKING_ENCODE 1.0
@ -42,5 +43,7 @@ vec4 filterPickingColor(vec4 color) {
* highlight color if this item is selected, otherwise unmodified argument.
*/
vec4 filterColor(vec4 color) {
// TODO: 过滤多余的 shader 计算
if(u_Dragging > 0.0) return color;
return filterPickingColor(filterHighlightColor(color));
}

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7",
"version": "2.5.30",
"version": "2.5.41",
"description": "A Large-scale WebGL-powered Geospatial Data Visualization",
"main": "lib/index.js",
"module": "es/index.js",
@ -25,12 +25,12 @@
"author": "antv",
"license": "MIT",
"dependencies": {
"@antv/l7-component": "^2.5.30",
"@antv/l7-core": "^2.5.30",
"@antv/l7-layers": "^2.5.30",
"@antv/l7-maps": "^2.5.30",
"@antv/l7-scene": "^2.5.30",
"@antv/l7-utils": "^2.5.30",
"@antv/l7-component": "^2.5.41",
"@antv/l7-core": "^2.5.41",
"@antv/l7-layers": "^2.5.41",
"@antv/l7-maps": "^2.5.41",
"@antv/l7-scene": "^2.5.41",
"@antv/l7-utils": "^2.5.41",
"@babel/runtime": "^7.7.7"
},
"gitHead": "684ba4eb806a798713496d3fc0b4d1e17517dc31",

View File

@ -1,2 +1,2 @@
const version = '2.5.30';
const version = '2.5.41';
export { version };

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-layers",
"version": "2.5.30",
"version": "2.5.41",
"description": "L7's collection of built-in layers",
"main": "lib/index.js",
"module": "es/index.js",
@ -23,10 +23,12 @@
"author": "xiaoiver",
"license": "ISC",
"dependencies": {
"@antv/geo-coord": "^1.0.8",
"@antv/async-hook": "^2.1.0",
"@antv/l7-core": "^2.5.30",
"@antv/l7-source": "^2.5.30",
"@antv/l7-utils": "^2.5.30",
"@antv/geo-coord": "^1.0.8",
"@antv/l7-core": "^2.5.41",
"@antv/l7-source": "^2.5.41",
"@antv/l7-utils": "^2.5.41",
"@babel/runtime": "^7.7.7",
"@mapbox/martini": "^0.2.0",
"@turf/meta": "^6.0.2",

View File

@ -113,6 +113,11 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
public layerModel: ILayerModel;
// TODO: 记录 sceneContainer 供创建子图层的时候使用 如 imageTileLayer
public sceneContainer: Container | undefined;
// TODO: 用于保存子图层对象
public layerChildren: ILayer[] = [];
@lazyInject(TYPES.IGlobalConfigService)
protected readonly configService: IGlobalConfigService;
@ -222,8 +227,9 @@ export default class BaseLayer<ChildLayerStyleOptions = {}> extends EventEmitter
* -> SceneContainer 1.*
* -> LayerContainer 1.*
*/
public setContainer(container: Container) {
public setContainer(container: Container, sceneContainer: Container) {
this.container = container;
this.sceneContainer = sceneContainer;
}
public getContainer() {

View File

@ -5,6 +5,7 @@ import earcut from 'earcut';
import { mat4, vec3 } from 'gl-matrix';
import {
EARTH_RADIUS,
EARTH_RADIUS_OUTER,
EARTH_SEGMENTS,
lglt2xyz,
primitiveSphere,
@ -415,3 +416,16 @@ export function earthTriangulation() {
normals: normalArr,
};
}
export function earthOuterTriangulation() {
const earthmesh = primitiveSphere(EARTH_RADIUS + EARTH_RADIUS_OUTER, {
segments: EARTH_SEGMENTS,
});
const { positionsArr, indicesArr, normalArr } = earthmesh;
return {
vertices: positionsArr,
indices: indicesArr,
size: 5,
normals: normalArr,
};
}

View File

@ -1,20 +1,28 @@
import BaseLayer from '../core/BaseLayer';
import EarthAtomSphereModel from './models/atmosphere';
import BaseEarthModel from './models/base';
import EarthBloomSphereModel from './models/bloomsphere';
export type EarthType = 'base';
interface IEarthLayerStyleOptions {
opacity: number;
setEarthTime(time: number): void;
}
const EarthModels: { [key in EarthType]: any } = {
export type EarthModelType = 'base' | 'atomSphere' | 'bloomSphere';
const EarthModels: { [key in EarthModelType]: any } = {
base: BaseEarthModel,
atomSphere: EarthAtomSphereModel,
bloomSphere: EarthBloomSphereModel,
};
const earthLayerTypes = ['base', 'atomSphere', 'bloomSphere'];
export default class EarthLayer extends BaseLayer<IEarthLayerStyleOptions> {
public type: string = 'EarthLayer';
public buildModels() {
const shape = 'base';
const shape = this.getModelType();
this.layerModel = new EarthModels[shape](this);
this.models = this.layerModel.initModels();
}
@ -30,4 +38,15 @@ export default class EarthLayer extends BaseLayer<IEarthLayerStyleOptions> {
console.error('请在 scene loaded 之后执行该方法!');
}
}
protected getModelType(): EarthModelType {
const shapeAttribute = this.styleAttributeService.getLayerStyleAttribute(
'shape',
);
let shape = (shapeAttribute?.scale?.field || 'base') as string;
if (earthLayerTypes.indexOf(shape) < 0) {
shape = 'base';
}
return shape as EarthModelType;
}
}

View File

@ -0,0 +1,126 @@
import {
AttributeType,
gl,
IEncodeFeature,
IModel,
IModelUniform,
} from '@antv/l7-core';
import { isNumber } from 'lodash';
import BaseModel from '../../core/BaseModel';
import { earthTriangulation } from '../../core/triangulation';
import atmoSphereFrag from '../shaders/atmosphere_frag.glsl';
import atmoSphereVert from '../shaders/atmosphere_vert.glsl';
interface IAtmoLayerStyleOptions {
opacity: number;
}
export default class EarthAtomSphereModel extends BaseModel {
public getUninforms(): IModelUniform {
const {
opacity = 1,
} = this.layer.getLayerConfig() as IAtmoLayerStyleOptions;
return {
u_opacity: isNumber(opacity) ? opacity : 1.0,
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public clearModels() {
return '';
}
public buildModels(): IModel[] {
// TODO: 调整图层的绘制顺序 地球大气层
this.layer.zIndex = -997;
return [
this.layer.buildLayerModel({
moduleName: 'earthAtmoSphere',
vertexShader: atmoSphereVert,
fragmentShader: atmoSphereFrag,
triangulation: earthTriangulation,
depth: {
enable: false,
},
blend: this.getBlend(),
}),
];
}
protected registerBuiltinAttributes() {
// point layer size;
this.styleAttributeService.registerStyleAttribute({
name: 'size',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Size',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { size = 1 } = feature;
return Array.isArray(size) ? [size[0]] : [size as number];
},
},
});
this.styleAttributeService.registerStyleAttribute({
name: 'normal',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Normal',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 3,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
normal: number[],
) => {
return normal;
},
},
});
this.styleAttributeService.registerStyleAttribute({
name: 'uv',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Uv',
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,
) => {
return [vertex[3], vertex[4]];
},
},
});
}
}

View File

@ -91,6 +91,8 @@ export default class BaseEarthModel extends BaseModel {
}
public buildModels(): IModel[] {
// TODO: 调整图层的绘制顺序 地球大气层
this.layer.zIndex = -998;
return [
this.layer.buildLayerModel({
moduleName: 'baseEarth',

View File

@ -0,0 +1,126 @@
import {
AttributeType,
gl,
IEncodeFeature,
IModel,
IModelUniform,
} from '@antv/l7-core';
import { isNumber } from 'lodash';
import BaseModel from '../../core/BaseModel';
import { earthOuterTriangulation } from '../../core/triangulation';
import bloomSphereFrag from '../shaders/bloomsphere_frag.glsl';
import bloomSphereVert from '../shaders/bloomsphere_vert.glsl';
interface IBloomLayerStyleOptions {
opacity: number;
}
export default class EarthBloomSphereModel extends BaseModel {
public getUninforms(): IModelUniform {
const {
opacity = 1,
} = this.layer.getLayerConfig() as IBloomLayerStyleOptions;
return {
u_opacity: isNumber(opacity) ? opacity : 1.0,
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public clearModels() {
return '';
}
public buildModels(): IModel[] {
// TODO: 调整图层的绘制顺序,让它保持在地球后面(减少锯齿现象)
this.layer.zIndex = -999;
return [
this.layer.buildLayerModel({
moduleName: 'earthBloomSphere',
vertexShader: bloomSphereVert,
fragmentShader: bloomSphereFrag,
triangulation: earthOuterTriangulation,
depth: {
enable: false,
},
blend: this.getBlend(),
}),
];
}
protected registerBuiltinAttributes() {
// point layer size;
this.styleAttributeService.registerStyleAttribute({
name: 'size',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Size',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { size = 1 } = feature;
return Array.isArray(size) ? [size[0]] : [size as number];
},
},
});
this.styleAttributeService.registerStyleAttribute({
name: 'normal',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Normal',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 3,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
normal: number[],
) => {
return normal;
},
},
});
this.styleAttributeService.registerStyleAttribute({
name: 'uv',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Uv',
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,
) => {
return [vertex[3], vertex[4]];
},
},
});
}
}

View File

@ -0,0 +1,17 @@
uniform float u_opacity;
uniform vec3 u_CameraPosition;
varying vec3 vVertexNormal;
varying float v_offset;
varying vec4 v_Color;
void main() {
// float intensity = pow(0.5 + dot(normalize(vVertexNormal), normalize(u_CameraPosition)), 3.0);
float intensity = pow(v_offset + dot(normalize(vVertexNormal), normalize(u_CameraPosition)), 3.0);
// TODO: 去除背面
if(intensity > 1.0) intensity = 0.0;
gl_FragColor = vec4(v_Color.rgb, v_Color.a * intensity * u_opacity);
}

View File

@ -0,0 +1,26 @@
attribute vec3 a_Position;
attribute vec3 a_Normal;
attribute vec2 a_Uv;
attribute vec4 a_Color;
uniform vec3 u_CameraPosition;
varying float v_CamreaDistance;
uniform mat4 u_ViewProjectionMatrix;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
varying vec3 vVertexNormal;
varying vec4 v_Color;
varying float v_offset;
void main() {
float EARTH_RADIUS = 100.0;
v_Color = a_Color;
v_offset = min(((length(u_CameraPosition) - EARTH_RADIUS)/600.0) * 0.5 + 0.4, 1.0);
vVertexNormal = a_Normal;
gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * vec4(a_Position, 1.0);
}

View File

@ -0,0 +1,15 @@
uniform float u_opacity;
uniform vec3 u_CameraPosition;
varying vec3 vVertexNormal;
varying vec4 v_Color;
void main() {
float intensity = - dot(normalize(vVertexNormal), normalize(u_CameraPosition));
// TODO: 去除背面
if(intensity > 1.0) intensity = 0.0;
gl_FragColor = vec4(v_Color.rgb, v_Color.a * intensity * u_opacity);
}

View File

@ -0,0 +1,20 @@
attribute vec3 a_Position;
attribute vec3 a_Normal;
attribute vec2 a_Uv;
attribute vec4 a_Color;
uniform vec3 u_CameraPosition;
uniform mat4 u_ViewProjectionMatrix;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
varying vec3 vVertexNormal;
varying vec4 v_Color;
void main() {
v_Color = a_Color;
vVertexNormal = a_Normal;
gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * vec4(a_Position, 1.0);
}

View File

@ -5,6 +5,8 @@ import { mat4, vec3 } from 'gl-matrix';
export const EARTH_RADIUS = 100;
export const EARTH_SEGMENTS = 36;
export const EARTH_RADIUS_OUTER = 40;
/**
*
* @param deg
@ -61,7 +63,6 @@ export function primitiveSphere(
const indicesArr = [];
const positions = [];
const positionsArr = [];
const normals = [];
const normalArr = [];
const uvs = [];
@ -96,7 +97,6 @@ export function primitiveSphere(
positionsArr.push(...tmpVec3.slice());
vec3.normalize(tmpVec3, tmpVec3);
normals.push(tmpVec3.slice());
normalArr.push(...tmpVec3.slice());
uvs.push([normalizedY, 1 - normalizedZ]);
@ -141,7 +141,6 @@ export function primitiveSphere(
return {
cells: indices,
positions,
normals,
uvs,
positionsArr,
indicesArr,

View File

@ -0,0 +1,38 @@
import BaseLayer from '../core/BaseLayer';
import ImageTileModels, { ImageTileModelType } from './models/index';
interface IImageLayerStyleOptions {
opacity: number;
}
export default class ImageTileLayer extends BaseLayer<IImageLayerStyleOptions> {
public type: string = 'ImageTileLayer';
public buildModels() {
const modelType = this.getModelType();
this.layerModel = new ImageTileModels[modelType](this);
this.models = this.layerModel.initModels();
}
public rebuildModels() {
this.models = this.layerModel.buildModels();
}
protected getConfigSchema() {
return {
properties: {
opacity: {
type: 'number',
minimum: 0,
maximum: 1,
},
},
};
}
protected getDefaultConfig() {
const type = this.getModelType();
const defaultConfig = {
imageTile: {},
};
return defaultConfig[type];
}
protected getModelType(): ImageTileModelType {
return 'imageTile';
}
}

View File

@ -0,0 +1,128 @@
import {
AttributeType,
gl,
IEncodeFeature,
ILayer,
ILayerPlugin,
IModel,
IModelUniform,
IRasterParserDataItem,
IStyleAttributeService,
ITexture2D,
lazyInject,
TYPES,
} from '@antv/l7-core';
import BaseModel from '../../core/BaseModel';
import { RasterImageTriangulation } from '../../core/triangulation';
import ImageTileFrag from './shaders/imagetile_frag.glsl';
import ImageTileVert from './shaders/imagetile_vert.glsl';
import Tile from '../utils/Tile';
interface IImageLayerStyleOptions {
resolution: string;
maxSourceZoom: number;
}
export default class ImageTileModel extends BaseModel {
public tileLayer: any;
public getUninforms(): IModelUniform {
return {};
}
// 临时的瓦片测试方法
public tile() {
const [WS, EN] = this.mapService.getBounds();
const NE = { lng: EN[0], lat: EN[1] };
const SW = { lng: WS[0], lat: WS[1] };
this.tileLayer.calCurrentTiles({
NE,
SW,
tileCenter: this.mapService.getCenter(),
currentZoom: this.mapService.getZoom(),
minSourceZoom: this.mapService.getMinZoom(),
minZoom: this.mapService.getMinZoom(),
maxZoom: this.mapService.getMaxZoom(),
});
}
public initModels() {
// TODO: 瓦片组件默认在最下层
this.layer.zIndex = -999;
const {
resolution = 'low',
maxSourceZoom = 17,
} = this.layer.getLayerConfig() as IImageLayerStyleOptions;
const source = this.layer.getSource();
// 当存在 url 的时候生效
if (source.data.tileurl) {
this.tileLayer = new Tile({
url: source.data.tileurl,
layerService: this.layerService,
layer: this.layer,
resolution,
maxSourceZoom,
// Tip: 当前为 default
crstype: 'epsg3857',
});
this.tile();
let t = new Date().getTime();
this.mapService.on('mapchange', () => {
const newT = new Date().getTime();
const cutT = newT - t;
t = newT;
if (cutT < 16) {
return;
}
this.tile();
});
}
return [
this.layer.buildLayerModel({
moduleName: 'ImageTileLayer',
vertexShader: ImageTileVert,
fragmentShader: ImageTileFrag,
triangulation: RasterImageTriangulation,
primitive: gl.TRIANGLES,
depth: { enable: false },
blend: this.getBlend(),
}),
];
}
public clearModels() {
this.tileLayer.removeTiles();
}
public buildModels() {
return this.initModels();
}
protected registerBuiltinAttributes() {
// point layer size;
this.styleAttributeService.registerStyleAttribute({
name: 'uv',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Uv',
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,
) => {
return [vertex[3], vertex[4]];
},
},
});
}
}

View File

@ -0,0 +1,8 @@
import ImageTileModel from './imagetile';
export type ImageTileModelType = 'imageTile';
const ImageTileModels: { [key in ImageTileModelType]: any } = {
imageTile: ImageTileModel,
};
export default ImageTileModels;

View File

@ -0,0 +1,4 @@
precision mediump float;
void main() {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}

View File

@ -0,0 +1,14 @@
precision highp float;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
attribute vec3 a_Position;
#pragma include "projection"
void main() {
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));
}
}

View File

@ -0,0 +1,9 @@
precision mediump float;
uniform float u_opacity: 1.0;
uniform sampler2D u_texture;
varying vec2 v_texCoord;
void main() {
vec4 color = texture2D(u_texture,vec2(v_texCoord.x,v_texCoord.y));
gl_FragColor = color;
gl_FragColor.a *= u_opacity;
}

View File

@ -0,0 +1,17 @@
precision highp float;
uniform mat4 u_ModelMatrix;
uniform mat4 u_Mvp;
attribute vec3 a_Position;
attribute vec2 a_Uv;
varying vec2 v_texCoord;
#pragma include "projection"
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));
}
}

View File

@ -0,0 +1,95 @@
import { LngLatBounds, toBounds, toLngLatBounds } from '@antv/geo-coord';
import { Container } from 'inversify';
import ImageLayer from '../../image';
interface IUrlParams {
x: number;
y: number;
z: number;
s?: string;
}
const r2d = 180 / Math.PI;
const tileURLRegex = /\{([zxy])\}/g;
export default class ImageTile {
public tile: number[]; // 当前图片瓦片的索引
public name: string;
public imageLayer: any;
constructor(
key: string,
url: string,
container: Container,
sceneContainer: Container,
) {
this.name = key;
this.tile = key.split('_').map((v) => Number(v));
const urlParams = {
x: this.tile[0],
y: this.tile[1],
z: this.tile[2],
};
const imageSrc = this.getTileURL(urlParams, url);
const lnglatBounds = this.tileLnglatBounds(this.tile);
const west = lnglatBounds.getWest();
const south = lnglatBounds.getSouth();
const east = lnglatBounds.getEast();
const north = lnglatBounds.getNorth();
const imageLayer = new ImageLayer({});
imageLayer.source(
// 'https://gw.alipayobjects.com/zos/rmsportal/FnHFeFklTzKDdUESRNDv.jpg',
imageSrc,
{
parser: {
type: 'image',
// extent: [121.168, 30.2828, 121.384, 30.4219],
extent: [west, south, east, north],
},
},
);
imageLayer.setContainer(container, sceneContainer);
imageLayer.init();
this.imageLayer = imageLayer;
}
public destroy() {
this.imageLayer.clearModels();
this.imageLayer.destroy();
}
public getTileURL(urlParams: IUrlParams, path: string) {
if (!urlParams.s) {
// Default to a random choice of a, b or c
urlParams.s = String.fromCharCode(97 + Math.floor(Math.random() * 3));
}
tileURLRegex.lastIndex = 0;
return path.replace(tileURLRegex, (value, key: any) => {
// @ts-ignore
return urlParams[key];
});
}
// Get tile bounds in WGS84 coordinates
public tileLnglatBounds(tile: number[]) {
const e = this.tile2lng(tile[0] + 1, tile[2]);
const w = this.tile2lng(tile[0], tile[2]);
const s = this.tile2lat(tile[1] + 1, tile[2]);
const n = this.tile2lat(tile[1], tile[2]);
return toLngLatBounds([w, n], [e, s]);
}
public tile2lng(x: number, z: number) {
return (x / Math.pow(2, z)) * 360 - 180;
}
public tile2lat(y: number, z: number) {
const n = Math.PI - (2 * Math.PI * y) / Math.pow(2, z);
return r2d * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)));
}
}

View File

@ -0,0 +1,359 @@
import { Bounds, GeoCoordinates, Point, toLngLat } from '@antv/geo-coord';
import {
createLayerContainer,
ILayer,
ILayerService,
ILngLat,
} from '@antv/l7-core';
import { Container } from 'inversify';
import ImageTile from './ImageTile';
import TileCache from './tileCache';
// Tip: 瓦片地图的存储上限
const CacheLimit = 30;
export default class Tile {
public tileList: any = {};
public tileCache: any;
public updateTileList: any[];
public tileZoom: number;
public noPruneRange: any;
public url: string;
public resolution: number;
public maxSourceZoom: number;
public crstype: string;
public currentCrs: any;
public layerService: ILayerService;
public layer: ILayer;
constructor(props: any) {
this.layerService = props.layerService;
this.layer = props.layer;
this.url = props.url;
this.resolution = props.resolution === 'low' ? -1 : 0;
this.maxSourceZoom = props.maxSourceZoom;
this.crstype = props.crstype;
this.currentCrs = new GeoCoordinates.default({
start: { x: 0, y: 0 },
end: { x: 0, y: 0 },
projection: this.crstype,
}).crs as any;
this.destroyTile = this.destroyTile.bind(this);
this.tileCache = new TileCache(CacheLimit, this.destroyTile);
this.updateTileList = [];
this.removeTiles = this.removeTiles.bind(this);
}
public calCurrentTiles(oprions: any) {
const {
NE,
SW,
tileCenter,
currentZoom,
minSourceZoom,
minZoom,
maxZoom,
} = oprions;
// TODO: 当前瓦片的层级要比地图底图的层级低
if (currentZoom >= this.maxSourceZoom) {
return;
}
const zoom = Math.floor(currentZoom) + this.resolution;
this.tileZoom = zoom > this.maxSourceZoom ? this.maxSourceZoom : zoom;
if (
currentZoom < minZoom ||
currentZoom >= maxZoom ||
currentZoom < minSourceZoom
) {
this.removeTiles();
return;
}
this.updateTileList = [];
// 计算瓦片中心
const centerPoint = this.currentCrs.lngLatToPoint(
toLngLat(tileCenter.lng, tileCenter.lat),
this.tileZoom,
);
const centerXY = centerPoint.divideBy(256).floor();
const pixelBounds = this.getPixelBounds(
NE,
SW,
tileCenter,
this.tileZoom,
this.currentCrs,
); // 计算像素范围
const tileRange = this.pxBoundsToTileRange(pixelBounds); // 计算瓦片范围
const margin = 4;
this.noPruneRange = new Bounds(
tileRange.getBottomLeft().subtract([margin, -margin]),
tileRange.getTopRight().add([margin, -margin]),
);
// T: isFinite(n: number) 用于检测 n 是否无穷大
if (
!(
isFinite(tileRange.min.x) &&
isFinite(tileRange.min.y) &&
isFinite(tileRange.max.x) &&
isFinite(tileRange.max.y)
)
) {
throw new Error('Attempted to load an infinite number of tiles');
}
// 根据视野判断新增的瓦片索引
for (let j = tileRange.min.y; j <= tileRange.max.y; j++) {
for (let i = tileRange.min.x; i <= tileRange.max.x; i++) {
const coords = [i, j, this.tileZoom];
const tile = this.tileList[coords.join('_')];
if (tile) {
tile.current = true;
} else {
this.tileList[coords.join('_')] = {
current: true,
coords,
};
this.updateTileList.push(coords);
}
}
}
// 瓦片列表排序
this.updateTileList.sort((a: any, b: any) => {
const tile1 = a;
const tile2 = b;
const d1 =
Math.pow(tile1[0] * 1 - centerXY.x, 2) +
Math.pow(tile1[1] * 1 - centerXY.y, 2);
const d2 =
Math.pow(tile2[0] * 1 - centerXY.x, 2) +
Math.pow(tile2[1] * 1 - centerXY.y, 2);
return d1 - d2;
});
this.pruneTiles();
this.updateTileList.forEach((coords: any) => {
const key = coords.join('_');
if (this.tileList[key].current) {
this.requestTile(key);
}
});
}
public pxBoundsToTileRange(pixelBounds: any) {
return new Bounds(
pixelBounds.min.divideBy(256).floor(),
pixelBounds.max
.divideBy(256)
.ceil()
.subtract([1, 1]),
);
}
public getPixelBounds(
NE: ILngLat,
SW: ILngLat,
tileCenter: ILngLat,
tileZoom: number,
crs: any,
) {
const zoom = tileZoom;
const NEPoint = crs.lngLatToPoint(toLngLat(NE.lng, NE.lat), zoom);
const SWPoint = crs.lngLatToPoint(toLngLat(SW.lng, SW.lat), zoom);
const centerPoint = crs.lngLatToPoint(
toLngLat(tileCenter.lng, tileCenter.lat),
zoom,
);
const topHeight = centerPoint.y - NEPoint.y;
const bottomHeight = SWPoint.y - centerPoint.y;
// 跨日界线的情况
let leftWidth;
let rightWidth;
if (tileCenter.lng - NE.lng > 0 || tileCenter.lng - SW.lng < 0) {
const width =
((Math.pow(2, zoom) * 256) / 360) * (180 - NE.lng) +
((Math.pow(2, zoom) * 256) / 360) * (SW.lng + 180);
if (tileCenter.lng - NE.lng > 0) {
// 日界线在右侧
leftWidth =
((Math.pow(2, zoom) * 256) / 360) * (tileCenter.lng - NE.lng);
rightWidth = width - leftWidth;
} else {
rightWidth =
((Math.pow(2, zoom) * 256) / 360) * (SW.lng - tileCenter.lng);
leftWidth = width - rightWidth;
}
} else {
// 不跨日界线
leftWidth = ((Math.pow(2, zoom) * 256) / 360) * (tileCenter.lng - SW.lng);
rightWidth =
((Math.pow(2, zoom) * 256) / 360) * (NE.lng - tileCenter.lng);
}
const pixelBounds = new Bounds(
centerPoint.subtract(leftWidth, topHeight),
centerPoint.add(rightWidth, bottomHeight),
);
return pixelBounds;
}
public pruneTiles() {
Object.keys(this.tileList).map((key) => {
const c = this.tileList[key].coords;
// 如果不是同一个缩放层级,则将瓦片设为不显示
if (
c[2] !== this.tileZoom ||
!this.noPruneRange.contains(new Point(c[0], c[1]))
) {
this.tileList[key].current = false;
}
});
Object.keys(this.tileList).map((key) => {
const tile = this.tileList[key];
tile.retain = tile.current;
});
Object.keys(this.tileList).map((key) => {
const tile = this.tileList[key];
if (tile.current && !tile.active) {
const [x, y, z] = key.split('_').map((v) => Number(v));
if (!this.retainParent(x, y, z, z - 5)) {
this.retainChildren(x, y, z, z + 2);
}
}
});
this.removeOutTiles();
}
public requestTile(key: string) {
const t = this.tileList[key];
if (!t) {
return;
}
let tile = this.tileCache.getTile(key);
if (!tile) {
const container = createLayerContainer(
this.layer.sceneContainer as Container,
);
tile = new ImageTile(
key,
this.url,
container,
this.layer.sceneContainer as Container,
);
tile.name = key;
t.current = true;
t.retain = true;
t.active = true;
// 往 imageTileLayer 中添加子图层
this.layer.layerChildren.push(tile.imageLayer);
this.tileCache.setTile(tile, key);
this.pruneTiles();
this.layerService.renderLayers();
} else {
// Tip: show 方法就是将相应的瓦片图片添加到渲染队列
tile.imageLayer.show();
t.current = true;
t.retain = true;
t.active = true;
this.pruneTiles();
}
}
public retainParent(x: number, y: number, z: number, minZoom: number): any {
const x2 = Math.floor(x / 2);
const y2 = Math.floor(y / 2);
const z2 = z - 1;
const tile = this.tileList[[x2, y2, z2].join('_')];
if (tile && tile.active) {
tile.retain = true;
return true;
} else if (tile && tile.loaded) {
tile.retain = true;
}
if (z2 > minZoom) {
return this.retainParent(x2, y2, z2, minZoom);
}
return false;
}
public retainChildren(x: number, y: number, z: number, maxZoom: number) {
for (let i = 2 * x; i < 2 * x + 2; i++) {
for (let j = 2 * y; j < 2 * y + 2; j++) {
const key = [i, j, z + 1].join('_');
const tile = this.tileList[key];
if (tile && tile.active) {
tile.retain = true;
continue;
} else if (tile && tile.loaded) {
tile.retain = true;
}
if (z + 1 < maxZoom) {
this.retainChildren(i, j, z + 1, maxZoom);
}
}
}
}
public destroyTile(tile: any) {
const layerIndex = this.layer.layerChildren.indexOf(tile.imageLayer);
if (layerIndex > -1) {
this.layer.layerChildren.splice(layerIndex, 1);
}
tile.imageLayer.emit('remove', null);
tile.imageLayer.destroy();
this.layerService.renderLayers();
// 清除 tileCache 中的存储 相当于 tileCache.setTile(tile, null)
tile = null;
}
public removeOutTiles() {
for (const key in this.tileList) {
if (!this.tileList[key].retain) {
// Tip: 不需要显示的瓦片对象
const tile = this.tileCache.getTile(key);
// Tip: 若是网格对象存在
if (tile) {
// Tip: hide 方法就是将相应的瓦片图片从渲染队列中剔除
tile.imageLayer.hide();
}
delete this.tileList[key];
}
}
}
public removeTiles() {
this.layer.layerChildren.forEach((layer: any) => {
layer.emit('remove', null);
layer.destroy();
});
this.layer.layerChildren = [];
this.layerService.renderLayers();
this.tileList = {};
this.tileCache.destory();
}
}

View File

@ -0,0 +1,80 @@
/**
* LRU Cache class with limit
*
* Update order for each get/set operation
* Delete oldest when reach given limit
*/
export default class LRUCache {
public limit: number;
public order: any[];
public cache: any;
public destroy: any;
constructor(limit = 50, destroy = () => '') {
this.limit = limit;
this.destroy = destroy;
this.order = [];
this.clear();
}
public clear() {
this.order.forEach((key: any) => {
this.delete(key);
});
this.cache = {};
// access/update order, first item is oldest, last item is newest
this.order = [];
}
public get(key: string) {
const value = this.cache[key];
if (value) {
// update order
this.deleteOrder(key);
this.appendOrder(key);
}
return value;
}
public set(key: string, value: any) {
if (!this.cache[key]) {
// if reach limit, delete the oldest
if (Object.keys(this.cache).length === this.limit) {
this.delete(this.order[0]);
}
this.cache[key] = value;
this.appendOrder(key);
} else {
// if found in cache, delete the old one, insert new one to the first of list
this.delete(key);
this.cache[key] = value;
this.appendOrder(key);
}
}
public delete(key: string) {
const value = this.cache[key];
if (value) {
this.deleteCache(key);
this.deleteOrder(key);
this.destroy(value, key);
}
}
public deleteCache(key: string) {
delete this.cache[key];
}
public deleteOrder(key: string) {
const index = this.order.findIndex((o) => o === key);
if (index >= 0) {
this.order.splice(index, 1);
}
}
public appendOrder(key: string) {
this.order.push(key);
}
}

View File

@ -0,0 +1,24 @@
import LRUCache from './lruCache';
export default class TileCache {
public cache: any;
constructor(limit = 50, tileDestroy: any) {
this.cache = new LRUCache(limit, tileDestroy);
}
public getTile(key: string) {
return this.cache.get(key);
}
public setTile(tile: any, key: string) {
this.cache.set(key, tile);
}
public destory() {
this.cache.clear();
}
public setNeedUpdate() {
this.cache.order.forEach((key: string) => {
const tile = this.cache.get(key);
tile.needUpdate = true;
});
}
}

View File

@ -4,6 +4,7 @@ import BaseLayer from './core/BaseLayer';
import './glsl.d';
import HeatmapLayer from './heatmap';
import ImageLayer from './image';
import ImageTileLayer from './imagetile';
import LineLayer from './line/index';
import PointLayer from './point';
import PolygonLayer from './polygon';
@ -25,6 +26,7 @@ import RegisterStyleAttributePlugin from './plugins/RegisterStyleAttributePlugin
import ShaderUniformPlugin from './plugins/ShaderUniformPlugin';
import UpdateModelPlugin from './plugins/UpdateModelPlugin';
import UpdateStyleAttributePlugin from './plugins/UpdateStyleAttributePlugin';
/**
*
* @see /dev-docs/ConfigSchemaValidation.md
@ -137,6 +139,7 @@ export {
LineLayer,
CityBuildingLayer,
ImageLayer,
ImageTileLayer,
RasterLayer,
HeatmapLayer,
EarthLayer,

View File

@ -31,6 +31,7 @@ export default class LineLayer extends BaseLayer<ILineLayerStyleOptions> {
line: {},
arc3d: { blend: 'additive' },
arc: { blend: 'additive' },
arcmini: { blend: 'additive' },
greatcircle: { blend: 'additive' },
};
return defaultConfig[type];

View File

@ -0,0 +1,134 @@
import {
AttributeType,
gl,
IAnimateOption,
IEncodeFeature,
ILayerConfig,
IModel,
IModelUniform,
} from '@antv/l7-core';
import { rgb2arr } from '@antv/l7-utils';
import { isNumber } from 'lodash';
import BaseModel from '../../core/BaseModel';
import { ILineLayerStyleOptions } from '../../core/interface';
import { LineArcTriangulation } from '../../core/triangulation';
import line_arcmini_frag from '../shaders/line_arcmini_frag.glsl';
import line_arcmini_vert from '../shaders/line_arcmini_vert.glsl';
export default class ArcMiniModel extends BaseModel {
public getUninforms(): IModelUniform {
const {
opacity,
sourceColor,
targetColor,
forward = true,
segmentNumber = 30,
thetaOffset = 0.314,
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
// 转化渐变色
let useLinearColor = 0; // 默认不生效
let sourceColorArr = [0, 0, 0, 0];
let targetColorArr = [0, 0, 0, 0];
if (sourceColor && targetColor) {
sourceColorArr = rgb2arr(sourceColor);
targetColorArr = rgb2arr(targetColor);
useLinearColor = 1;
}
return {
u_thetaOffset: thetaOffset,
u_opacity: isNumber(opacity) ? opacity : 1.0,
segmentNumber,
u_blur: 0.9,
u_lineDir: forward ? 1 : -1,
// 渐变色支持参数
u_linearColor: useLinearColor,
u_sourceColor: sourceColorArr,
u_targetColor: targetColorArr,
};
}
public getAnimateUniforms(): IModelUniform {
const { animateOption } = this.layer.getLayerConfig() as ILayerConfig;
return {
u_aimate: this.animateOption2Array(animateOption as IAnimateOption),
u_time: this.layer.getLayerAnimateTime(),
};
}
public initModels(): IModel[] {
return this.buildModels();
}
public buildModels(): IModel[] {
const {
segmentNumber = 30,
} = this.layer.getLayerConfig() as ILineLayerStyleOptions;
return [
this.layer.buildLayerModel({
moduleName: 'arc2dminiline',
vertexShader: line_arcmini_vert,
fragmentShader: line_arcmini_frag,
triangulation: LineArcTriangulation,
depth: { enable: false },
blend: this.getBlend(),
segmentNumber,
}),
];
}
protected registerBuiltinAttributes() {
// point layer size;
this.styleAttributeService.registerStyleAttribute({
name: 'size',
type: AttributeType.Attribute,
descriptor: {
name: 'a_Size',
buffer: {
// give the WebGL driver a hint that this buffer may change
usage: gl.DYNAMIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 1,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
const { size = 1 } = feature;
return Array.isArray(size) ? [size[0]] : [size as number];
},
},
});
this.styleAttributeService.registerStyleAttribute({
name: 'instance', // 弧线起始点信息
type: AttributeType.Attribute,
descriptor: {
name: 'a_Instance',
buffer: {
usage: gl.STATIC_DRAW,
data: [],
type: gl.FLOAT,
},
size: 4,
update: (
feature: IEncodeFeature,
featureIdx: number,
vertex: number[],
attributeIdx: number,
) => {
return [vertex[3], vertex[4], vertex[5], vertex[6]];
},
},
});
}
}

View File

@ -1,12 +1,19 @@
import ArcModel from './arc';
import Arc3DModel from './arc_3d';
import ArcMiniModel from './arcmini';
import GreatCircleModel from './great_circle';
import LineModel from './line';
export type LineModelType = 'arc' | 'arc3d' | 'greatcircle' | 'line';
export type LineModelType =
| 'arc'
| 'arcmini'
| 'arc3d'
| 'greatcircle'
| 'line';
const LineModels: { [key in LineModelType]: any } = {
arc: ArcModel,
arcmini: ArcMiniModel,
arc3d: Arc3DModel,
greatcircle: GreatCircleModel,
line: LineModel,

View File

@ -17,8 +17,6 @@ uniform vec2 u_textSize;
varying float v_segmentIndex;
uniform float segmentNumber;
varying vec4 v_dataset; // 数据集
varying vec2 v_iconMapUV;
uniform float u_time;
@ -35,7 +33,7 @@ varying mat4 styleMappingMat;
void main() {
float opacity = styleMappingMat[0][0];
float animateSpeed = 0.0; // 运动速度
float d_distance_ratio = v_dataset.g; // 当前点位距离占线总长的比例
float d_distance_ratio = styleMappingMat[3].g; // 当前点位距离占线总长的比例
if(u_linearColor == 1.0) { // 使用渐变颜色
gl_FragColor = mix(u_sourceColor, u_targetColor, v_segmentIndex/segmentNumber);
@ -68,7 +66,7 @@ void main() {
if(u_line_texture == LineTexture && u_line_type != LineTypeDash) { // while load texture
// float arcRadio = smoothstep( 0.0, 1.0, (v_segmentIndex / segmentNumber));
float arcRadio = v_segmentIndex / (segmentNumber - 1.0);
float count = v_dataset.b; // // 贴图在弧线上重复的数量
float count = styleMappingMat[3].b; // // 贴图在弧线上重复的数量
float u = fract(arcRadio * count - animateSpeed * count);
@ -76,7 +74,7 @@ void main() {
u = gl_FragColor.a/opacity;
}
float v = v_dataset.a; // 线图层贴图部分的 v 坐标值
float v = styleMappingMat[3].a; // 线图层贴图部分的 v 坐标值
vec2 uv= v_iconMapUV / u_textSize + vec2(u, v) / u_textSize * 64.;
vec4 pattern = texture2D(u_texture, uv);

View File

@ -24,8 +24,6 @@ uniform float u_icon_step: 100;
uniform float u_line_texture: 0.0;
varying float v_segmentIndex;
varying vec4 v_dataset; // 数据集
attribute vec2 a_iconMapUV;
varying vec2 v_iconMapUV;
@ -106,7 +104,7 @@ void main() {
0.0, 0.0, 0.0, 0.0, // opacity - strokeOpacity - strokeWidth - empty
0.0, 0.0, 0.0, 0.0, // strokeR - strokeG - strokeB - strokeA
0.0, 0.0, 0.0, 0.0, // offsets[0] - offsets[1]
0.0, 0.0, 0.0, 0.0
0.0, 0.0, 0.0, 0.0 // dataset 数据集
);
float rowCount = u_cellTypeLayout[0][0]; // 当前的数据纹理有几行
@ -151,7 +149,7 @@ void main() {
if(u_aimate.x == Animate) {
d_distance_ratio = segmentIndex / segmentNumber;
}
v_dataset.g = d_distance_ratio; // 当前点位距离占线总长的比例
styleMappingMat[3].g = d_distance_ratio; // 当前点位距离占线总长的比例
float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
vec3 curr = getPos(source, target, segmentRatio);
@ -165,12 +163,12 @@ void main() {
float arcDistrance = length(source - target);
float pixelLen = project_pixel(u_icon_step);
v_dataset.b = floor(arcDistrance/pixelLen); // 贴图在弧线上重复的数量
styleMappingMat[3].b = floor(arcDistrance/pixelLen); // 贴图在弧线上重复的数量
vec2 projectOffset = project_pixel(offset);
float lineOffsetWidth = length(projectOffset + projectOffset * sign(a_Position.y)); // 线横向偏移的距离
float linePixelSize = project_pixel(a_Size); // 定点位置偏移,按地图等级缩放后的距离
v_dataset.a = lineOffsetWidth/linePixelSize; // 线图层贴图部分的 v 坐标值
styleMappingMat[3].a = lineOffsetWidth/linePixelSize; // 线图层贴图部分的 v 坐标值
v_iconMapUV = a_iconMapUV;
}

View File

@ -21,8 +21,6 @@ uniform vec2 u_textSize;
uniform float segmentNumber;
varying vec2 v_iconMapUV;
varying vec4 v_dataset; // 数据集 - 用于合并单个的 varying 变量
varying mat4 styleMappingMat; // 传递从片元中传递的映射数据
uniform float u_linearColor: 0;
@ -34,8 +32,8 @@ uniform vec4 u_targetColor;
void main() {
float opacity = styleMappingMat[0][0];
float animateSpeed = 0.0; // 运动速度
float d_segmentIndex = v_dataset.r; // 当前顶点在弧线中所处的分段位置
float d_distance_ratio = v_dataset.b; // 当前顶点在弧线中所处的分段比例
float d_segmentIndex = styleMappingMat[3].r; // 当前顶点在弧线中所处的分段位置
float d_distance_ratio = styleMappingMat[3].b; // 当前顶点在弧线中所处的分段比例
// 设置弧线的底色
if(u_linearColor == 1.0) { // 使用渐变颜色
@ -70,14 +68,14 @@ void main() {
float arcRadio = smoothstep( 0.0, 1.0, (d_segmentIndex / segmentNumber));
// float arcRadio = smoothstep( 0.0, 1.0, d_distance_ratio);
float d_texCount = v_dataset.g; // 贴图在弧线上重复的数量
float d_texCount = styleMappingMat[3].g; // 贴图在弧线上重复的数量
float u = 1.0 - fract(arcRadio * d_texCount + animateSpeed);
if(u_aimate.x == Animate) {
u = gl_FragColor.a/opacity;
}
float v = v_dataset.a; // 横向 v
float v = styleMappingMat[3].a; // 横向 v
vec2 uv= v_iconMapUV / u_textSize + vec2(u, v) / u_textSize * 64.;
vec4 pattern = texture2D(u_texture, uv);

View File

@ -20,8 +20,6 @@ uniform sampler2D u_texture;
uniform vec2 u_textSize;
uniform float segmentNumber;
varying vec4 v_dataset; // 数据集
varying vec2 v_iconMapUV;
uniform float u_linearColor: 0;
@ -37,7 +35,7 @@ varying mat4 styleMappingMat;
void main() {
float opacity = styleMappingMat[0][0];
float animateSpeed = 0.0;
float d_segmentIndex = v_dataset.g;
float d_segmentIndex = styleMappingMat[3].g;
// 设置弧线的底色
if(u_linearColor == 1.0) { // 使用渐变颜色
@ -71,14 +69,14 @@ void main() {
if(LineTexture == u_line_texture && u_line_type != LineTypeDash) {
float arcRadio = smoothstep( 0.0, 1.0, (d_segmentIndex / (segmentNumber - 1.0)));
// float arcRadio = d_segmentIndex / (segmentNumber - 1.0);
float count = v_dataset.b; // 贴图在弧线上重复的数量
float count = styleMappingMat[3].b; // 贴图在弧线上重复的数量
float u = fract(arcRadio * count - animateSpeed * count);
// float u = fract(arcRadio * count - animateSpeed);
if(u_aimate.x == Animate) {
u = gl_FragColor.a/opacity;
}
float v = v_dataset.a; // 线图层贴图部分的 v 坐标值
float v = styleMappingMat[3].a; // 线图层贴图部分的 v 坐标值
vec2 uv= v_iconMapUV / u_textSize + vec2(u, v) / u_textSize * 64.;
vec4 pattern = texture2D(u_texture, uv);

View File

@ -22,8 +22,6 @@ varying vec4 v_dash_array;
uniform float u_icon_step: 100;
uniform float u_line_texture: 0.0;
varying vec4 v_dataset; // 数据集
attribute vec2 a_iconMapUV;
varying vec2 v_iconMapUV;
@ -131,7 +129,7 @@ void main() {
0.0, 0.0, 0.0, 0.0, // opacity - strokeOpacity - strokeWidth - empty
0.0, 0.0, 0.0, 0.0, // strokeR - strokeG - strokeB - strokeA
0.0, 0.0, 0.0, 0.0, // offsets[0] - offsets[1]
0.0, 0.0, 0.0, 0.0
0.0, 0.0, 0.0, 0.0 // dataset 数据集
);
float rowCount = u_cellTypeLayout[0][0]; // 当前的数据纹理有几行
@ -185,7 +183,7 @@ void main() {
// 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));
v_dataset.g = a_Position.x; // 该顶点在弧线上的分段排序
styleMappingMat[3].g = a_Position.x; // 该顶点在弧线上的分段排序
if(LineTexture == u_line_texture) { // 开启贴图模式
// float mapZoomScale = u_CoordinateSystem !== COORDINATE_SYSTEM_P20_2?10000000.0:1.0;
float d_arcDistrance = length(source - target);
@ -196,11 +194,11 @@ void main() {
d_arcDistrance = project_pixel_allmap(d_arcDistrance);
}
float d_pixelLen = project_pixel(u_icon_step)/8.0;
v_dataset.b = floor(d_arcDistrance/d_pixelLen); // 贴图在弧线上重复的数量
styleMappingMat[3].b = floor(d_arcDistrance/d_pixelLen); // 贴图在弧线上重复的数量
float lineOffsetWidth = length(offset + offset * sign(a_Position.y)); // 线横向偏移的距离
float linePixelSize = project_pixel(a_Size); // 定点位置偏移,按地图等级缩放后的距离
v_dataset.a = lineOffsetWidth/linePixelSize; // 线图层贴图部分的 v 坐标值
styleMappingMat[3].a = lineOffsetWidth/linePixelSize; // 线图层贴图部分的 v 坐标值
v_iconMapUV = a_iconMapUV;
}

View File

@ -25,8 +25,6 @@ uniform float u_line_texture: 0.0;
attribute vec2 a_iconMapUV;
varying vec2 v_iconMapUV;
varying vec4 v_dataset; // 数据集 - 用于合并单个的 varying 变量
uniform float u_opacity: 1.0;
varying mat4 styleMappingMat; // 用于将在顶点着色器中计算好的样式值传递给片元
@ -92,7 +90,7 @@ void main() {
0.0, 0.0, 0.0, 0.0, // opacity - strokeOpacity - strokeWidth - empty
0.0, 0.0, 0.0, 0.0, // strokeR - strokeG - strokeB - strokeA
0.0, 0.0, 0.0, 0.0, // offsets[0] - offsets[1]
0.0, 0.0, 0.0, 0.0
0.0, 0.0, 0.0, 0.0 // dataset 数据集
);
float rowCount = u_cellTypeLayout[0][0]; // 当前的数据纹理有几行
@ -144,7 +142,7 @@ void main() {
}
}
v_dataset.b = d_distance_ratio;
styleMappingMat[3].b = d_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));
@ -155,7 +153,7 @@ void main() {
float d_segmentIndex = a_Position.x + 1.0; // 当前顶点在弧线中所处的分段位置
v_dataset.r = d_segmentIndex;
styleMappingMat[3].r = d_segmentIndex;
if(LineTexture == u_line_texture) { // 开启贴图模式
@ -171,11 +169,11 @@ void main() {
float pixelLen = project_pixel(u_icon_step); // 贴图沿弧线方向的长度 - 随地图缩放改变
float texCount = floor(arcDistrance/pixelLen); // 贴图在弧线上重复的数量
v_dataset.g = texCount;
styleMappingMat[3].g = texCount;
float lineOffsetWidth = length(offset + offset * sign(a_Position.y)); // 线横向偏移的距离
float linePixelSize = project_pixel(a_Size); // 定点位置偏移
v_dataset.a = lineOffsetWidth/linePixelSize; // 线图层贴图部分的 v 坐标值
styleMappingMat[3].a = lineOffsetWidth/linePixelSize; // 线图层贴图部分的 v 坐标值
}

View File

@ -0,0 +1,42 @@
#define LineTypeSolid 0.0
#define Animate 0.0
uniform float u_opacity;
uniform float u_blur : 0.9;
// varying vec2 v_normal;
varying vec4 v_color;
uniform float u_time;
uniform vec4 u_aimate: [ 0, 2., 1.0, 0.2 ];
uniform float segmentNumber;
varying float v_distance_ratio;
uniform float u_linearColor: 0;
uniform vec4 u_sourceColor;
uniform vec4 u_targetColor;
#pragma include "picking"
void main() {
// 设置弧线的底色
if(u_linearColor == 1.0) { // 使用渐变颜色
gl_FragColor = mix(u_sourceColor, u_targetColor, v_distance_ratio);
} else { // 使用 color 方法传入的颜色
gl_FragColor = v_color;
}
gl_FragColor.a *= u_opacity;
if(u_aimate.x == Animate) {
float 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) + u_time / u_aimate.y);
alpha = (alpha + u_aimate.w -1.0) / u_aimate.w;
// alpha = smoothstep(0., 1., alpha);
alpha = clamp(alpha, 0.0, 1.0);
gl_FragColor.a *= alpha;
}
gl_FragColor = filterColor(gl_FragColor);
}

View File

@ -0,0 +1,105 @@
#define LineTypeSolid 0.0
#define LineTypeDash 1.0
#define Animate 0.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;
// varying vec2 v_normal;
uniform float u_lineDir: 1.0;
// 偏移量
uniform float u_thetaOffset: 0.314;
uniform float u_opacity: 1.0;
varying float v_distance_ratio;
#pragma include "projection"
#pragma include "project"
#pragma include "picking"
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 midPoint(vec2 source, vec2 target) {
vec2 center = target - source;
float r = length(center);
float theta = atan(center.y, center.x);
float thetaOffset = u_thetaOffset;
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.));
}
vec2 interpolate (vec2 source, vec2 target, float t) {
// if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation
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));
}
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction) {
// normalized direction of the line
vec2 dir_screenspace = normalize(line_clipspace);
// rotate by 90 degrees
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
vec2 offset = dir_screenspace * offset_direction * setPickingSize(a_Size) / 2.0;
return offset;
}
vec2 getNormal(vec2 line_clipspace, float offset_direction) {
// normalized direction of the line
vec2 dir_screenspace = normalize(line_clipspace);
// rotate by 90 degrees
dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);
return reverse_offset_normal(vec3(dir_screenspace,1.0)).xy * sign(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);
v_distance_ratio = segmentIndex / segmentNumber;
if(u_aimate.x == Animate && 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);
//unProjCustomCoord
vec2 offset = project_pixel(getExtrusionOffset((next.xy - curr.xy) * indexDir, a_Position.y));
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);
}

View File

@ -7,7 +7,7 @@ uniform float u_line_type: 0.0;
uniform float u_opacity : 1.0;
uniform float u_textureBlend;
varying vec4 v_color;
varying vec2 v_normal;
// varying vec2 v_normal;
// line texture
uniform float u_line_texture;
@ -19,8 +19,6 @@ uniform float u_dash_offset : 0.0;
uniform float u_dash_ratio : 0.1;
varying vec4 v_dash_array;
varying vec4 v_dataset; // 数据集 - distance_ratio/distance/pixelLen/texV
varying vec2 v_iconMapUV;
uniform float u_linearColor: 0;
@ -37,7 +35,7 @@ varying mat4 styleMappingMat;
void main() {
float opacity = styleMappingMat[0][0];
float animateSpeed = 0.0; // 运动速度
float d_distance_ratio = v_dataset.r; // 当前点位距离占线总长的比例
float d_distance_ratio = styleMappingMat[3].r; // 当前点位距离占线总长的比例
if(u_linearColor == 1.0) { // 使用渐变颜色
gl_FragColor = mix(u_sourceColor, u_targetColor, d_distance_ratio);
@ -66,13 +64,14 @@ void main() {
}
if(u_line_texture == LineTexture && u_line_type != LineTypeDash) { // while load texture
float aDistance = v_dataset.g; // 当前顶点的距离
float d_texPixelLen = v_dataset.b; // 贴图的像素长度,根据地图层级缩放
float aDistance = styleMappingMat[3].g; // 当前顶点的距离
float d_texPixelLen = styleMappingMat[3].b; // 贴图的像素长度,根据地图层级缩放
float u = fract(mod(aDistance, d_texPixelLen)/d_texPixelLen - animateSpeed);
float v = v_dataset.a; // 线图层贴图部分的 v 坐标值
float v = styleMappingMat[3].a; // 线图层贴图部分的 v 坐标值
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));
vec4 pattern = texture2D(u_texture, uv);
@ -90,13 +89,14 @@ void main() {
} else {
gl_FragColor = filterColor(gl_FragColor);
}
// gl_FragColor = filterColor(vec4(1.0, 0.0, 0.0, 1.0));
// gl_FragColor = (vec4(1.0, 0.0, 0.0, 1.0));
// if(rV < r || rV > 1.0 - r) {
// gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
// }
// if(v > 0.9) {
// gl_FragColor = vec4(0.17647, 0.43921568, 0.2, 1.0);
// 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);
// }

View File

@ -28,9 +28,10 @@ varying vec4 v_color;
varying vec4 v_dash_array;
varying vec2 v_normal;
varying vec4 v_dataset; // 数据集 - distance_ratio/distance/pixelLen/texV
// texV 线图层 - 贴图部分的 v 坐标(线的宽度方向)
varying vec2 v_iconMapUV;
uniform float u_linearColor: 0;
uniform float u_opacity: 1.0;
@ -45,7 +46,7 @@ void main() {
0.0, 0.0, 0.0, 0.0, // opacity - strokeOpacity - strokeWidth - empty
0.0, 0.0, 0.0, 0.0, // strokeR - strokeG - strokeB - strokeA
0.0, 0.0, 0.0, 0.0, // offsets[0] - offsets[1]
0.0, 0.0, 0.0, 0.0
0.0, 0.0, 0.0, 0.0 // distance_ratio/distance/pixelLen/texV
);
float rowCount = u_cellTypeLayout[0][0]; // 当前的数据纹理有几行
@ -84,7 +85,6 @@ void main() {
}
v_normal = vec2(reverse_offset_normal(a_Normal) * sign(a_Miter));
v_color = a_Color;
vec3 size = a_Miter * setPickingSize(a_Size.x) * reverse_offset_normal(a_Normal);
@ -96,10 +96,10 @@ void main() {
float texV = lineOffsetWidth/linePixelSize; // 线图层贴图部分的 v 坐标值
// 设置数据集的参数
v_dataset.r = d_distance_ratio; // 当前点位距离占线总长的比例
v_dataset.g = a_Distance; // 当前顶点的距离
v_dataset.b = d_texPixelLen; // 贴图的像素长度,根据地图层级缩放
v_dataset.a = texV; // 线图层贴图部分的 v 坐标值
styleMappingMat[3][0] = d_distance_ratio; // 当前点位距离占线总长的比例
styleMappingMat[3][1] = a_Distance; // 当前顶点的距离
styleMappingMat[3][2] = d_texPixelLen; // 贴图的像素长度,根据地图层级缩放
styleMappingMat[3][3] = texV; // 线图层贴图部分的 v 坐标值
vec4 project_pos = project_position(vec4(a_Position.xy, 0, 1.0));

View File

@ -5,9 +5,8 @@ import {
IMapService,
TYPES,
} from '@antv/l7-core';
import Source from '@antv/l7-source';
import Source, { DEFAULT_DATA, DEFAULT_PARSER } from '@antv/l7-source';
import { injectable } from 'inversify';
import { cloneDeep } from 'lodash';
import 'reflect-metadata';
@injectable()
@ -18,7 +17,11 @@ export default class DataSourcePlugin implements ILayerPlugin {
layer.hooks.init.tap('DataSourcePlugin', () => {
const source = layer.getSource();
if (!source) {
const { data, options } = layer.sourceOption;
// TODO: 允许用户不使用 layer 的 source 方法,在这里传入一个默认的替换的默认数据
const { data, options } = layer.sourceOption || {
data: DEFAULT_DATA,
options: DEFAULT_PARSER,
};
layer.setSource(new Source(data, options));
}

View File

@ -78,6 +78,8 @@ export default class ShaderUniformPlugin implements ILayerPlugin {
// u_ModelMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
u_ModelMatrix: this.cameraService.getModelMatrix(),
u_PickingBuffer: layer.getLayerConfig().pickingBuffer || 0,
// TODO: 当前地图是否在拖动
u_Dragging: Number(this.mapService.dragging),
});
});

View File

@ -9,7 +9,6 @@ import {
IModel,
IModelUniform,
} from '@antv/l7-core';
import { rgb2arr } from '@antv/l7-utils';
import BaseModel, {
styleColor,
styleOffset,
@ -22,7 +21,7 @@ import {
import pointFillFrag from '../shaders/fill_frag.glsl';
import pointFillVert from '../shaders/fill_vert.glsl';
import { isNumber, isString } from 'lodash';
import { isNumber } from 'lodash';
import { mat4, vec3 } from 'gl-matrix';
@ -32,7 +31,6 @@ interface IPointLayerStyleOptions {
stroke: styleColor;
strokeOpacity: styleSingle;
offsets: styleOffset;
isGlobel?: boolean;
}
// 判断当前使用的 style 中的变量属性是否需要进行数据映射
export default class FillModel extends BaseModel {
@ -43,8 +41,6 @@ export default class FillModel extends BaseModel {
strokeWidth = 0,
stroke = 'rgba(0,0,0,0)',
offsets = [0, 0],
// TODO: 判断当前图层是否为地球模式
isGlobel = false,
} = this.layer.getLayerConfig() as IPointLayerStyleOptions;
if (

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-map",
"version": "2.5.30",
"version": "2.5.41",
"description": "l7 map",
"keywords": [],
"author": "thinkinggis <lzx199065@gmail.com>",
@ -37,7 +37,7 @@
},
"homepage": "https://github.com/antvis/L7#readme",
"dependencies": {
"@antv/l7-utils": "^2.5.30",
"@antv/l7-utils": "^2.5.41",
"@babel/runtime": "^7.7.7",
"@mapbox/point-geometry": "^0.1.0",
"@mapbox/unitbezier": "^0.0.0",

View File

@ -307,7 +307,7 @@ class ScrollZoomHandler {
private onTimeout(initialEvent: any) {
this.type = 'wheel';
this.delta -= this.lastValue;
if (!this.active) {
if (!this.active && this.start) {
this.start(initialEvent);
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-maps",
"version": "2.5.30",
"version": "2.5.41",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
@ -27,9 +27,9 @@
"license": "ISC",
"dependencies": {
"@amap/amap-jsapi-loader": "^0.0.3",
"@antv/l7-core": "^2.5.30",
"@antv/l7-map": "^2.5.30",
"@antv/l7-utils": "^2.5.30",
"@antv/l7-core": "^2.5.41",
"@antv/l7-map": "^2.5.41",
"@antv/l7-utils": "^2.5.41",
"@babel/runtime": "^7.7.7",
"@types/amap-js-api": "^1.4.6",
"@types/mapbox-gl": "^1.11.2",

View File

@ -61,6 +61,12 @@ export default class AMapService
*/
public map: AMap.Map & IAMapInstance;
// TODO: 判断地图是否正在拖拽
public dragging: boolean = false;
// 背景色
public bgColor: string = 'rgba(0, 0, 0, 0)';
@inject(TYPES.IGlobalConfigService)
private readonly configService: IGlobalConfigService;
@ -79,6 +85,9 @@ export default class AMapService
private viewport: Viewport;
private cameraChangedCallback: (viewport: IViewport) => void;
public setBgColor(color: string) {
this.bgColor = color;
}
public addMarkerContainer(): void {
const mapContainer = this.map.getContainer();
@ -397,6 +406,16 @@ export default class AMapService
}
});
// TODO: 判断地图是否正在被拖拽
this.map.on('dragstart', () => {
this.dragging = true;
return '';
});
this.map.on('dragend', () => {
this.dragging = false;
return '';
});
this.viewport = new Viewport();
}
@ -453,6 +472,8 @@ export default class AMapService
position,
} = e.camera;
const { lng, lat } = this.getCenter();
// Tip: 触发地图变化事件
this.emit('mapchange');
if (this.cameraChangedCallback) {
// resync viewport
// console.log('cameraHeight', height)

View File

@ -64,12 +64,18 @@ export default class AMapService
*/
public map: AMap.Map & IAMapInstance;
// TODO: 判断地图是否正在拖拽
public dragging: boolean = false;
/**
* customCooords
*/
public sceneCenter!: [number, number]; // 一般使用用户数据的第一个
public sceneCenterMKT!: [number, number]; // 莫卡托
// 背景色
public bgColor: string = 'rgba(0, 0, 0, 0)';
@inject(TYPES.IGlobalConfigService)
private readonly configService: IGlobalConfigService;
@ -88,6 +94,9 @@ export default class AMapService
private viewport: Viewport;
private cameraChangedCallback: (viewport: IViewport) => void;
public setBgColor(color: string) {
this.bgColor = color;
}
/**
* 2.0
@ -145,15 +154,17 @@ export default class AMapService
}
const mapContainer = this.map.getContainer();
if (mapContainer !== null) {
// const amap = mapContainer.getElementsByClassName(
// 'amap-maps',
// )[0] as HTMLElement;
// this.markerContainer = DOM.create('div', 'l7-marker-container2', amap);
this.markerContainer = DOM.create(
'div',
'l7-marker-container2',
mapContainer,
);
const amap = mapContainer.getElementsByClassName(
'amap-maps',
)[0] as HTMLElement;
// TODO: amap2 的 amap-maps 新增 z-index=0; 样式,让 marker 中 zIndex 失效
amap.style.zIndex = 'auto';
this.markerContainer = DOM.create('div', 'l7-marker-container2', amap);
// this.markerContainer = DOM.create(
// 'div',
// 'l7-marker-container2',
// mapContainer,
// );
// this.markerContainer = mapContainer;
}
}
@ -486,6 +497,16 @@ export default class AMapService
}
}
});
// TODO: 判断地图是否正在被拖拽
this.map.on('dragstart', () => {
this.dragging = true;
return '';
});
this.map.on('dragend', () => {
this.dragging = false;
return '';
});
}
public exportMap(type: 'jpg' | 'png'): string {
@ -550,6 +571,8 @@ export default class AMapService
// left, right, bottom, top
// @ts-ignore
} = this.map.customCoords?.getCameraParams();
// Tip: 统一触发地图变化事件
this.emit('mapchange');
// // @ts-ignore
// console.log('this.map.customCoords.getCameraParams()', this.map.customCoords.getCameraParams())
// const { left, right, bottom, top, near, far, position } = this.map.customCoords.getCameraParams();
@ -612,6 +635,9 @@ export default class AMapService
// left, right, bottom, top
// @ts-ignore
} = this.map.customCoords.getCameraParams();
// Tip: 统一触发地图变化事件
this.emit('mapchange');
const { zoom } = e;
// @ts-ignore
const center = this.map.customCoords.getCenter() as [number, number];

View File

@ -2,6 +2,11 @@ import { IMapCamera, IViewport } from '@antv/l7-core';
import { mat4, vec3 } from 'gl-matrix';
import WebMercatorViewport from 'viewport-mercator-project';
export interface IEarthCamera {
viewportHeight: number;
viewportWidth: number;
}
export default class Viewport implements IViewport {
// TODO: 初始化相机的姿态 看向地球
private xzReg: number = -Math.PI * 0.6;
@ -21,7 +26,7 @@ export default class Viewport implements IViewport {
private ViewProjectionMatrixUncentered: mat4 = mat4.create();
private viewUncenteredMatrix: mat4 = mat4.create();
public syncWithMapCamera(mapCamera: Partial<IMapCamera>) {
public syncWithMapCamera(mapCamera: Partial<IEarthCamera>) {
const { viewportHeight = 1, viewportWidth = 1 } = mapCamera;
const aspect = viewportWidth / viewportHeight;
const near = 0.1;

View File

@ -5,10 +5,10 @@ import {
Bounds,
CoordinateSystem,
ICoordinateSystemService,
IEarthService,
IGlobalConfigService,
ILngLat,
IMapConfig,
IMapService,
IMercator,
IPoint,
IStatusOptions,
@ -38,10 +38,16 @@ const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
* AMapService
*/
@injectable()
export default class L7MapService implements IMapService<Map> {
export default class L7EarthService implements IEarthService<Map> {
public version: string = Version.GLOBEL;
public map: Map;
// TODO: 判断地图是否正在拖拽
public dragging: boolean = false;
// 背景色
public bgColor: string = '#000';
@inject(TYPES.MapConfig)
private readonly config: Partial<IMapConfig>;
@ -60,7 +66,9 @@ export default class L7MapService implements IMapService<Map> {
// T: 用于记录鼠标对相机的控制
private handleCameraChanging: boolean;
private handleCameraTimer: any;
public setBgColor(color: string) {
this.bgColor = color;
}
// init
public addMarkerContainer(): void {
const container = this.map.getCanvasContainer();
@ -323,18 +331,17 @@ export default class L7MapService implements IMapService<Map> {
this.viewport.rotateY(reg);
this.viewport.syncWithMapCamera({
bearing: this.map.getBearing(),
viewportHeight: this.map.transform.height,
pitch: this.map.getPitch(),
viewportWidth: this.map.transform.width,
zoom: this.map.getZoom(),
// mapbox 中固定相机高度为 viewport 高度的 1.5 倍
cameraHeight: 0,
});
this.cameraChangedCallback(this.viewport);
}
}
private handleCameraChanged = (e: any) => {
// Tip: 统一触发地图变化事件
this.emit('mapchange');
const DELAY_TIME = 2000;
this.handleCameraChanging = true;
if (this.handleCameraTimer) {
@ -374,13 +381,8 @@ export default class L7MapService implements IMapService<Map> {
// resync
this.viewport.syncWithMapCamera({
bearing: this.map.getBearing(),
viewportHeight: this.map.transform.height,
pitch: this.map.getPitch(),
viewportWidth: this.map.transform.width,
zoom: this.map.getZoom(),
// mapbox 中固定相机高度为 viewport 高度的 1.5 倍
cameraHeight: 0,
});
// set coordinate system
if (

View File

@ -43,6 +43,12 @@ export default class L7MapService implements IMapService<Map> {
public version: string = Version.L7MAP;
public map: Map;
// TODO: 判断地图是否正在拖拽
public dragging: boolean = false;
// 背景色
public bgColor: string = 'rgba(0.0, 0.0, 0.0, 0.0)';
@inject(TYPES.MapConfig)
private readonly config: Partial<IMapConfig>;
@ -58,6 +64,9 @@ export default class L7MapService implements IMapService<Map> {
private markerContainer: HTMLElement;
private cameraChangedCallback: (viewport: IViewport) => void;
private $mapContainer: HTMLElement | null;
public setBgColor(color: string) {
this.bgColor = color;
}
// init
public addMarkerContainer(): void {
@ -274,6 +283,16 @@ export default class L7MapService implements IMapService<Map> {
this.map.on('load', this.handleCameraChanged);
this.map.on('move', this.handleCameraChanged);
// TODO: 判断地图是否正在被拖拽
this.map.on('dragstart', () => {
this.dragging = true;
return '';
});
this.map.on('dragend', () => {
this.dragging = false;
return '';
});
// 不同于高德地图,需要手动触发首次渲染
this.handleCameraChanged();
}
@ -314,7 +333,8 @@ export default class L7MapService implements IMapService<Map> {
private handleCameraChanged = () => {
const { lat, lng } = this.map.getCenter();
const { offsetCoordinate = true } = this.config;
// Tip: 统一触发地图变化事件
this.emit('mapchange');
// resync
this.viewport.syncWithMapCamera({
bearing: this.map.getBearing(),

View File

@ -50,6 +50,12 @@ export default class MapboxService
public version: string = Version.MAPBOX;
public map: Map & IMapboxInstance;
// TODO: 判断地图是否正在拖拽
public dragging: boolean = false;
// 背景色
public bgColor: string = 'rgba(0.0, 0.0, 0.0, 0.0)';
@inject(TYPES.MapConfig)
private readonly config: Partial<IMapConfig>;
@ -65,6 +71,9 @@ export default class MapboxService
private markerContainer: HTMLElement;
private cameraChangedCallback: (viewport: IViewport) => void;
private $mapContainer: HTMLElement | null;
public setBgColor(color: string) {
this.bgColor = color;
}
// init
public addMarkerContainer(): void {
@ -357,6 +366,16 @@ export default class MapboxService
this.map.on('load', this.handleCameraChanged);
this.map.on('move', this.handleCameraChanged);
// TODO: 判断地图是否正在被拖拽
this.map.on('dragstart', () => {
this.dragging = true;
return '';
});
this.map.on('dragend', () => {
this.dragging = false;
return '';
});
// 不同于高德地图,需要手动触发首次渲染
this.handleCameraChanged();
}
@ -397,7 +416,8 @@ export default class MapboxService
private handleCameraChanged = () => {
// @see https://github.com/mapbox/mapbox-gl-js/issues/2572
const { lat, lng } = this.map.getCenter().wrap();
// Tip: 统一触发地图变化事件
this.emit('mapchange');
// resync
this.viewport.syncWithMapCamera({
bearing: this.map.getBearing(),

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-renderer",
"version": "2.5.30",
"version": "2.5.41",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
@ -26,7 +26,7 @@
"gl": "^4.4.0"
},
"dependencies": {
"@antv/l7-core": "^2.5.30",
"@antv/l7-core": "^2.5.41",
"@babel/runtime": "^7.7.7",
"inversify": "^5.0.1",
"l7regl": "^0.0.14",

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-scene",
"version": "2.5.30",
"version": "2.5.41",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
@ -23,12 +23,12 @@
"author": "xiaoiver",
"license": "ISC",
"dependencies": {
"@antv/l7-component": "^2.5.30",
"@antv/l7-core": "^2.5.30",
"@antv/l7-layers": "^2.5.30",
"@antv/l7-maps": "^2.5.30",
"@antv/l7-renderer": "^2.5.30",
"@antv/l7-utils": "^2.5.30",
"@antv/l7-component": "^2.5.41",
"@antv/l7-core": "^2.5.41",
"@antv/l7-layers": "^2.5.41",
"@antv/l7-maps": "^2.5.41",
"@antv/l7-renderer": "^2.5.41",
"@antv/l7-utils": "^2.5.41",
"@babel/runtime": "^7.7.7",
"inversify": "^5.0.1",
"mapbox-gl": "^1.2.1",

View File

@ -153,12 +153,16 @@ class Scene
return this.mapService.map;
}
public setBgColor(color: string) {
this.mapService.setBgColor(color);
}
// layer 管理
public addLayer(layer: ILayer): void {
// 为当前图层创建一个容器
// TODO: 初始化的时候设置 容器
const layerContainer = createLayerContainer(this.container);
layer.setContainer(layerContainer);
layer.setContainer(layerContainer, this.container);
this.sceneService.addLayer(layer);
}
@ -174,8 +178,8 @@ class Scene
return this.layerService.getLayerByName(name);
}
public removeLayer(layer: ILayer): void {
this.layerService.remove(layer);
public removeLayer(layer: ILayer, parentLayer?: ILayer): void {
this.layerService.remove(layer, parentLayer);
}
public removeAllLayer(): void {

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-source",
"version": "2.5.30",
"version": "2.5.41",
"description": "",
"main": "lib/index.js",
"module": "es/index.js",
@ -26,8 +26,8 @@
"license": "ISC",
"dependencies": {
"@antv/async-hook": "^2.1.0",
"@antv/l7-core": "^2.5.30",
"@antv/l7-utils": "^2.5.30",
"@antv/l7-core": "^2.5.41",
"@antv/l7-utils": "^2.5.41",
"@babel/runtime": "^7.7.7",
"@mapbox/geojson-rewind": "^0.4.0",
"@turf/helpers": "^6.1.4",

View File

@ -2,7 +2,7 @@ import { registerParser, registerTransform } from './factory';
import csv from './parser/csv';
import geojson from './parser/geojson';
import image from './parser/image';
import json from './parser/json';
import json, { defaultData, defaultParser } from './parser/json';
import raster from './parser/raster';
import Source from './source';
import { cluster } from './transform/cluster';
@ -31,3 +31,6 @@ export {
} from './factory';
export * from './interface';
export const DEFAULT_DATA = defaultData;
export const DEFAULT_PARSER = defaultParser;

View File

@ -7,7 +7,8 @@ export default function image(
data: string | string[],
cfg: IImageCfg,
): IParserData {
const { extent } = cfg;
// TODO: 为 extent 赋默认值
const { extent = [121.168, 30.2828, 121.384, 30.4219] } = cfg;
const images = new Promise((resolve) => {
loadData(data, (res: any) => {
resolve(res);

View File

@ -47,3 +47,23 @@ export default function json(data: IJsonData, cfg: IParserCfg): IParserData {
dataArray: resultData,
};
}
// TODO: 提供默认数据和解析器
export const defaultData = [
{
lng1: 100,
lat1: 30.0,
lng2: 130,
lat2: 30,
},
];
export const defaultParser = {
parser: {
type: 'json',
x: 'lng1',
y: 'lat1',
x1: 'lng2',
y1: 'lat2',
},
};

View File

@ -207,6 +207,14 @@ export default class Source extends EventEmitter implements ISource {
private excuteParser(): void {
const parser = this.parser;
const type: string = parser.type || 'geojson';
// TODO: 图片瓦片地图组件只需要使用 url 参数
if (type === 'imagetile') {
this.data = {
tileurl: this.originData,
dataArray: [],
};
return;
}
const sourceParser = getParser(type);
this.data = sourceParser(this.originData, parser);
// 计算范围

View File

@ -1,6 +1,6 @@
{
"name": "@antv/l7-three",
"version": "2.5.30",
"version": "2.5.41",
"description": "three for L7 ",
"keywords": [
"3D",
@ -44,9 +44,9 @@
},
"homepage": "https://github.com/antvis/L7#readme",
"dependencies": {
"@antv/l7-core": "^2.5.30",
"@antv/l7-layers": "^2.5.30",
"@antv/l7-scene": "^2.5.30",
"@antv/l7-core": "^2.5.41",
"@antv/l7-layers": "^2.5.41",
"@antv/l7-scene": "^2.5.41",
"@babel/runtime": "^7.7.7",
"inversify": "^5.0.1",
"reflect-metadata": "^0.1.13",

View File

@ -23,7 +23,7 @@ export default class ThreeJSLayer
}>
implements ILayer {
public type: string = 'custom';
protected threeRenderService: IThreeRenderService;
public threeRenderService: IThreeRenderService;
// 构建 threejs 的 scene
private scene: Scene = new Scene();
private renderer: WebGLRenderer;
@ -198,6 +198,10 @@ export default class ThreeJSLayer
return this;
}
public getRenderCamera() {
return this.threeRenderService.getRenderCamera();
}
public addAnimateMixer(mixer: AnimationMixer) {
this.animateMixer.push(mixer);
}

View File

@ -6,7 +6,7 @@ import {
} from './threeRenderService';
export default class ThreeRender {
private threeRenderService: IThreeRenderService;
public threeRenderService: IThreeRenderService;
constructor(scene: Scene) {
const sceneContainer = scene.getServiceContainer();
sceneContainer

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