docs: 官网文档新增 createModelData/updateModelData 方法的 demo、文档 (#1083)

* chore: update version 2.8.30 -> 2.8.31

* docs: 完善时间轴公交数据 demo

* style: lint style

* docs: 增加官网依赖配置

* feat: 增加公交时序数据

* docs: 为地形 demo 增加 LOD

* style: lint style

* docs: 修改公交站点时序数据的 demo

* style: lint style

* docs: 官网文档新增 createModelData/updateModelData 方法的 demo、文档
This commit is contained in:
YiQianYao 2022-04-26 19:15:43 +08:00 committed by GitHub
parent 44bfbfe803
commit a6e32892ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 333 additions and 73 deletions

View File

@ -39,3 +39,50 @@ layer.setData(data);
参数:
- type blend 类型 normal additive subtractive max
### createModelData(data: any, option?: ISourceCFG)
- data 原始数据
- options 为可选参数,一般是解析数据的 parser但是在某些特殊图层中还可能是其他的参数
```javascript
const modelData = layer.createModelData(data); // data 为 GeoJson
const modelData = layer.createModelData(data, { // data 为 json 数据
parser: {
type: 'json',
x: 'lng',
y: 'lat',
},
});
const modelData = layer.createModelData([], { // 计算 planeGeometry 的 modelData
widthSegments: 100, // planeGeometry 的顶点和 widthSegments/heightSegments 相关
heightSegments: 100,
});
```
🌟 在计算某些图层的 modelData 的时候我们需要考虑对应的时机,如 planeGeometry 在加载地形的时候
planeGeometry 的顶点位置和地形贴图相关,因此如果我们要计算实际地形顶点的模型数据,需要等待对应地形贴图加载完:
```javascript
let modelData10 = null, modelData100 = null;
layer.on('terrainImageLoaded', () => {
modelData10 = layer.createModelData([], {
widthSegments: 10,
heightSegments: 10,
});
modelData100 = layer.createModelData([], {
widthSegments: 100,
heightSegments: 100,
});
});
```
[在线案例](/zh/examples/geometry/geometry#terrain)
### updateModelData(data: IAttrubuteAndElements)
- data 是通过 createModelData 方法生成的图层的标准模型数据。
我们通过这个方法可以实时更新图层的模型数据。
[在线案例](/zh/examples/gallery/animate#timeline)

View File

@ -48,6 +48,11 @@
"filename": "box_select.js",
"title": "框选要素",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*G1lyQ6e5gKAAAAAAAAAAAAAAARQnAQ"
},
{
"filename": "timeline.js",
"title": "公交站点时序数据",
"screenshot":"https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*l2YoR56mK1EAAAAAAAAAAAAAARQnAQ"
}
]
}

View File

@ -0,0 +1,178 @@
import { Scene, PointLayer } from '@antv/l7';
import { GaodeMap } from '@antv/l7-maps';
let currentTimeKey = '0000';
let timeKeys = [];
let layer = null;
const modelDatas = {};
const parser = {
parser: {
type: 'json',
x: 'o',
y: 'a'
}
};
insetDom();
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [ 120.2, 36.1 ],
zoom: 10,
style: 'dark'
})
});
scene.on('loaded', () => {
setDragBar();
fetch(
'https://gw.alipayobjects.com/os/bmw-prod/82d85bb6-db7c-4583-af26-35b11c7b2d0d.json'
)
.then(res => res.json())
.then(originData => {
timeKeys = Object.keys(originData);
layer = new PointLayer({})
.source(originData[currentTimeKey], parser)
.shape('simple')
.size('v', v => Math.sqrt(v) / 5)
.color('v', [
'#ffffb2',
'#fed976',
'#feb24c',
'#fd8d3c',
'#f03b20',
'#bd0026'
])
.style({
opacity: 0.6
});
scene.addLayer(layer);
getModelDatas(originData);
return '';
});
return '';
});
function getModelDatas(originData) {
timeKeys.map(timeKey => {
modelDatas[timeKey] = layer.createModelData(originData[timeKey], parser);
return '';
});
}
function updateTime() {
if (layer && scene) {
layer.updateModelData(modelDatas[currentTimeKey]);
scene.render();
}
}
function setDragBar() {
const script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', 'https://cdn.bootcss.com/jquery/2.1.1/jquery.min.js');
script.async = true;
document.head.appendChild(script);
script.onload = () => {
const bar = document.getElementById('progress');
const barWidth = bar.getBoundingClientRect().width;
let tag = false,
ox = 0,
left = 0,
bgleft = 0;
const $ = window.$;
$('.progress_btn').mousedown(function(e) {
ox = e.pageX - left;
tag = true;
});
$(document).mouseup(function() { tag = false; });
$(document).mousemove(function(e) { // 鼠标移动
if (tag) {
left = e.pageX - ox;
currentTimeKey = setText(left, barWidth);
updateTime();
}
});
$('.progress_bg').click(function(e) { // 鼠标点击
if (!tag) {
bgleft = $('.progress_bg').offset().left;
left = e.pageX - bgleft;
currentTimeKey = setText(left, barWidth);
updateTime();
}
});
return '';
};
function setText(left, barWidth) {
if (left <= 0) {
left = 0;
} else if (left > barWidth) {
left = barWidth;
}
const $ = window.$;
$('.progress_btn').css('left', left);
const time = parseInt((left / barWidth) * 48);
const timeText = getTimeKey(time, ':');
const timeKey = getTimeKey(time, '');
$('.text').html(timeText);
return timeKey;
}
}
function insetDom() {
const mapContrainer = document.getElementById('map');
const wrap = document.createElement('div');
wrap.id = 'progress';
wrap.style.zIndex = 10;
wrap.style.position = 'absolute';
wrap.style.bottom = '50px';
wrap.style.left = '10%';
wrap.style.right = '10%';
wrap.innerHTML = `
<div class="progress_bg" style="
height: 6px;
border-radius: 3px;
overflow: hidden;
background-color:#f2f2f2;">
</div>
<div class="progress_btn" style="
width: 20px;
height: 20px;
border-radius: 10px;
position: absolute;
background:#ccc;
left: 0px;
margin-left: -10px; top:-9px;
cursor: pointer;
box-sizing:border-box;
">
<div class="text" style="transform:translateY(-30px); color: #fff;user-select:none">00:00</div>
</div>
`;
mapContrainer.appendChild(wrap);
}
function getTimeKey(time, text) {
const half = Math.floor(time / 2);
let res = '';
if (half < 10) {
res += '0';
}
if (time / 2 > half) {
res += half + text + '30';
} else {
res += half + text + '00';
}
return res;
}

View File

@ -11,7 +11,7 @@
},
{
"filename": "terrain.js",
"title": "自定义 3D 地形",
"title": "自定义 3D 地形LOD",
"screenshot": "https://gw.alipayobjects.com/mdn/rms_816329/afts/img/A*DIb4TaijKIAAAAAAAAAAAAAAARQnAQ"
},
{

View File

@ -11,6 +11,8 @@ const scene = new Scene({
zoom: 14
})
});
let currentZoom = 14,
currentModelData = '100x100';
scene.on('loaded', () => {
const layer = new GeometryLayer()
@ -19,8 +21,8 @@ scene.on('loaded', () => {
width: 0.074,
height: 0.061,
center: [ 120.1025, 30.2594 ],
widthSegments: 200,
heightSegments: 200,
widthSegments: 100,
heightSegments: 100,
terrainClipHeight: 1,
mapTexture:
'https://gw.alipayobjects.com/mdn/rms_23a451/afts/img/A*gA0NRbuOF5cAAAAAAAAAAAAAARQnAQ',
@ -36,4 +38,51 @@ scene.on('loaded', () => {
}
});
scene.addLayer(layer);
let modelData10,
modelData20 = null,
modelData100;
layer.on('terrainImageLoaded', () => {
modelData10 = layer.createModelData([], {
widthSegments: 10,
heightSegments: 10
});
modelData20 = layer.createModelData([], {
widthSegments: 20,
heightSegments: 20
});
modelData100 = layer.createModelData([], {
widthSegments: 100,
heightSegments: 100
});
});
scene.on('zoom', ({ value }) => {
const zoom = Math.floor(value);
if (currentZoom !== zoom) {
if (zoom > 13) {
if (currentModelData !== '100x100') {
layer.updateModelData(modelData100);
currentModelData = '100x100';
}
} else if (zoom > 12) {
if (currentModelData !== '20x20') {
layer.updateModelData(modelData20);
currentModelData = '20x20';
}
} else {
if (currentModelData !== '10x10') {
layer.updateModelData(modelData10);
currentModelData = '10x10';
}
}
currentZoom = zoom;
}
return '';
});
});

View File

@ -19,5 +19,4 @@ window.react = require('react');
window.popmotion = require('popmotion');
window.reactDom = require('react-dom');
window.antd = require('antd');
window.d3Dsv = require('d3-dsv');
window.materialUI = require('@material-ui')
window.materialUICore = require('@material-ui/core')

View File

@ -3,7 +3,6 @@ import { Scene, json } from '@antv/l7';
import { PointLayer } from '@antv/l7-layers';
import { GaodeMap } from '@antv/l7-maps';
import * as React from 'react';
import { csvParse } from 'd3-dsv';
import { styled, withStyles } from '@material-ui/core/styles';
import Slider from '@material-ui/core/Slider';
@ -13,7 +12,7 @@ export default class Demo extends React.Component {
constructor() {
this.state = {
currentYear: 50,
currentYear: 24,
modelDatas: undefined,
};
}
@ -21,34 +20,18 @@ export default class Demo extends React.Component {
this.scene.destroy();
}
public getSortedData(dataList: { DateTime: string }[]) {
const res = {},
years = [];
dataList.map((data) => {
const { DateTime } = data;
const year = DateTime.slice(0, 4);
if (res[year]) {
res[year].push({
Latitude: Number(data.Latitude),
Longitude: Number(data.Longitude),
Depth: Number(data.Depth),
Magnitude: Number(data.Magnitude),
});
} else {
years.push(year);
res[year] = [];
res[year].push({
Latitude: Number(data.Latitude),
Longitude: Number(data.Longitude),
Depth: Number(data.Depth),
Magnitude: Number(data.Magnitude),
});
public getTimeKey(time) {
const half = Math.floor(time / 2);
const res = '';
if (half < 10) {
res += '0';
}
});
return {
res,
years,
};
if (time / 2 > half) {
res += half + '30';
} else {
res += half + '00';
}
return res;
}
public getModelDatas(layer, sortedData, years, parser) {
@ -62,50 +45,37 @@ export default class Demo extends React.Component {
});
}
public generateData(size) {
let data = [];
for (let i = 0; i < size; i++) {
data.push({
lng: Math.random() * 180,
lat: Math.random() * 80 - 40,
c: Math.random() > 0.5 ? '#f00' : '#ff0',
});
}
return data;
}
public async componentDidMount() {
const scene = new Scene({
id: 'map',
map: new GaodeMap({
center: [-120, 36],
center: [120.2, 36.1],
pitch: 0,
zoom: 6,
zoom: 10,
style: 'dark',
}),
});
this.scene = scene;
// 公交出行需求量的时序数据
scene.on('loaded', () => {
fetch(
'https://gw.alipayobjects.com/os/bmw-prod/6b15fe03-9d5b-4779-831d-ec30aa2e4738.csv',
'https://gw.alipayobjects.com/os/bmw-prod/82d85bb6-db7c-4583-af26-35b11c7b2d0d.json',
)
.then((res) => res.text())
.then((res) => {
const originData = csvParse(res);
const { res: sortedData, years } = this.getSortedData(originData);
.then((res) => res.json())
.then((originData) => {
const times = Object.keys(originData);
const parser = {
parser: {
type: 'json',
x: 'Longitude',
y: 'Latitude',
x: 'o',
y: 'a',
},
};
let layer = new PointLayer()
.source(sortedData[years[0]], parser)
let layer = new PointLayer({})
.source(originData[times[0]], parser)
.shape('simple')
.size('Magnitude', (v) => Math.pow(v, 2))
.color('Magnitude', [
.size('v', (v) => Math.sqrt(v) / 5)
.color('v', [
'#ffffb2',
'#fed976',
'#feb24c',
@ -114,20 +84,20 @@ export default class Demo extends React.Component {
'#bd0026',
])
.style({
opacity: 0.5,
opacity: 0.6,
});
scene.addLayer(layer);
this.layer = layer;
this.getModelDatas(layer, sortedData, years, parser);
this.getModelDatas(layer, originData, times, parser);
});
});
}
public timelinechange(time) {
if (time !== this.state.currentYear) {
this.layer.updateModelData(this.state.modelDatas[time]);
this.layer.updateModelData(this.state.modelDatas[this.getTimeKey(time)]);
this.scene.render();
this.setState({
currentYear: time,
@ -149,9 +119,9 @@ export default class Demo extends React.Component {
>
{this.state.modelDatas !== undefined && (
<RangeInput
min={1988}
max={2018}
value={this?.state?.currentYear || 1988}
min={0}
max={48}
value={this?.state?.currentYear || 0}
onChange={(e) => this.timelinechange(e)}
/>
)}
@ -162,7 +132,7 @@ export default class Demo extends React.Component {
const PositionContainer = styled('div')({
position: 'absolute',
zIndex: 1,
zIndex: 2,
bottom: '40px',
width: '100%',
display: 'flex',
@ -173,12 +143,12 @@ const PositionContainer = styled('div')({
const SliderInput = withStyles({
root: {
marginLeft: 12,
width: '40%',
width: '60%',
},
valueLabel: {
'& span': {
background: 'none',
color: '#000',
color: '#fff',
},
},
})(Slider);
@ -192,7 +162,19 @@ function RangeInput({ min, max, value, onChange }) {
value={value}
onChange={(event, newValue) => onChange(newValue)}
valueLabelDisplay="auto"
valueLabelFormat={(t) => t}
valueLabelFormat={(t) => {
const half = Math.floor(t / 2);
const res = '';
if (half < 10) {
res += '0';
}
if (t / 2 > half) {
res += half + ':30';
} else {
res += half + ':00';
}
return res;
}}
/>
</PositionContainer>
);