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:

  1. 【 VUe-Cesium 】 3d map development using Cesium on VUE (part 1)
  2. 【 VUe-Cesium 】 3d map development using Cesium on VUE (part 2)
  3. 【 VUe-cesium 】 3d map development using Cesium on VUE (ii) Continued
  4. 【 VUe-Cesium 】 3d map development using Cesium on VUE (3)
  5. 【 VUe-cesium 】 using CESium on VUE to develop 3d map (four) map loading
  6. 【 VUe-cesium 】 Using CESium on VUE to develop 3d map (five) point loading
  7. [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:

  1. 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 rightAnd part of theContent covered, seeThe data is incompletethe
  2. This is also the third question left from yesterday, inThe operation point in the container on the leftAlthough,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 quadrangleBut I was thereIn the container on the left, it isThere will be no quadrangleBecause 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