This is the 10th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
preface
Previous articles in this series:
- 【 VUe-Cesium 】 3d map development using Cesium on VUE (part 1)
- 【 VUe-Cesium 】 3d map development using Cesium on VUE (part 2)
- 【 VUe-cesium 】 3d map development using Cesium on VUE (ii) Continued
- 【 VUe-Cesium 】 3d map development using Cesium on VUE (3)
- 【 VUe-cesium 】 using CESium on VUE to develop 3d map (four) map loading
- 【 VUe-cesium 】 Using CESium on VUE to develop 3d map (five) point loading
- [VUe-cesium] using CESium on VUE to develop 3d map (six) point frame
Common webGIS functions are shown as follows:
Today we’re going to talk about point positioning
First positioning
The API used is New Cesium.BoundingSphere
And then I want to go to this initial location, new Cesium.Camera. FlyTo
These two apis have already been introduced in the map loading tutorial, but we are just going to reuse them.
The code is as follows:
// Point to the center of the map
locationToCenter(lon, lat) {
const Cesium = this.cesium;
const pointLocation = new Cesium.BoundingSphere(Cesium.Cartesian3.fromDegrees(lon * 1, lat * 1.100), 15000); / / 120.55538, 31.87532
this.viewer.camera.flyToBoundingSphere(pointLocation);
},
Copy the code
Then add this method when you click on the dot in init()
init(){...// Listen for map click events
const handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
// Click events
handler.setInputAction((click) = >{...// Get the entity coordinates on the map
const pick = this.viewer.scene.pick(click.position);
// If pick is not undefined, then it is a point-to-point position
if (pick && pick.id) {
// Locate to the center of the map
this.locationToCenter(lon, lat); . }else {
// Remove the popbox
if (document.querySelector("#one")) {
this.removeDynamicLayer(this.viewer, { element: "#one" });
this$("#one").css("z-index", -1);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
},
Copy the code
The problem of orientation was thus solved.
To optimize the
Let’s add some content to the popup
Similarly, load JSON data in AXIos. See “Vue Start” to quickly build a Vue project and introduce third-party plug-ins
Json data is as follows:
{
"success": true."code": 200."msg": "Operation successful"."count": 8."data": {
"lowValue": "0"."unit": "mg/l"."upperValue": "1"."factorCode": "w21003"."tstamp": "The 2020-06-30 09:00:00"."factorName": "Ammonia nitrogen"."data": [{"tstamp": "The 2020-10-20 15:00:00"."factorValue": "0.32"
},
{
"tstamp": "The 2020-10-20 16:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-20 17:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-20 18:00:00"."factorValue": "0.2"
},
{
"tstamp": "The 2020-10-20 19:00:00"."factorValue": "0.3"
},
{
"tstamp": "The 2020-10-20 20:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-20 21:00:00"."factorValue": "0.4"
},
{
"tstamp": "The 2020-10-20 22:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-20 23:00:00"."factorValue": "0.4"
},
{
"tstamp": "The 2020-10-21 00:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-21 01:00:00"."factorValue": "0.8"
},
{
"tstamp": "The 2020-10-21 02:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-21 03:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-21 04:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-21 05:00:00"."factorValue": "0.3"
},
{
"tstamp": "The 2020-10-21 06:00:00"."factorValue": "0.2"
},
{
"tstamp": "The 2020-10-21 07:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-21 08:00:00"."factorValue": "0.7"
},
{
"tstamp": "The 2020-10-21 09:00:00"."factorValue": "0.1"
},
{
"tstamp": "The 2020-10-21 10:00:00"."factorValue": "0.3"
},
{
"tstamp": "The 2020-10-21 11:00:00"."factorValue": "0.14"
},
{
"tstamp": "The 2020-10-21 12:00:00"."factorValue": "0.12"
},
{
"tstamp": "The 2020-10-21 13:00:00"."factorValue": "0.05"
},
{
"tstamp": "2020-10-21 14:00:00." "."factorValue": "0.2"}}}]Copy the code
CesiumPopup. Vue: cesiumPopup
<template>
<div style="width: 532px;">
<div class="header">
<div class="title">{{pointInfo.title}}</div>
<div class="dateTime">{{dateTime}}</div>
</div>
<div class="pop-tab">
<div :class="{'tab':true, 'checked': item.checked}"
v-for="(item) in choseList" :key="item.code"
@click="choseType(item)">
{{item.label}}
</div>
</div>
<div class="factorUnitText">Units: {{curChosedUnit}}</div>
<div v-show="isChartHaveData" style="width: 435px; height: 170px;">
<Echart ref="FactorChart" :options="echartObj" :autoResize="true" style="width: 435px; height: 170px;"/>
</div>
<div v-show=! "" isChartHaveData" style="width: 445px; height: 170px; color:#909399; text-align: center; line-height: 170px;">Temporarily no data</div>
</div>
</template>
<script>
export default {
props: {
pointInfo: {
type: Object.// The type of value to be passed
default() {
return {
pointId: "--".title: "--"}; }},},data() {
return {
/ / list TAB
choseList: [{code: "SO2".label: "SO2".unit: "Mu g/m3".checked: true },
{ code: "NO2".label: "NO2".unit: "Mu g/m3".checked: false },
{ code: "PM10".label: "PM10".unit: "Mu g/m3".checked: false },
{ code: "CO".label: "CO".unit: "Mu g/m3".checked: false },
{ code: "O38".label: "O3-8".unit: "Mu g/m3".checked: false },
{ code: "PM25".label: "PM2.5".unit: "Mu g/m3".checked: false},].// The selected item by default
curChosed: "SO2".// The factor encoding is currently selected
curChosedLabel: "SO2".// The currently selected factor name
curChosedUnit: "Mu g/m3".// The factor unit is currently selected
echartObj: {}, // Graph object
dateTime: "--".// Pass time
lineChartData: [].// Graph data returned by the interface
upperValue: ""./ / ceiling
isChartHaveData: false.The false chart has no data. The true chart has data
};
},
methods: {
choseType(item) {
// Clear the previous chart
this.echartObj = {};
this.choseList.forEach((element) = > {
element.checked = false;
});
item.checked = true;
this.curChosed = item.code;
this.curChosedLabel = item.label;
this.curChosedUnit = item.unit;
this.loadEcharts();
},
loadEcharts() {
this.dateTime = "";
this.isChartHaveData = false;
// Call a specific method
this.$apiMethods
.getChartData(this.pointInfo.pointId, this.curChosed)
.then((res) = > {
// console.log(res.data.data);
if(res.data ! =null) {
this.dateTime = res.data.tstamp;
this.upperValue = res.data.upperValue;
if(res.data.data ! =null && res.data.data.length > 0) {
this.isChartHaveData = true;
this.lineChartData = res.data.data;
this.drawChart();
} else {
this.isChartHaveData = false; }}else {
this.isChartHaveData = false;
}
})
.catch(() = > {
setTimeout(() = > {
this.isChartHaveData = false;
}, 8000);
});
},
drawChart() {
const XData = []; // X-coordinate data
const YData = []; // Ordinate data
const limitData = []; // Limit data
this.lineChartData.forEach((item) = > {
XData.push(item.tstamp);
YData.push(item.factorValue);
limitData.push(this.upperValue);
});
const seriesData = [
{
name: this.curChosedLabel,
type: "line".smooth: true.stack: "Total".data: YData,
areaStyle: {},
itemStyle: {
normal: {
lineStyle: {
width: 3.// Fold width
color: "rgba(252, 254, 0, 1)",},},},}];if (this.upperValue ! =null && this.upperValue ! ="") {
seriesData.push({
name: "Standard limits".type: "line".showSymbol: false.data: limitData,
lineStyle: {
normal: {
width: 1.color: "#e74143".// Set the safety baseline color here
type: "dashed",}}}); }this.echartObj = {
tooltip: {
trigger: "axis".axisPointer: {
type: "cross".label: {
backgroundColor: "#6a7985",}}},grid: {
top: "6%".left: "6%".right: "6%".bottom: "3%".containLabel: true,},xAxis: {
type: "category".boundaryGap: false.data: XData,
axisLine: { // The color and width of the x axis
show: true.lineStyle: {
color: "white".width: 1.type: "solid",}},axisLabel: {
show: true.textStyle: {
color: "white",},// Set the calibration labels for the axes.
formatter(params) {
let newParamsName = ""; // The final concatenated string
const paramsNameNumber = params.length; // The number of actual tags
const provideNumber = 10; // The number of words per line
const rowNumber = Math.ceil(paramsNameNumber / provideNumber); // To wrap a line, display a few lines, rounded up
/** * Checks whether the number of labels is greater than the specified number. If yes, line break is performed. If no, equal to or less than, the original label */ is returned
// The condition is equivalent to rowNumber>1
if (paramsNameNumber > provideNumber) {
/** loop through each line,p for line */
// eslint-disable-next-line no-plusplus
for (let p = 0; p < rowNumber; p++) {
let tempStr = ""; // Represents each truncated string
const start = p * provideNumber; // Start intercepting position
const end = start + provideNumber; // End the intercept position
// The index value of the last row is handled specifically here
if (p === rowNumber - 1) {
// The last time no line breaks
tempStr = params.substring(start, paramsNameNumber);
} else {
// Concatenate the string each time and wrap it
tempStr = `${params.substring(start, end)}\n`;
}
newParamsName += tempStr; // The resultant string}}else {
// Assign the value of the old label to the new label
newParamsName = params;
}
// Return the final string
returnnewParamsName; }},},yAxis: {
type: "value".axisTick: false.axisLabel: {
show: true.textStyle: {
color: "white",}},splitLine: {
show: true.lineStyle: {
color: ["# 777"].opacity: 0.3.width: 1.type: "solid",}},axisLine: { // The color and width of the y axis
show: false.lineStyle: {
color: "#9dcbfb".width: 1.type: "solid",}}},itemStyle: { // Area map color Settings
color: {
type: "linear".x: 0.y: 0.x2: 0.y2: 1.colorStops: [{offset: 0.color: "rgba(252, 254, 0, 1)".// The color at 0%
},
{
offset: 1.color: "Rgba (252, 254, 0, 0.1)".// Color at 100%},].globalCoord: false.// The default is false}},series: seriesData,
};
},
clearEcharts() {
this.$refs.FactorChart.dispose(); // Clear timer when component is destroyed
},
// The loadEcharts component is always in cesiummap.vue. The v-if is not used, so it is always there. // The loadEcharts component is always in cesiummap.vue
// Therefore, we need to make a method that will be called every time the popbox opens
defalutSetting() {
// Restore default Settings
this.choseList.forEach((element) = > {
element.checked = false;
if (element.code == "SO2") {
element.checked = true;
this.curChosed = "SO2";
this.curChosedLabel = "SO2";
this.unit = "Mu g/m3"; }});this.loadEcharts(); }},mounted(){}};</script>
<style lang="scss" scoped>
.header{
position: relative;
margin-bottom: 15px;
.title{
display: inline-block;
color: #19ffff;
font-weight: 700;
font-size: 18px;
}
.dateTime{
color: #00de00;
transform: skew(-20deg);
font-size: 21px;
padding-left: 10px;
padding-right: 10px;
position: absolute;
right: 75px;
top: 0px; }}.pop-tab {
.tab {
display: inline-block;
width: 60px;
height: 40px;
background-color: transparent;
cursor: pointer;
text-align: center;
line-height: 40px;
}
.checked {
background-color: #00a2ff;
border-radius: 7px; }}.factorUnitText {
color: white;
width: 100px;
padding: 5px 0px 0px 10px;
}
</style>
Copy the code
Now look at the results:
Questions raised in the previous chapter
So at the end of the last video, we had three points, and we looked at each of them
Question 1
Since we use components to do the box, so must involve the transfer of value
A: We already did this in the popbox, passing the required values through prop, which is already used in cesiumpopup. vue
Question 2
Now the point popbox is displayed on the right, so in our common business, the point popbox is displayed on the top of the point, so how to change
A: This may be difficult for some people to understand, what is wrong with the popbox coming out from the right? This is related to GIS business, so let me draw a picture for you
In GIS project, usually on both side of the map to set two container, the two put the contents of the container, usually on the left is a list of points in a container, or point of tree structure, to the point, for example, point positioning, open play box is equivalent to operating point on the map icon, and hide/show.
The right side is sometimes used for business purposes, but in most cases it is used to display other information about the point.
Having said all this, two questions arise:
- The spot-position cartridge is displayed on the right. If the cartridge is large and the container on the right is wide, as in the case above,
It intersects the container on the right
And part of theContent covered
, seeThe data is incomplete
the - This is also the third question left from yesterday, in
The operation point in the container on the left
Although,The function is the same as manipulating point ICONS on the map
, butThere is a difference
, that is, when you manipulate the dot icon on the map, there will be oneA green quadrangle
But I was thereIn the container on the left
, it isThere will be no quadrangle
Because I didn’t click on the map
Let’s tackle the first question first:
Let the bullet frame appear in the point position above, the last article has said the bullet frame implementation, the principle of the position, see the following picture:
So this time we just need to change the top and left of the popbox div:
The modified code is as follows:
cesiumMap.vue
.methods: {...// Create an htmlElement and it will be automatically hidden behind Earth
creatHtmlElement(viewer, element, position, arr, flog){...if (Cesium.defined(canvasPosition)) {
// Set the popbox directly above the point
// ele.style.left 534 is the width of the popbox set in the CSS style.
// 30 of the 15 in ele.style.left is half the width of the dot icon
// ele.style.left the last 3 is the increment added after tweaking the page to make sure that the popbox is just above the popbox
// 30 in ele.style.top is the height of the dot icon, which is 30 by 30
// ele.style.top is 22 because there is a label above the point, the popbox can not cover the label, fine tune the result
ele.style.left = (canvasPosition.x + arr[0] - 534/2 - 15 + 5) + 'px';
ele.style.top = (canvasPosition.y + arr[1] - 30 - 22) + 'px'; . }}); },... }...Copy the code
Take a look at the effect:
Next, to solve the second problem:
If you want to make sure that you know what point it corresponds to when it comes up, you can put an arrow on the bottom of it. That’s right, let’s draw an arrow on the bottom. And then, you have the arrows, so the cesium’s click points, the quadrants, I’ll take them out
The code is as follows: HTML section
<template>
<div id="container" class="box">
<div id="cesiumContainer"></div>
<! -- Map popup -->
<div class="dynamic-layer" id="one">
<div class="line"></div>
<div class="main">
<cesiumPopup :pointInfo="popData" ref="popUp" />
<! -- More than this -->
<div class="tooltip-arrow"></div>
</div>
</div>
</div>
</template>
Copy the code
The CSS part
..tooltip-arrow{
position: absolute;
left: 45%;
bottom: -21px;
width: 0;
height: 0;
border-top: 12px solid rgba(3.22.37.0.85);
border-right: 12px solid transparent;
border-bottom: 12px solid transparent;
border-left: 12px solid transparent;
}
Copy the code
Js part
.methods: {
init(){...this.viewer = new Cesium.Viewer("cesiumContainer", {...selectionIndicator: false.// Cesium close click on the green box. }); . }... },...Copy the code
The final result
Come to an end
The basic general functions have been implemented: map loading, point loading, point popbox, point positioning, and componentation of popbox content.
The explanation of API has been interspersed in the content, so I won’t mention it separately. CTRL + C, CTRL + V, CTRL + F, CTRL + V.
As for the container on both sides of the map I said, it is completely vUE, I believe we can figure it out, using the value transfer between components, method calls between components, we can fix it.
I’ll keep updating if there are any new discoveries at Cesium.
Now that we’re all here, please give me a thumbs up before you go, because your thumbs up means a lot to me