# 示例:对数据进行提取中心点计算
设想我们正在开发一个需要分析计算的应用,在这个应用中我们已经能够查看用户的数据,现在我们需要将这个数据进行中心点提取,并查看提取后的结果。
示例使用 Vue 作为开发框架
# 1. 搭建页面框架
首先我们创建一个名为 data-transform.html
的页面,然后将需要处理的数据显示在地图上:
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<div id="map" style="width: 600px; height: 600px"></div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
map: null,
renderLayer: null,
accountId: '3897a3d3-3d32-4b6d-a138-489657278b70',
vdatasetId: 'a444f5c3-c384-4ea2-8543-22295fbe49cb',
},
mounted() {
this.map = new ol.Map({
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([140, 40]),
zoom: 5,
}),
});
fetch('http://localhost:9000/heycloud/api/render/layer', {
method: 'POST',
mode: 'cors',
headers: {
'content-type': 'application/json',
'x-heycloud-account-id': this.accountId,
},
body: JSON.stringify({
'datasource': {
'type': 'vdataset',
'source': this.vdatasetId,
'attrFields': ['nl_name'],
},
'style': {
'type': 'polygon-simple',
'fillColor': '#000',
'outlineColor': '#fff',
'outlineWidth': 1,
'labelField': 'nl_name',
'labelPlacement': 'interior',
'labelSize': 14,
'labelHaloRadius': 1,
},
}),
})
.then(resp => resp.json())
.then(resp => {
const { uid } = resp.result;
this.renderLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
url: `http://localhost:9000/heycloud/api/render/layer/${uid}/tile/{z}/{x}/{y}/${ol.has.DEVICE_PIXEL_RATIO||1}/image.png?x-heycloud-account-id=${this.accountId}`,
crossOrigin: '*',
}),
});
this.map.addLayer(this.renderLayer);
});
}
});
</script>
</body>
</html>
这时我们会看到这样的效果:
# 2. 添加执行提取中心点计算的按钮
下面,我们在页面上添加一个按钮,当点击这个按钮的时候,调用analytics/job/create
接口来创建一个分析任务。我们希望这个分析任务可以执行提取中心点计算,但暂时将具体执行计算的内容留空,留待下面详细解释。
<div id="app">
<div id="map" style="width: 600px; height: 600px"></div>
<div>
<button @click="process">提取中心点</button>
</div>
</div>
methods: {
process: function() {
const job = {
'title': '示例-提取中心点',
'type': 'flow',
'definition': {
// 暂时忽略
},
};
fetch('http://localhost:9000/heycloud/api/analytics/job/create', {
method: 'POST',
mode: 'cors',
headers: {
'content-type': 'application/json',
'x-heycloud-account-id': this.accountId,
},
body: JSON.stringify(job),
})
.then(resp => resp.json())
.then(resp => {
const { jobId } = resp.result;
console.log(jobId)
});
},
},
# 3. 定义具体的计算任务
在分析计算 API 的接口中,definition
属性定义了这个计算任务的具体内容。这是一个用 JSON 描述的工作流,工作流中主要有三种对象需要定义:
- node 节点,一个最小的计算单元
- link 连接,将节点和节点连接起来构成完整的工作流
- result 结果,将计算结果输出
在这里,我们需要将一个矢量数据集进行提取中心点计算,那么总共需要三个节点来构成这个工作流:
- io/ExtraceVdataset 提取矢量数据集
- transform/Centroid 提取中心点计算
- io/SaveVdataset 保存结果
具体用definition
属性定义如下:
{
"nodes": {
"node-1": {
"name": "io/ExtractVdataset",
"settings": {
"vdatasetId": "172484b1-2444-4fff-be18-eaa8b7ed8172"
}
},
"node-2": {
"name": "transform/Centroid",
},
"node-3": {
"name": "io/SaveVdataset",
}
},
"links": [
{
"from": {
"nodeId": "node-1",
"outPort": 0
},
"to": {
"nodeId": "node-2",
"inPort": 0
}
},
{
"from": {
"nodeId": "node-2",
"outPort": 0
},
"to": {
"nodeId": "node-3",
"inPort": 0
}
}
],
"results": [
{
"title": "结果",
"nodeId": "node-3",
"outPort": 0,
"outType": "kvs"
}
]
}
# 4. 检查任务的完成情况
所有的分析计算任务都是异步执行的,因此我们需要定时去检查这个任务是否已经完成,如果任务已经完成,那么通过接口获取新生成的结果数据的 ID,然后就可以通过这个 ID 将结果数据也显示到地图上:
check: function(jobId) {
fetch(`http://localhost:9000/heycloud/api/analytics/job/${jobId}`, {
method: 'GET',
mode: 'cors',
headers: {
'x-heycloud-account-id': this.accountId,
},
})
.then(resp => resp.json())
.then(resp => {
const { status } = resp.result;
if (status === 'success') {
clearInterval(this.tid);
// 获取结果
fetch(`http://localhost:9000/heycloud/api/analytics/job/${jobId}/result/0`, {
method: 'GET',
mode: 'cors',
headers: {
'x-heycloud-account-id': this.accountId,
},
})
.then(resp => resp.json())
.then(resp => {
const { vdatasetId } = resp;
this.showResult(vdatasetId);
});
}
});
},
# 5. 最终的效果和代码
页面效果如下图:
最终的页面代码:
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
<div id="app">
<div id="map" style="width: 600px; height: 600px"></div>
<div>
<button @click="process" :disabled="isProcessing">{{ isProcessing?'计算中...':'提取中心点' }}</button>
</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
map: null,
renderLayer: null,
resultLayer: null,
accountId: '3897a3d3-3d32-4b6d-a138-489657278b70',
vdatasetId: 'a444f5c3-c384-4ea2-8543-22295fbe49cb',
isProcessing: false,
tid: null,
},
mounted() {
this.map = new ol.Map({
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([140, 40]),
zoom: 5,
}),
});
fetch('http://localhost:9000/heycloud/api/render/layer', {
method: 'POST',
mode: 'cors',
headers: {
'content-type': 'application/json',
'x-heycloud-account-id': this.accountId,
},
body: JSON.stringify({
'datasource': {
'type': 'vdataset',
'source': this.vdatasetId,
'attrFields': ['nl_name'],
},
'style': {
'type': 'polygon-simple',
'fillColor': '#000',
'outlineColor': '#fff',
'outlineWidth': 1,
'labelField': 'nl_name',
'labelPlacement': 'interior',
'labelSize': 14,
'labelHaloRadius': 1,
},
}),
})
.then(resp => resp.json())
.then(resp => {
const { uid } = resp.result;
this.renderLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
url: `http://localhost:9000/heycloud/api/render/layer/${uid}/tile/{z}/{x}/{y}/${ol.has.DEVICE_PIXEL_RATIO||1}/image.png?x-heycloud-account-id=${this.accountId}`,
crossOrigin: '*',
}),
});
this.map.addLayer(this.renderLayer);
});
},
methods: {
process: function() {
this.resultLayer && this.map.removeLayer(this.resultLayer);
this.isProcessing = true;
const job = {
'title': '示例-提取中心点',
'type': 'flow',
'definition': {
"nodes": {
"node-1": {
"name": "io/ExtractVdataset",
"settings": {
"vdatasetId": this.vdatasetId,
}
},
"node-2": {
"name": "transform/Centroid",
},
"node-3": {
"name": "io/SaveVdataset",
"settings": {
"title": '示例-提取中心点结果',
}
}
},
"links": [{
"from": {
"nodeId": "node-1",
"outPort": 0
},
"to": {
"nodeId": "node-2",
"inPort": 0
}
},
{
"from": {
"nodeId": "node-2",
"outPort": 0
},
"to": {
"nodeId": "node-3",
"inPort": 0
}
}
],
"results": [{
"title": "结果",
"nodeId": "node-3",
"outPort": 0,
"outType": "kvs"
}]
},
};
fetch('http://localhost:9000/heycloud/api/analytics/job/create', {
method: 'POST',
mode: 'cors',
headers: {
'content-type': 'application/json',
'x-heycloud-account-id': this.accountId,
},
body: JSON.stringify(job),
})
.then(resp => resp.json())
.then(resp => {
const { jobId } = resp.result;
clearInterval(this.tid);
this.tid = setInterval(() => {
this.check(jobId);
}, 1000);
});
},
check: function(jobId) {
fetch(`http://localhost:9000/heycloud/api/analytics/job/${jobId}`, {
method: 'GET',
mode: 'cors',
headers: {
'x-heycloud-account-id': this.accountId,
},
})
.then(resp => resp.json())
.then(resp => {
const { status } = resp.result;
if (status === 'success') {
clearInterval(this.tid);
// 获取结果
fetch(`http://localhost:9000/heycloud/api/analytics/job/${jobId}/result/0`, {
method: 'GET',
mode: 'cors',
headers: {
'x-heycloud-account-id': this.accountId,
},
})
.then(resp => resp.json())
.then(resp => {
const { vdatasetId } = resp;
this.showResult(vdatasetId);
});
}
});
},
showResult: function(resultVdatasetId) {
fetch('http://localhost:9000/heycloud/api/render/layer', {
method: 'POST',
mode: 'cors',
headers: {
'content-type': 'application/json',
'x-heycloud-account-id': this.accountId,
},
body: JSON.stringify({
'datasource': {
'type': 'vdataset',
'source': resultVdatasetId,
},
'style': {
'type': 'marker-simple',
"markerWidth": 8,
"markerHeight": 8,
"markerColor": '#f00',
'outlineColor': '#fff',
'outlineWidth': 1,
},
}),
})
.then(resp => resp.json())
.then(resp => {
const { uid } = resp.result;
this.resultLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
url: `http://localhost:9000/heycloud/api/render/layer/${uid}/tile/{z}/{x}/{y}/${ol.has.DEVICE_PIXEL_RATIO||1}/image.png?x-heycloud-account-id=${this.accountId}`,
crossOrigin: '*',
}),
});
this.map.addLayer(this.resultLayer);
});
this.isProcessing = false;
},
},
});
</script>
</body>
</html>