mirror of https://gitee.com/antv-l7/antv-l7
docs: add site example
This commit is contained in:
parent
7b8822aa1e
commit
3c5333d7c7
|
@ -3,6 +3,25 @@ title: Layer 组件
|
||||||
order: 2
|
order: 2
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Layer 类型
|
||||||
|
|
||||||
|
React 各个组件名称和 L7 名称保持一致
|
||||||
|
|
||||||
|
- PointLayer
|
||||||
|
- PolygonLayer
|
||||||
|
- LineLayer
|
||||||
|
- HeatmapLayer
|
||||||
|
- RasterLayer
|
||||||
|
- ImageLayer
|
||||||
|
- CityBuildingLayer
|
||||||
|
|
||||||
|
### 使用方式
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
import { PointLayer } '@antv/l7-react';
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## Layer Props
|
## Layer Props
|
||||||
|
|
||||||
| prop name | Type | Default | Description |
|
| prop name | Type | Default | Description |
|
||||||
|
@ -17,6 +36,7 @@ order: 2
|
||||||
| filter | `Function` | | 图层数据过滤方法 |
|
| filter | `Function` | | 图层数据过滤方法 |
|
||||||
| select | `boolean` `interaction option` | | 图层选中高亮 |
|
| select | `boolean` `interaction option` | | 图层选中高亮 |
|
||||||
| active | `boolean` `interaction option` | `false` | 图层 hover 高亮 |
|
| active | `boolean` `interaction option` | `false` | 图层 hover 高亮 |
|
||||||
|
| animate | `animate Option` | `null` | 图层动画配置 |
|
||||||
| onLayerLoaded | `Function` | | 图层添加完成后回调,用于获取 layer 对象 |
|
| onLayerLoaded | `Function` | | 图层添加完成后回调,用于获取 layer 对象 |
|
||||||
|
|
||||||
### layer options
|
### layer options
|
||||||
|
@ -73,19 +93,25 @@ const scales = {
|
||||||
|
|
||||||
### interaction option
|
### interaction option
|
||||||
|
|
||||||
|
active,select 配置项
|
||||||
|
|
||||||
**option**
|
**option**
|
||||||
|
|
||||||
- color 设置交互的颜色,指滑过或者选中的
|
- color 设置交互的颜色,指滑过或者选中的
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
<>
|
||||||
|
```
|
||||||
|
|
||||||
### 获取 layer 对象
|
### 获取 layer 对象
|
||||||
|
|
||||||
#### onLayerLoaded
|
#### onLayerLoaded
|
||||||
|
|
||||||
回调函数获取 layer, scene 对象
|
回调函数获取 layer, scene 对象
|
||||||
|
|
||||||
onLayerLoaded=(layer, scene) =>{
|
```javascript
|
||||||
|
onLayerLoaded = (layer, scene) => {};
|
||||||
}
|
```
|
||||||
|
|
||||||
#### Context API
|
#### Context API
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,10 @@ order: 3
|
||||||
| offsets | `Array[x,y]` | `null` | marker 位置偏移 |
|
| offsets | `Array[x,y]` | `null` | marker 位置偏移 |
|
||||||
| extData | `object` | `null` | marker 属性数据 |
|
| extData | `object` | `null` | marker 属性数据 |
|
||||||
|
|
||||||
|
## Maker 事件
|
||||||
|
|
||||||
|
通过 onMarkerLoaded 方法获取 Marker 实例监听
|
||||||
|
|
||||||
## 实例
|
## 实例
|
||||||
|
|
||||||
```jsx
|
```jsx
|
||||||
|
|
|
@ -3,6 +3,14 @@ title: Scene 组件
|
||||||
order: 1
|
order: 1
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 使用
|
||||||
|
|
||||||
|
在 React 版本中 Mapbox 和高德地图作为两个组件封装的。
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { MapboxScene, AmapScene } from '@antv/l7-react';
|
||||||
|
```
|
||||||
|
|
||||||
## Scene Props
|
## Scene Props
|
||||||
|
|
||||||
| prop name | Type | Default | Description |
|
| prop name | Type | Default | Description |
|
||||||
|
|
|
@ -13,6 +13,7 @@ order: 0
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { LineLayer, AMapScene } from '@antv/l7-react';
|
import { LineLayer, AMapScene } from '@antv/l7-react';
|
||||||
|
|
||||||
export default React.memo(function Map() {
|
export default React.memo(function Map() {
|
||||||
const [data, setData] = React.useState();
|
const [data, setData] = React.useState();
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { AMapScene, Marker } from '@antv/l7-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
function creatMarkers() {
|
||||||
|
const markers = [];
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
for (let j = 0; j < 5; j++) {
|
||||||
|
markers.push(<Marker key={i + '-' + j} lnglat={[112 + i, 30 + j]} />);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
const MapScene = React.memo(function Map() {
|
||||||
|
return (
|
||||||
|
<AMapScene
|
||||||
|
map={{
|
||||||
|
center: [114, 32],
|
||||||
|
pitch: 0,
|
||||||
|
style: 'dark',
|
||||||
|
zoom: 6,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{creatMarkers()}
|
||||||
|
</AMapScene>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ReactDOM.render(<MapScene />, document.getElementById('map'));
|
|
@ -5,7 +5,7 @@ const MapScene = React.memo(function Map() {
|
||||||
return (
|
return (
|
||||||
<AMapScene
|
<AMapScene
|
||||||
map={{
|
map={{
|
||||||
center: [110.19382669582967, 50.258134],
|
center: [110.19382669582967, 30.258134],
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
style: 'dark',
|
style: 'dark',
|
||||||
zoom: 1,
|
zoom: 1,
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"title": {
|
||||||
|
"zh": "Scene 组件",
|
||||||
|
"en": "Scene Component"
|
||||||
|
},
|
||||||
|
"demos": [
|
||||||
|
|
||||||
|
{
|
||||||
|
"filename": "Marker.tsx",
|
||||||
|
"title": "Marker 组件",
|
||||||
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*ocOWSKz2peAAAAAAAAAAAABkARQnAQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "control.tsx",
|
||||||
|
"title": "Control组件",
|
||||||
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*_65gSYgf1DoAAAAAAAAAAABkARQnAQ"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
title: Control Component
|
title: Control Component
|
||||||
order: 0
|
order: 3
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
title: Control 组件
|
title: Control 组件
|
||||||
order: 0
|
order: 3
|
||||||
---
|
---
|
||||||
|
|
|
@ -0,0 +1,224 @@
|
||||||
|
import {
|
||||||
|
LayerEvent,
|
||||||
|
LineLayer,
|
||||||
|
MapboxScene,
|
||||||
|
Marker,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
} from '@antv/l7-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
function joinData(geodata: any, ncovData: any) {
|
||||||
|
const ncovDataObj: any = {};
|
||||||
|
ncovData.forEach((item: any) => {
|
||||||
|
const {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
} = item;
|
||||||
|
if (countryName === '中国') {
|
||||||
|
if (!ncovDataObj[countryName]) {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName: 0,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount: 0,
|
||||||
|
confirmedCount: 0,
|
||||||
|
suspectedCount: 0,
|
||||||
|
curedCount: 0,
|
||||||
|
deadCount: 0,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName].currentConfirmedCount += currentConfirmedCount;
|
||||||
|
ncovDataObj[countryName].confirmedCount += confirmedCount;
|
||||||
|
ncovDataObj[countryName].suspectedCount += suspectedCount;
|
||||||
|
ncovDataObj[countryName].curedCount += curedCount;
|
||||||
|
ncovDataObj[countryName].deadCount += deadCount;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const geoObj: any = {};
|
||||||
|
geodata.features.forEach((feature: any) => {
|
||||||
|
const { name } = feature.properties;
|
||||||
|
geoObj[name] = feature.properties;
|
||||||
|
const ncov = ncovDataObj[name] || {};
|
||||||
|
feature.properties = {
|
||||||
|
...feature.properties,
|
||||||
|
...ncov,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return geodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const World = React.memo(function Map() {
|
||||||
|
const [data, setData] = React.useState();
|
||||||
|
const [filldata, setfillData] = React.useState();
|
||||||
|
const [popupInfo, setPopupInfo] = React.useState<{
|
||||||
|
lnglat: number[];
|
||||||
|
feature: any;
|
||||||
|
}>();
|
||||||
|
React.useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
const [geoData, ncovData] = await Promise.all([
|
||||||
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
|
).then((d) => d.json()),
|
||||||
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
|
d.json(),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
const worldData = joinData(geoData, ncovData.results);
|
||||||
|
const pointdata = worldData.features.map((feature: any) => {
|
||||||
|
return feature.properties;
|
||||||
|
});
|
||||||
|
setfillData(worldData);
|
||||||
|
setData(pointdata);
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
function showPopup(args: any): void {
|
||||||
|
setPopupInfo({
|
||||||
|
lnglat: args.lngLat,
|
||||||
|
feature: args.feature,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MapboxScene
|
||||||
|
map={{
|
||||||
|
center: [110.19382669582967, 50.258134],
|
||||||
|
pitch: 0,
|
||||||
|
style: 'blank',
|
||||||
|
zoom: 1,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{popupInfo && (
|
||||||
|
<Popup lnglat={popupInfo.lnglat}>
|
||||||
|
{popupInfo.feature.name}
|
||||||
|
<ul
|
||||||
|
style={{
|
||||||
|
margin: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<li>现有确诊:{popupInfo.feature.currentConfirmedCount}</li>
|
||||||
|
<li>累计确诊:{popupInfo.feature.confirmedCount}</li>
|
||||||
|
<li>治愈:{popupInfo.feature.curedCount}</li>
|
||||||
|
<li>死亡:{popupInfo.feature.deadCount}</li>
|
||||||
|
</ul>
|
||||||
|
</Popup>
|
||||||
|
)}
|
||||||
|
{data && [
|
||||||
|
<PolygonLayer
|
||||||
|
key={'1'}
|
||||||
|
options={{
|
||||||
|
autoFit: false,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data: filldata,
|
||||||
|
}}
|
||||||
|
scale={{
|
||||||
|
values: {
|
||||||
|
confirmedCount: {
|
||||||
|
type: 'quantile',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#ddd',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'fill',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<LineLayer
|
||||||
|
key={'3'}
|
||||||
|
source={{
|
||||||
|
data: filldata,
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
values: 0.6,
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#fff',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'line',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<PointLayer
|
||||||
|
key={'2'}
|
||||||
|
options={{
|
||||||
|
autoFit: true,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
coordinates: 'centroid',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
scale={{
|
||||||
|
values: {
|
||||||
|
confirmedCount: {
|
||||||
|
type: 'log',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#b10026',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'circle',
|
||||||
|
}}
|
||||||
|
active={{
|
||||||
|
option: {
|
||||||
|
color: '#0c2c84',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
field: 'confirmedCount',
|
||||||
|
values: [5, 60],
|
||||||
|
}}
|
||||||
|
animate={{
|
||||||
|
enable: true,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 0.6,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LayerEvent type="mousemove" handler={showPopup} />
|
||||||
|
</PointLayer>,
|
||||||
|
]}
|
||||||
|
</MapboxScene>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ReactDOM.render(<World />, document.getElementById('map'));
|
|
@ -0,0 +1,276 @@
|
||||||
|
import {
|
||||||
|
LayerEvent,
|
||||||
|
LineLayer,
|
||||||
|
MapboxScene,
|
||||||
|
Marker,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
} from '@antv/l7-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
const colors = [
|
||||||
|
'#732200',
|
||||||
|
'#CC3D00',
|
||||||
|
'#FF6619',
|
||||||
|
'#FF9466',
|
||||||
|
'#FFC1A6',
|
||||||
|
'#FCE2D7',
|
||||||
|
'#ffffff',
|
||||||
|
].reverse();
|
||||||
|
function joinData(geodata: any, ncovData: any) {
|
||||||
|
const ncovDataObj: any = {};
|
||||||
|
ncovData.forEach((item: any) => {
|
||||||
|
const {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
} = item;
|
||||||
|
if (countryName === '中国') {
|
||||||
|
if (!ncovDataObj[countryName]) {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount: 0,
|
||||||
|
confirmedCount: 0,
|
||||||
|
suspectedCount: 0,
|
||||||
|
curedCount: 0,
|
||||||
|
deadCount: 0,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName].currentConfirmedCount += currentConfirmedCount;
|
||||||
|
ncovDataObj[countryName].confirmedCount += confirmedCount;
|
||||||
|
ncovDataObj[countryName].suspectedCount += suspectedCount;
|
||||||
|
ncovDataObj[countryName].curedCount += curedCount;
|
||||||
|
ncovDataObj[countryName].deadCount += deadCount;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const geoObj: any = {};
|
||||||
|
geodata.features.forEach((feature: any) => {
|
||||||
|
const { name } = feature.properties;
|
||||||
|
geoObj[name] = feature.properties;
|
||||||
|
const ncov = ncovDataObj[name] || {};
|
||||||
|
feature.properties = {
|
||||||
|
...feature.properties,
|
||||||
|
...ncov,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return geodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const World = React.memo(function Map() {
|
||||||
|
const [data, setData] = React.useState();
|
||||||
|
const [filldata, setfillData] = React.useState();
|
||||||
|
const [popupInfo, setPopupInfo] = React.useState<{
|
||||||
|
lnglat: number[];
|
||||||
|
feature: any;
|
||||||
|
}>();
|
||||||
|
React.useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
const [geoData, ncovData] = await Promise.all([
|
||||||
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
|
).then((d) => d.json()),
|
||||||
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
|
d.json(),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
const worldData = joinData(geoData, ncovData.results);
|
||||||
|
const pointdata = worldData.features.map((feature: any) => {
|
||||||
|
return feature.properties;
|
||||||
|
});
|
||||||
|
setfillData(worldData);
|
||||||
|
setData(pointdata);
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
function showPopup(args: any): void {
|
||||||
|
setPopupInfo({
|
||||||
|
lnglat: args.lngLat,
|
||||||
|
feature: args.feature,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MapboxScene
|
||||||
|
map={{
|
||||||
|
center: [110.19382669582967, 50.258134],
|
||||||
|
pitch: 0,
|
||||||
|
style: 'blank',
|
||||||
|
zoom: 1,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{popupInfo && (
|
||||||
|
<Popup lnglat={popupInfo.lnglat}>
|
||||||
|
{popupInfo.feature.name}
|
||||||
|
<ul
|
||||||
|
style={{
|
||||||
|
margin: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<li>现有确诊:{popupInfo.feature.currentConfirmedCount}</li>
|
||||||
|
<li>累计确诊:{popupInfo.feature.confirmedCount}</li>
|
||||||
|
<li>治愈:{popupInfo.feature.curedCount}</li>
|
||||||
|
<li>死亡:{popupInfo.feature.deadCount}</li>
|
||||||
|
</ul>
|
||||||
|
</Popup>
|
||||||
|
)}
|
||||||
|
{data && [
|
||||||
|
<PolygonLayer
|
||||||
|
key={'1'}
|
||||||
|
options={{
|
||||||
|
autoFit: true,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data: filldata,
|
||||||
|
}}
|
||||||
|
scale={{
|
||||||
|
values: {
|
||||||
|
confirmedCount: {
|
||||||
|
type: 'quantile',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#ddd',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'fill',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<LineLayer
|
||||||
|
key={'3'}
|
||||||
|
source={{
|
||||||
|
data: filldata,
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
values: 0.6,
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#fff',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'line',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<PointLayer
|
||||||
|
key={'2'}
|
||||||
|
options={{
|
||||||
|
autoFit: true,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
coordinates: 'centroid',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
scale={{
|
||||||
|
values: {
|
||||||
|
confirmedCount: {
|
||||||
|
type: 'log',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
field: 'confirmedCount',
|
||||||
|
values: (count) => {
|
||||||
|
return count > 10000
|
||||||
|
? colors[6]
|
||||||
|
: count > 1000
|
||||||
|
? colors[5]
|
||||||
|
: count > 500
|
||||||
|
? colors[4]
|
||||||
|
: count > 100
|
||||||
|
? colors[3]
|
||||||
|
: count > 10
|
||||||
|
? colors[2]
|
||||||
|
: count > 1
|
||||||
|
? colors[1]
|
||||||
|
: colors[0];
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'circle',
|
||||||
|
}}
|
||||||
|
active={{
|
||||||
|
option: {
|
||||||
|
color: '#0c2c84',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
field: 'confirmedCount',
|
||||||
|
values: [0, 30],
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 0.8,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LayerEvent type="mousemove" handler={showPopup} />
|
||||||
|
</PointLayer>,
|
||||||
|
<PointLayer
|
||||||
|
key={'5'}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
coordinates: 'centroid',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#fff',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
field: 'countryName',
|
||||||
|
values: 'text',
|
||||||
|
}}
|
||||||
|
filter={{
|
||||||
|
field: 'currentConfirmedCount',
|
||||||
|
values: (v) => {
|
||||||
|
return v > 500;
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
values: 12,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LayerEvent type="mousemove" handler={showPopup} />
|
||||||
|
</PointLayer>,
|
||||||
|
]}
|
||||||
|
</MapboxScene>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ReactDOM.render(<World />, document.getElementById('map'));
|
|
@ -0,0 +1,224 @@
|
||||||
|
import {
|
||||||
|
LineLayer,
|
||||||
|
MapboxScene,
|
||||||
|
Marker,
|
||||||
|
PointLayer,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
} from '@antv/l7-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
function joinData(geodata: any, ncovData: any) {
|
||||||
|
const ncovDataObj: any = {};
|
||||||
|
ncovData.forEach((item: any) => {
|
||||||
|
const {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
} = item;
|
||||||
|
if (countryName === '中国') {
|
||||||
|
if (!ncovDataObj[countryName]) {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName: 0,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount: 0,
|
||||||
|
confirmedCount: 0,
|
||||||
|
suspectedCount: 0,
|
||||||
|
curedCount: 0,
|
||||||
|
deadCount: 0,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName].currentConfirmedCount += currentConfirmedCount;
|
||||||
|
ncovDataObj[countryName].confirmedCount += confirmedCount;
|
||||||
|
ncovDataObj[countryName].suspectedCount += suspectedCount;
|
||||||
|
ncovDataObj[countryName].curedCount += curedCount;
|
||||||
|
ncovDataObj[countryName].deadCount += deadCount;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const geoObj: any = {};
|
||||||
|
geodata.features.forEach((feature: any) => {
|
||||||
|
const { name } = feature.properties;
|
||||||
|
geoObj[name] = feature.properties;
|
||||||
|
const ncov = ncovDataObj[name] || {};
|
||||||
|
feature.properties = {
|
||||||
|
...feature.properties,
|
||||||
|
...ncov,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return geodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const World = React.memo(function Map() {
|
||||||
|
const [data, setData] = React.useState();
|
||||||
|
const [filldata, setfillData] = React.useState();
|
||||||
|
React.useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
const [geoData, ncovData] = await Promise.all([
|
||||||
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
|
).then((d) => d.json()),
|
||||||
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
|
d.json(),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
const worldData = joinData(geoData, ncovData.results);
|
||||||
|
const pointdata = worldData.features.map((feature: any) => {
|
||||||
|
return feature.properties;
|
||||||
|
});
|
||||||
|
setfillData(worldData);
|
||||||
|
setData(pointdata);
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MapboxScene
|
||||||
|
map={{
|
||||||
|
center: [110.19382669582967, 50.258134],
|
||||||
|
pitch: 50,
|
||||||
|
style: 'blank',
|
||||||
|
zoom: 1,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data && [
|
||||||
|
<PolygonLayer
|
||||||
|
key={'1'}
|
||||||
|
options={{
|
||||||
|
autoFit: true,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data: filldata,
|
||||||
|
}}
|
||||||
|
scale={{
|
||||||
|
values: {
|
||||||
|
confirmedCount: {
|
||||||
|
type: 'quantile',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#ddd',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'fill',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<LineLayer
|
||||||
|
key={'3'}
|
||||||
|
source={{
|
||||||
|
data: filldata,
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
values: 0.6,
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#fff',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'line',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<PointLayer
|
||||||
|
key={'2'}
|
||||||
|
options={{
|
||||||
|
autoFit: true,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
coordinates: 'centroid',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
scale={{
|
||||||
|
values: {
|
||||||
|
confirmedCount: {
|
||||||
|
type: 'log',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
active={{
|
||||||
|
option: {
|
||||||
|
color: '#0c2c84',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
field: 'confirmedCount',
|
||||||
|
values: (count) => {
|
||||||
|
return count > 10000
|
||||||
|
? '#732200'
|
||||||
|
: count > 1000
|
||||||
|
? '#CC3D00'
|
||||||
|
: count > 500
|
||||||
|
? '#FF6619'
|
||||||
|
: count > 100
|
||||||
|
? '#FF9466'
|
||||||
|
: count > 10
|
||||||
|
? '#FFC1A6'
|
||||||
|
: count > 1
|
||||||
|
? '#FCE2D7'
|
||||||
|
: 'rgb(255,255,255)';
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'cylinder',
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
field: 'confirmedCount',
|
||||||
|
values: (count: number) => {
|
||||||
|
const height =
|
||||||
|
count > 10000
|
||||||
|
? 70
|
||||||
|
: count > 1000
|
||||||
|
? 40
|
||||||
|
: count > 500
|
||||||
|
? 30
|
||||||
|
: count > 100
|
||||||
|
? 20
|
||||||
|
: count > 10
|
||||||
|
? 10
|
||||||
|
: count > 1
|
||||||
|
? 5
|
||||||
|
: 1;
|
||||||
|
return [5, 5, height];
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
</MapboxScene>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ReactDOM.render(<World />, document.getElementById('map'));
|
|
@ -0,0 +1,171 @@
|
||||||
|
import {
|
||||||
|
LineLayer,
|
||||||
|
MapboxScene,
|
||||||
|
Marker,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
} from '@antv/l7-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
function joinData(geodata: any, ncovData: any) {
|
||||||
|
const ncovDataObj: any = {};
|
||||||
|
ncovData.forEach((item: any) => {
|
||||||
|
const {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
} = item;
|
||||||
|
if (countryName === '中国') {
|
||||||
|
if (!ncovDataObj[countryName]) {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName: 0,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount: 0,
|
||||||
|
confirmedCount: 0,
|
||||||
|
suspectedCount: 0,
|
||||||
|
curedCount: 0,
|
||||||
|
deadCount: 0,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName].currentConfirmedCount += currentConfirmedCount;
|
||||||
|
ncovDataObj[countryName].confirmedCount += confirmedCount;
|
||||||
|
ncovDataObj[countryName].suspectedCount += suspectedCount;
|
||||||
|
ncovDataObj[countryName].curedCount += curedCount;
|
||||||
|
ncovDataObj[countryName].deadCount += deadCount;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const geoObj: any = {};
|
||||||
|
geodata.features.forEach((feature: any) => {
|
||||||
|
const { name } = feature.properties;
|
||||||
|
geoObj[name] = feature.properties;
|
||||||
|
const ncov = ncovDataObj[name] || {};
|
||||||
|
feature.properties = {
|
||||||
|
...feature.properties,
|
||||||
|
...ncov,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return geodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const World = React.memo(function Map() {
|
||||||
|
const [data, setData] = React.useState();
|
||||||
|
React.useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
const [geoData, ncovData] = await Promise.all([
|
||||||
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
|
).then((d) => d.json()),
|
||||||
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
|
d.json(),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
setData(joinData(geoData, ncovData.results));
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MapboxScene
|
||||||
|
map={{
|
||||||
|
center: [110.19382669582967, 50.258134],
|
||||||
|
pitch: 50,
|
||||||
|
style: 'blank',
|
||||||
|
zoom: 1,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data && [
|
||||||
|
<PolygonLayer
|
||||||
|
key={'1'}
|
||||||
|
options={{
|
||||||
|
autoFit: true,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
}}
|
||||||
|
scale={{
|
||||||
|
values: {
|
||||||
|
confirmedCount: {
|
||||||
|
type: 'quantile',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
active={{
|
||||||
|
option: {
|
||||||
|
color: '#0c2c84',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
field: 'confirmedCount',
|
||||||
|
values: (count) => {
|
||||||
|
return count > 10000
|
||||||
|
? '#732200'
|
||||||
|
: count > 1000
|
||||||
|
? '#CC3D00'
|
||||||
|
: count > 500
|
||||||
|
? '#FF6619'
|
||||||
|
: count > 100
|
||||||
|
? '#FF9466'
|
||||||
|
: count > 10
|
||||||
|
? '#FFC1A6'
|
||||||
|
: count > 1
|
||||||
|
? '#FCE2D7'
|
||||||
|
: 'rgb(255,255,255)';
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'extrude',
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
field: 'confirmedCount',
|
||||||
|
values: [0, 200000, 600000, 800000, 1000000],
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<LineLayer
|
||||||
|
key={'2'}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
values: 0.6,
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#FCE2D7',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'line',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
</MapboxScene>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ReactDOM.render(<World />, document.getElementById('map'));
|
|
@ -0,0 +1,161 @@
|
||||||
|
import {
|
||||||
|
LineLayer,
|
||||||
|
MapboxScene,
|
||||||
|
Marker,
|
||||||
|
PolygonLayer,
|
||||||
|
Popup,
|
||||||
|
} from '@antv/l7-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
function joinData(geodata: any, ncovData: any) {
|
||||||
|
const ncovDataObj: any = {};
|
||||||
|
ncovData.forEach((item: any) => {
|
||||||
|
const {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
} = item;
|
||||||
|
if (countryName === '中国') {
|
||||||
|
if (!ncovDataObj[countryName]) {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName: 0,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount: 0,
|
||||||
|
confirmedCount: 0,
|
||||||
|
suspectedCount: 0,
|
||||||
|
curedCount: 0,
|
||||||
|
deadCount: 0,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName].currentConfirmedCount += currentConfirmedCount;
|
||||||
|
ncovDataObj[countryName].confirmedCount += confirmedCount;
|
||||||
|
ncovDataObj[countryName].suspectedCount += suspectedCount;
|
||||||
|
ncovDataObj[countryName].curedCount += curedCount;
|
||||||
|
ncovDataObj[countryName].deadCount += deadCount;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ncovDataObj[countryName] = {
|
||||||
|
countryName,
|
||||||
|
countryEnglishName,
|
||||||
|
currentConfirmedCount,
|
||||||
|
confirmedCount,
|
||||||
|
suspectedCount,
|
||||||
|
curedCount,
|
||||||
|
deadCount,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const geoObj: any = {};
|
||||||
|
geodata.features.forEach((feature: any) => {
|
||||||
|
const { name } = feature.properties;
|
||||||
|
geoObj[name] = feature.properties;
|
||||||
|
const ncov = ncovDataObj[name] || {};
|
||||||
|
feature.properties = {
|
||||||
|
...feature.properties,
|
||||||
|
...ncov,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return geodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
const World = React.memo(function Map() {
|
||||||
|
const [data, setData] = React.useState();
|
||||||
|
React.useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
const [geoData, ncovData] = await Promise.all([
|
||||||
|
fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
|
).then((d) => d.json()),
|
||||||
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
|
d.json(),
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
setData(joinData(geoData, ncovData.results));
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<MapboxScene
|
||||||
|
map={{
|
||||||
|
center: [110.19382669582967, 50.258134],
|
||||||
|
pitch: 0,
|
||||||
|
style: 'blank',
|
||||||
|
zoom: 1,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{data && [
|
||||||
|
<PolygonLayer
|
||||||
|
key={'1'}
|
||||||
|
options={{
|
||||||
|
autoFit: true,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
}}
|
||||||
|
scale={{
|
||||||
|
values: {
|
||||||
|
confirmedCount: {
|
||||||
|
type: 'quantile',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
active={{
|
||||||
|
option: {
|
||||||
|
color: '#0c2c84',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
field: 'confirmedCount',
|
||||||
|
values: [
|
||||||
|
'#732200',
|
||||||
|
'#CC3D00',
|
||||||
|
'#FF6619',
|
||||||
|
'#FF9466',
|
||||||
|
'#FFC1A6',
|
||||||
|
'#FCE2D7',
|
||||||
|
].reverse()
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'fill',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
<LineLayer
|
||||||
|
key={'2'}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
values: 0.6,
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#f00',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
values: 'line',
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
</MapboxScene>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ReactDOM.render(<World />, document.getElementById('map'));
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"title": {
|
||||||
|
"zh": "COVID-19 地图",
|
||||||
|
"en": "COVID-19 Map"
|
||||||
|
},
|
||||||
|
"demos": [
|
||||||
|
{
|
||||||
|
"filename": "covid_animate.tsx",
|
||||||
|
"title": "气泡动图",
|
||||||
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*ZFdoQ7QTqVYAAAAAAAAAAABkARQnAQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "covid_fill.tsx",
|
||||||
|
"title": "填充图",
|
||||||
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*R6quR4grVI0AAAAAAAAAAABkARQnAQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "covid_bubble.tsx",
|
||||||
|
"title": "气泡图",
|
||||||
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*_PwXRp5xA3oAAAAAAAAAAABkARQnAQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "covid_column.tsx",
|
||||||
|
"title": "3D柱图",
|
||||||
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*XCGtTIIouIcAAAAAAAAAAABkARQnAQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "covid_extrude.tsx",
|
||||||
|
"title": "3D 填充图",
|
||||||
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*k-f5T4jyFgkAAAAAAAAAAABkARQnAQ"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: COVID-19 Map
|
||||||
|
order: 0
|
||||||
|
---
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: COVID-19 地图
|
||||||
|
order: 0
|
||||||
|
---
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { AMapScene, LoadImage, PointLayer } from '@antv/l7-react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
const World = React.memo(function Map() {
|
||||||
|
const [data, setData] = React.useState();
|
||||||
|
React.useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
const response = await fetch(
|
||||||
|
'https://gw.alipayobjects.com/os/basement_prod/893d1d5f-11d9-45f3-8322-ee9140d288ae.json',
|
||||||
|
);
|
||||||
|
const data = await response.json();
|
||||||
|
setData(data);
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<AMapScene
|
||||||
|
map={{
|
||||||
|
center: [0.19382669582967, 50.258134],
|
||||||
|
pitch: 0,
|
||||||
|
style: 'light',
|
||||||
|
zoom: 6,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LoadImage name="00" url="https://gw.alipayobjects.com/zos/basement_prod/604b5e7f-309e-40db-b95b-4fac746c5153.svg"/>
|
||||||
|
<LoadImage name="01" url="https://gw.alipayobjects.com/zos/basement_prod/30580bc9-506f-4438-8c1a-744e082054ec.svg"/>
|
||||||
|
<LoadImage name="02" url="https://gw.alipayobjects.com/zos/basement_prod/7aa1f460-9f9f-499f-afdf-13424aa26bbf.svg"/>
|
||||||
|
{data && (
|
||||||
|
<PointLayer
|
||||||
|
key={'2'}
|
||||||
|
options={{
|
||||||
|
autoFit: true,
|
||||||
|
}}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
x: 'longitude',
|
||||||
|
y: 'latitude',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
field: 'name',
|
||||||
|
values: ['00', '01', '02'],
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
values: 10,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AMapScene>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ReactDOM.render(<World />, document.getElementById('map'));
|
|
@ -8,7 +8,12 @@
|
||||||
{
|
{
|
||||||
"filename": "world.jsx",
|
"filename": "world.jsx",
|
||||||
"title": "世界地图",
|
"title": "世界地图",
|
||||||
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*ZiMnSZlmblIAAAAAAAAAAABkARQnAQ"
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*SPnxSLCgZ7IAAAAAAAAAAABkARQnAQ"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "Point_image.tsx",
|
||||||
|
"title": "点标注图",
|
||||||
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*HQShTKuKq6wAAAAAAAAAAABkARQnAQ"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
title: Layer Component
|
title: Layer Component
|
||||||
order: 0
|
order: 2
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
title: Layer 组件
|
title: Layer 组件
|
||||||
order: 0
|
order: 2
|
||||||
---
|
---
|
||||||
|
|
|
@ -8,12 +8,12 @@
|
||||||
{
|
{
|
||||||
"filename": "amap.jsx",
|
"filename": "amap.jsx",
|
||||||
"title": "高德地图",
|
"title": "高德地图",
|
||||||
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*ZiMnSZlmblIAAAAAAAAAAABkARQnAQ"
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*QrQkRKHte0YAAAAAAAAAAABkARQnAQ"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"filename": "Mapbox.jsx",
|
"filename": "mapbox.jsx",
|
||||||
"title": "Mapbox 地图",
|
"title": "Mapbox 地图",
|
||||||
"screenshot": "https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*ZiMnSZlmblIAAAAAAAAAAABkARQnAQ"
|
"screenshot": "https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*_65gSYgf1DoAAAAAAAAAAABkARQnAQ"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
title: Scene Component
|
title: Scene Component
|
||||||
order: 0
|
order: 1
|
||||||
---
|
---
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
---
|
---
|
||||||
title: Scene 组件
|
title: Scene 组件
|
||||||
order: 0
|
order: 1
|
||||||
---
|
---
|
||||||
|
|
|
@ -175,6 +175,14 @@ module.exports = {
|
||||||
en: 'Featured'
|
en: 'Featured'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
slug: 'react',
|
||||||
|
icon: 'map',
|
||||||
|
title: {
|
||||||
|
zh: 'React 组件',
|
||||||
|
en: 'React Demo'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
slug: 'point',
|
slug: 'point',
|
||||||
icon: 'point',
|
icon: 'point',
|
||||||
|
@ -216,14 +224,6 @@ module.exports = {
|
||||||
en: 'Raster Layer'
|
en: 'Raster Layer'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
slug: 'react',
|
|
||||||
icon: 'map',
|
|
||||||
title: {
|
|
||||||
zh: 'React 组件',
|
|
||||||
en: 'React Demo'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
slug: 'tutorial',
|
slug: 'tutorial',
|
||||||
icon: 'map',
|
icon: 'map',
|
||||||
|
|
|
@ -111,6 +111,7 @@ export default class TextModel extends BaseModel {
|
||||||
const { canvas, mapping } = this.fontService;
|
const { canvas, mapping } = this.fontService;
|
||||||
if (Object.keys(mapping).length !== this.textCount) {
|
if (Object.keys(mapping).length !== this.textCount) {
|
||||||
this.updateTexture();
|
this.updateTexture();
|
||||||
|
this.textCount = Object.keys(mapping).length;
|
||||||
}
|
}
|
||||||
this.preTextStyle = {
|
this.preTextStyle = {
|
||||||
textAnchor,
|
textAnchor,
|
||||||
|
|
|
@ -30,4 +30,24 @@ const RasterLayer = React.memo(function Layer(
|
||||||
return BaseLayer('rasterLayer', props);
|
return BaseLayer('rasterLayer', props);
|
||||||
});
|
});
|
||||||
|
|
||||||
export { PolygonLayer, LineLayer, PointLayer, HeatMapLayer, RasterLayer };
|
const ImageLayer = React.memo(function Layer(
|
||||||
|
props: ILayerProps & { children?: any },
|
||||||
|
) {
|
||||||
|
return BaseLayer('imagelayer', props);
|
||||||
|
});
|
||||||
|
|
||||||
|
const CityBuildingLayer = React.memo(function Layer(
|
||||||
|
props: ILayerProps & { children?: any },
|
||||||
|
) {
|
||||||
|
return BaseLayer('citybuildinglayer', props);
|
||||||
|
});
|
||||||
|
|
||||||
|
export {
|
||||||
|
PolygonLayer,
|
||||||
|
LineLayer,
|
||||||
|
PointLayer,
|
||||||
|
HeatMapLayer,
|
||||||
|
RasterLayer,
|
||||||
|
ImageLayer,
|
||||||
|
CityBuildingLayer,
|
||||||
|
};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import {
|
import {
|
||||||
|
CityBuildingLayer,
|
||||||
HeatmapLayer,
|
HeatmapLayer,
|
||||||
ILayer,
|
ILayer,
|
||||||
|
ImageLayer,
|
||||||
LineLayer,
|
LineLayer,
|
||||||
PointLayer,
|
PointLayer,
|
||||||
PolygonLayer,
|
PolygonLayer,
|
||||||
|
@ -61,6 +63,12 @@ export default function BaseLayer(type: string, props: ILayerProps) {
|
||||||
case 'rasterLayer':
|
case 'rasterLayer':
|
||||||
l = new RasterLayer(options);
|
l = new RasterLayer(options);
|
||||||
break;
|
break;
|
||||||
|
case 'imageLayer':
|
||||||
|
l = new ImageLayer(options);
|
||||||
|
break;
|
||||||
|
case 'citybuildingLayer':
|
||||||
|
l = new CityBuildingLayer(options);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
l = new PolygonLayer(options);
|
l = new PolygonLayer(options);
|
||||||
}
|
}
|
||||||
|
@ -115,9 +123,9 @@ export default function BaseLayer(type: string, props: ILayerProps) {
|
||||||
<LayerContext.Provider value={layer}>
|
<LayerContext.Provider value={layer}>
|
||||||
<Source layer={layer} source={source} />
|
<Source layer={layer} source={source} />
|
||||||
{scale && <Scale layer={layer} scale={scale} />}
|
{scale && <Scale layer={layer} scale={scale} />}
|
||||||
<Color layer={layer} color={color} />
|
{color && <Color layer={layer} color={color} />}
|
||||||
{size && <Size layer={layer} size={size} />}
|
{size && <Size layer={layer} size={size} />}
|
||||||
<Shape layer={layer} shape={shape} />
|
{shape && <Shape layer={layer} shape={shape} />}
|
||||||
{style && <Style layer={layer} style={style} />}
|
{style && <Style layer={layer} style={style} />}
|
||||||
{active && <Active layer={layer} active={active} />}
|
{active && <Active layer={layer} active={active} />}
|
||||||
{select && <Select layer={layer} select={select} />}
|
{select && <Select layer={layer} select={select} />}
|
||||||
|
|
|
@ -5,7 +5,7 @@ export { default as Scene } from './component/Scene';
|
||||||
export * from './component/Layer';
|
export * from './component/Layer';
|
||||||
export { default as Control } from './component/Control';
|
export { default as Control } from './component/Control';
|
||||||
export { default as CustomControl } from './component/CustomControl';
|
export { default as CustomControl } from './component/CustomControl';
|
||||||
export { PolygonLayer, LineLayer, PointLayer } from './component/Layer';
|
export * from './component/Layer';
|
||||||
export { LayerEvent } from './component/LayerEvent';
|
export { LayerEvent } from './component/LayerEvent';
|
||||||
export { useSceneValue, SceneContext } from './component/SceneContext';
|
export { useSceneValue, SceneContext } from './component/SceneContext';
|
||||||
export { useLayerValue, LayerContext } from './component/LayerContext';
|
export { useLayerValue, LayerContext } from './component/LayerContext';
|
||||||
|
|
|
@ -68,7 +68,7 @@ export default React.memo(function Map() {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const [geoData, ncovData] = await Promise.all([
|
const [geoData, ncovData] = await Promise.all([
|
||||||
fetch(
|
fetch(
|
||||||
'https://gw.alipayobjects.com/os/bmw-prod/36741c60-5e69-4c36-9033-d4ce42754a78.json',
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
).then((d) => d.json()),
|
).then((d) => d.json()),
|
||||||
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
d.json(),
|
d.json(),
|
||||||
|
|
|
@ -8,7 +8,15 @@ import {
|
||||||
Popup,
|
Popup,
|
||||||
} from '@antv/l7-react';
|
} from '@antv/l7-react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
const colors = [
|
||||||
|
'#ffffb2',
|
||||||
|
'#fed976',
|
||||||
|
'#feb24c',
|
||||||
|
'#fd8d3c',
|
||||||
|
'#fc4e2a',
|
||||||
|
'#e31a1c',
|
||||||
|
'#b10026',
|
||||||
|
];
|
||||||
function joinData(geodata: any, ncovData: any) {
|
function joinData(geodata: any, ncovData: any) {
|
||||||
const ncovDataObj: any = {};
|
const ncovDataObj: any = {};
|
||||||
ncovData.forEach((item: any) => {
|
ncovData.forEach((item: any) => {
|
||||||
|
@ -24,7 +32,7 @@ function joinData(geodata: any, ncovData: any) {
|
||||||
if (countryName === '中国') {
|
if (countryName === '中国') {
|
||||||
if (!ncovDataObj[countryName]) {
|
if (!ncovDataObj[countryName]) {
|
||||||
ncovDataObj[countryName] = {
|
ncovDataObj[countryName] = {
|
||||||
countryName: 0,
|
countryName,
|
||||||
countryEnglishName,
|
countryEnglishName,
|
||||||
currentConfirmedCount: 0,
|
currentConfirmedCount: 0,
|
||||||
confirmedCount: 0,
|
confirmedCount: 0,
|
||||||
|
@ -75,7 +83,7 @@ export default React.memo(function Map() {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const [geoData, ncovData] = await Promise.all([
|
const [geoData, ncovData] = await Promise.all([
|
||||||
fetch(
|
fetch(
|
||||||
'https://gw.alipayobjects.com/os/bmw-prod/36741c60-5e69-4c36-9033-d4ce42754a78.json',
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
).then((d) => d.json()),
|
).then((d) => d.json()),
|
||||||
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
d.json(),
|
d.json(),
|
||||||
|
@ -196,18 +204,18 @@ export default React.memo(function Map() {
|
||||||
field: 'confirmedCount',
|
field: 'confirmedCount',
|
||||||
values: (count) => {
|
values: (count) => {
|
||||||
return count > 10000
|
return count > 10000
|
||||||
? '#b10026'
|
? colors[6]
|
||||||
: count > 1000
|
: count > 1000
|
||||||
? '#e31a1c'
|
? colors[5]
|
||||||
: count > 500
|
: count > 500
|
||||||
? '#fc4e2a'
|
? colors[4]
|
||||||
: count > 100
|
: count > 100
|
||||||
? '#fd8d3c'
|
? colors[3]
|
||||||
: count > 10
|
: count > 10
|
||||||
? '#feb24c'
|
? colors[2]
|
||||||
: count > 1
|
: count > 1
|
||||||
? '#fed976'
|
? colors[1]
|
||||||
: 'rgb(255,255,255)';
|
: colors[0];
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
shape={{
|
shape={{
|
||||||
|
@ -228,6 +236,37 @@ export default React.memo(function Map() {
|
||||||
>
|
>
|
||||||
<LayerEvent type="mousemove" handler={showPopup} />
|
<LayerEvent type="mousemove" handler={showPopup} />
|
||||||
</PointLayer>,
|
</PointLayer>,
|
||||||
|
<PointLayer
|
||||||
|
key={'5'}
|
||||||
|
source={{
|
||||||
|
data,
|
||||||
|
parser: {
|
||||||
|
type: 'json',
|
||||||
|
coordinates: 'centroid',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
color={{
|
||||||
|
values: '#fff',
|
||||||
|
}}
|
||||||
|
shape={{
|
||||||
|
field: 'countryName',
|
||||||
|
values: 'text',
|
||||||
|
}}
|
||||||
|
filter={{
|
||||||
|
field: 'currentConfirmedCount',
|
||||||
|
values: (v) => {
|
||||||
|
return v > 500;
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
size={{
|
||||||
|
values: 12,
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
opacity: 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<LayerEvent type="mousemove" handler={showPopup} />
|
||||||
|
</PointLayer>,
|
||||||
]}
|
]}
|
||||||
</MapboxScene>
|
</MapboxScene>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -75,7 +75,7 @@ export default React.memo(function Map() {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const [geoData, ncovData] = await Promise.all([
|
const [geoData, ncovData] = await Promise.all([
|
||||||
fetch(
|
fetch(
|
||||||
'https://gw.alipayobjects.com/os/bmw-prod/36741c60-5e69-4c36-9033-d4ce42754a78.json',
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
).then((d) => d.json()),
|
).then((d) => d.json()),
|
||||||
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
d.json(),
|
d.json(),
|
||||||
|
|
|
@ -70,7 +70,7 @@ export default React.memo(function Map() {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const [geoData, ncovData] = await Promise.all([
|
const [geoData, ncovData] = await Promise.all([
|
||||||
fetch(
|
fetch(
|
||||||
'https://gw.alipayobjects.com/os/bmw-prod/36741c60-5e69-4c36-9033-d4ce42754a78.json',
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
).then((d) => d.json()),
|
).then((d) => d.json()),
|
||||||
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
d.json(),
|
d.json(),
|
||||||
|
|
|
@ -68,7 +68,7 @@ export default React.memo(function Map() {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
const [geoData, ncovData] = await Promise.all([
|
const [geoData, ncovData] = await Promise.all([
|
||||||
fetch(
|
fetch(
|
||||||
'https://gw.alipayobjects.com/os/bmw-prod/36741c60-5e69-4c36-9033-d4ce42754a78.json',
|
'https://gw.alipayobjects.com/os/bmw-prod/e62a2f3b-ea99-4c98-9314-01d7c886263d.json',
|
||||||
).then((d) => d.json()),
|
).then((d) => d.json()),
|
||||||
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
fetch('https://lab.isaaclin.cn/nCoV/api/area?latest=1').then((d) =>
|
||||||
d.json(),
|
d.json(),
|
||||||
|
@ -118,21 +118,14 @@ export default React.memo(function Map() {
|
||||||
}}
|
}}
|
||||||
color={{
|
color={{
|
||||||
field: 'confirmedCount',
|
field: 'confirmedCount',
|
||||||
values: (count) => {
|
values: [
|
||||||
return count > 10000
|
'#732200',
|
||||||
? '#b10026'
|
'#CC3D00',
|
||||||
: count > 1000
|
'#FF6619',
|
||||||
? '#e31a1c'
|
'#FF9466',
|
||||||
: count > 500
|
'#FFC1A6',
|
||||||
? '#fc4e2a'
|
'#FCE2D7',
|
||||||
: count > 100
|
].reverse(),
|
||||||
? '#fd8d3c'
|
|
||||||
: count > 10
|
|
||||||
? '#feb24c'
|
|
||||||
: count > 1
|
|
||||||
? '#fed976'
|
|
||||||
: 'rgb(255,255,255)';
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
shape={{
|
shape={{
|
||||||
values: 'fill',
|
values: 'fill',
|
||||||
|
|
Loading…
Reference in New Issue