cesium绘制编辑区域

news2024/11/19 23:34:51

 

 npm 安装也是可以的 

#默认安装最新的
yarn add cesium
 
#卸载插件
yarn remove cesium
 
#安装指定版本的
yarn add cesium@1.96.0
 
#安装指定版本到测试环境
yarn add cesium@1.96.0 -D
yarn install @turf/turf
<template>
  <div id="cesiumContainer"></div>
  <div class="but">
    <div :class="btnDraw" @click="drawPlane">开始绘制</div>
    <div :class="btnEdit" @click="echoEditing">回显编辑</div>
    <div :class="btnCleanup" @click="clean">清除</div>
    <div :class="btnThorough" @click="thoroughClean">彻底清除</div>
  </div>
  <div class="but-boxone">
    <button class="btn" v-for="(item,index) in dataGPSList.dataGPSListAPI" :key="index" @click="getClickLook(item)">{{item.name}}</button>
  </div>
</template>
  <!-- 绘制面并且编辑 -->
  <script setup lang="ts">
import * as Cesium from "cesium";
import { onMounted, reactive, ref, computed } from "vue";
import * as turf from "@turf/turf";

// 地图实例
let viewer: any;
// 存点数组,里面对象是这个{
//       lon: '',
//       lat: '',
//       hei: '',
//     };
const points: any = ref([]);
// 区域面积
const area = ref(0);
// 实体
let handler: any = null;
// 是否点击
let mouseClick = false;
// 是否移动
let mouseMove = false;
// 取消绘制
let startPicking = ref(false);
let deleteState = ref(false);
interface PositionsList {
  x: number;
  y: number;
  z: number;
}
// 存储绘制点
let tableDataObj = reactive({
  drawList: [],
});

const btnDraw = computed<string>(() => {
  return tableDataObj.drawList.length === 0
    ? "zoomIn animated_three"
    : "wobble animated_eight";
});
const btnEdit = computed<string>(() => {
  return tableDataObj.drawList.length === 0
    ? "fadeOut animated_two"
    : "fadeInDown animated";
});

const btnCleanup = computed<string>(() => {
  return tableDataObj.drawList.length === 0
    ? "fadeOutDownBig animated_six"
    : "fadeInUpBig animated_four";
});

const btnThorough = computed<string>(() => {
  return tableDataObj.drawList.length === 0
    ? "rotateOut animated_seven"
    : "rotateIn animated_five";
});

onMounted(() => {
  // 初始化Cesium并创建viewer
  Cesium.Ion.defaultAccessToken =
    "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJmMGU1MDc1Yy0zZTMyLTQ0ODEtYjcxYi0yYjAyNDgyZGY1MjQiLCJpZCI6MjAxMDQ3LCJpYXQiOjE3MTAxNjM4NjF9.b9qwNlQbvo49RJTHEMpjIiOS-mOvf9MF8ZHSYTdf6CI";
  viewer = new Cesium.Viewer("cesiumContainer", {
    infoBox: false, // 禁用沙箱,解决控制台报错
    selectionIndicator: false, //选择指示器
    timeline: false, // 时间轴
    animation: false, // 动画小组件
    geocoder: false, // 地理编码(搜索)组件
    homeButton: false, // 首页,点击之后将视图跳转到默认视角
    sceneModePicker: false, // 投影方式,切换2D、3D 和 Columbus View (CV) 模式。
    baseLayerPicker: false, // 底图组件,选择三维数字地球的底图(imagery and terrain)。
    navigationHelpButton: false, // 帮助按钮
    fullscreenButton: false, // 全屏按钮

    // vrButton: false, // VR模式
    // shouldAnimate: true, // 自动播放动画控件
    // shadows: true, // 是否显示光照投射的阴影
    // terrainShadows: Cesium.ShadowMode.RECEIVE_ONLY, // 地质接收阴影`

    // imageryProvider: esri, //自定义图层,默认是谷歌的影响图层
    scene3DOnly: true, // 每个几何实例将只能以3D渲染以节省GPU内存
    sceneMode: 3, // 初始场景模式 1 2D模式 2 2D循环模式 3 3D模式  Cesium.SceneMode
  });
  viewer._cesiumWidget._creditContainer.style.display = "none"; //隐藏logo版权
  let destination = Cesium.Cartesian3.fromDegrees(116.3974, 39.9087, 10000); // 北京天安门广场的经纬度坐标及高度
  pointerdefault();
  viewer.camera.flyTo({
    destination: destination,
    duration: 2, // 飞行动画持续时间(单位:秒)
  });
});

//开始绘制
const drawPlane = () => {
  // viewer.entities.removeAll()
  if (handler != null) {
    console.log("绘制");
    clean();
  }

  points.value = [];
  startPicking.value = false;
  // 点位存储
  let positions: any = [];
  area.value = 0;
  let polygon = new Cesium.PolygonHierarchy();
  let dynamicPolygon: any = new Cesium.Entity();
  let polyObj: any = null;
  let polyId = "planBy" + buildUUID();

  handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

  handler.setInputAction(
    (movement: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
      let pick: any = pickEllisoidPosition(viewer, movement.position);
      mouseClick = true;
      if (
        Cesium.defined(pick) &&
        Cesium.defined(pick.cartesian) &&
        pick.cartesian.x
      ) {
        positions.push(pick.cartesian.clone());
        polygon.positions.push(pick.cartesian.clone());
        if (!polyObj) {
          dynamicPolygon = {
            id: polyId,
            polyline: {
              width: 7,
              // ...lineStyle,
              material: new Cesium.PolylineOutlineMaterialProperty({
                color: Cesium.Color.AQUA.withAlpha(0.7), // 线的颜色
                outlineWidth: 4,
                outlineColor: Cesium.Color.WHITE.withAlpha(0.6),
              }),
              show: true,
              clampToGround: true,
              positions: new Cesium.CallbackProperty(function () {
                return positions;
              }, false),
            },
            polygon: {
              hierarchy: new Cesium.CallbackProperty(function () {
                return polygon;
              }, false),
              // 绘制区域颜色
              material: Cesium.Color.STEELBLUE.withAlpha(0.4),
              clampToGround: true,
            },
          };
          polyObj = viewer.entities.add(dynamicPolygon);
        }
        let ray = viewer.camera.getPickRay(movement.position);
        let cartesian = viewer.scene.globe.pick(ray, viewer.scene);
        let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
        let lng = Cesium.Math.toDegrees(cartographic.longitude); // 经度
        let lat = Cesium.Math.toDegrees(cartographic.latitude); // 纬度
        viewer.entities.add({
          id: "editPoint" + buildUUID(),
          name: "点",
          point: {
            pixelSize: 15,
            color: Cesium.Color.WHITE,
            // ...lineStyle,
            show: true,
            clampToGround: true,
            // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
          },
          distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
            0,
            3000
          ), // 可视范围
          position: Cesium.Cartesian3.fromDegrees(lng, lat, 0),
        });
      }
    },
    Cesium.ScreenSpaceEventType.LEFT_CLICK
  );

  handler.setInputAction(
    (movement: Cesium.ScreenSpaceEventHandler.PositionedEvent) => {
      if (mouseClick) {
        let pick: any = pickEllisoidPosition(viewer, movement?.endPosition);
        if (positions.length >= 0 && Cesium.defined(pick)) {
          if (mouseMove) {
            positions.pop();
            polygon.positions.pop();
          }
          if (pick.cartesian && pick.cartesian.x) {
            positions.push(pick.cartesian);
            polygon.positions.push(pick.cartesian);
            mouseMove = true;
          }
        }
      }
    },
    Cesium.ScreenSpaceEventType.MOUSE_MOVE
  );
  handler.setInputAction((movement) => {
    if (mouseClick && mouseMove) {
      positions.pop();
      polygon.positions.pop();
    }
    if (positions.length < 3) {
      alert("必须绘制三个点以上,请重新绘制");
      // 再次开启
      drawPlane();
      return;
    }

    // 计算面积
    getCalculateArea(positions);
    positions.push(positions[0]);
    mouseMove = false;
    mouseClick = false;
    points.value = [];

    for (let i = 0; i < positions.length; i++) {
      const tmp = cartesian3ToGps(viewer, positions[i]);
      const tmpPoint: object = {
        lon: tmp[0],
        lat: tmp[1],
        hei: tmp[2],
      };
      points.value.push(tmpPoint);
    }

    const arr = points.value.map((item) => [item.lon, item.lat]);
    area.value = turf.area(turf.polygon([arr])).toFixed(2) as any;

    // let pick =  viewer.scene.pick(movement.position);
    // console.log("右键:")
    pickClear(polyObj);
    // 停止绘制
    stopDraw();

    handlePolyClick();
    // 右键删除
    handlePolyRightClick();
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
};

// 计算面积
function getCalculateArea(positions: PositionsList) {
  tableDataObj.drawList = positions as any;
  console.log("cesium坐标:", tableDataObj.drawList.length);
  var areaCenter = getAreaAndCenter(positions);
  var calculatearea = areaCenter.area;
  var center = areaCenter.center;
  var text = formateArea(calculatearea, "m");
  // console.log("calculatearea面积:",calculatearea)
  // console.log("text面积",text)
  let labelId = viewer.entities.add({
    id: "label_" + buildUUID(),
    position: center,
    label: {
      text: "面积:" + text,
      // 字体大小
      font: "18px sans-serif",
      // FILL填充/OUTLINE描边/FILL_AND_OUTLINED填充描边
      style: Cesium.LabelStyle.FILL_AND_OUTLINE,
      // 描边颜色
      outlineColor: Cesium.Color.WHITE,
      // 描边宽度
      outlineWidth: 5,
      // 字体颜色
      fillColor: Cesium.Color.BLUE,
    },
  });
}

// 添加小手
function pointerdefault() {
  // 添加小手
  viewer.screenSpaceEventHandler.setInputAction(function onMouseMove(movement) {
    const pickedObject = viewer.scene.pick(movement.endPosition);
    if (pickedObject && pickedObject.id) {
      viewer.container.style.cursor = "pointer";
    } else {
      viewer.container.style.cursor = "default";
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}

// 创建完面之后监听事件
const handlePolyClick = () => {
  handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  let pickData: any;
  handler.setInputAction((event: any) => {
    let windowPosition = event.position;
    // 通过屏幕坐标获取当前位置的实体信息
    let pickedObject = viewer.scene.pick(windowPosition);
    if (Cesium.defined(pickedObject)) {
      if (/planBy/.test(pickedObject.id._id)) {
        if (pickData && pickData._id == pickedObject._id) {
          return;
        }
        pickData = pickedObject.id; //获取编辑的事件
        editPlane(pickData, handler);
      }
    } else {
      if (!pickData) {
        return;
      }
      pickClear(pickData);
      pickData = undefined;
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
};

// 右键删除
const handlePolyRightClick = () => {
  console.log("触发了么");
  // handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

  handler.setInputAction((event: any) => {
    let windowPosition = event.position;
    // 通过屏幕坐标获取当前位置的实体信息
    let pickedObject = viewer.scene.pick(windowPosition);
    let pick = viewer.scene.pick(event.position);
    // 通过屏幕坐标获取当前位置的实体信息
    let pickData: any;
    if (Cesium.defined(pickedObject)) {
      pickData = pickedObject.id; //获取编辑的事件

      pickClear(pickData);
      pickData = undefined;

      if (!deleteState.value) {
        //右键删除
        createDelteDom(event.position, pick.id.id);
      } else {
        return;
      }
    }
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
};

// 删除
function createDelteDom(px, objId) {
  deleteState.value = true;
  if (!objId) return;
  let deleteDom = window.document.createElement("span");
  deleteDom.style.background = "red";
  deleteDom.style.position = "absolute";
  deleteDom.style.color = "white";
  deleteDom.style.left = px.x + 10 + "px";
  deleteDom.style.top = px.y + 10 + "px";
  deleteDom.style.padding = "6px";
  deleteDom.style.borderRadius = "6px";
  deleteDom.style.cursor = "pointer";
  deleteDom.id = "easy3d-plot-delete";
  deleteDom.setAttribute("objId", objId);
  deleteDom.innerHTML = `删除`;
  let mapDom = window.document.getElementById(viewer.container.id);
  mapDom.appendChild(deleteDom);

  const clsBtn = window.document.getElementById("easy3d-plot-delete");
  if (!clsBtn) return;

  clsBtn.addEventListener("click", (e) => {
    let id = deleteDom.getAttribute("objId");
    removeByObjId(id);
  });
  document.addEventListener("click", function () {
    clsBtn.remove();
    deleteState.value = false;
  });
}
/**
 * 根据id移除创建的对象
 * @param {String | Number} id 对象id
 */
function removeByObjId(id) {
  console.log("查看写ID", id);
  if (!id) return;
  let entity = viewer.entities.getById(id);
  if (entity) {
    viewer.entities.remove(entity);
  }

  // 删除面积label
  let label_id = viewer.entities.values[0].id;
  var reg = new RegExp("label_");
  if (reg.test(label_id)) {
    viewer.entities.removeById(label_id);
  }
}

// 创建完面之后编辑事件
const editPlane = (pick: any, handler: any) => {
  console.log("编辑editPlane");
  if (!pick) {
    return;
  }
  // const view = viewer.entities.getById(polyId)
  pick.polyline.width = 7;
  pick.polyline.material.outlineWidth = 4;
  pick.polyline.material.outlineColor = Cesium.Color.WHITE.withAlpha(0.6);
  removeEntities(viewer, {
    filterType: "id",
    filterReg: /(editPoint)|labelPoy_/,
  });
  let pointId: any = [];
  let downStatus = false;
  let currentPoint: any; //当前编辑点
  console.log(pick.polygon.hierarchy.getValue(), "pick.polygon.hierarchy");
  let positions = pick.polygon.hierarchy.getValue(
    Cesium.JulianDate.now()
  ).positions;
  console.log("positions", positions, positions.length);
  // 生成编辑点
  for (let i = 0; i < positions.length; i++) {
    let ID = "editPoint" + buildUUID();

    let point = viewer.entities.add({
      id: ID,
      position: positions[i],
      vertexIndex: i,
      point: {
        pixelSize: 15,
        color: Cesium.Color.WHITE,
        // ...lineStyle,
        show: true,
        clampToGround: true,
        // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
      },
      distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 3000), // 可视范围
    });
    // 保存点的ID以便删除
    pointId.push(ID);
  }
  const resp = positions.map((item) => {
    let cartographic = Cesium.Cartographic.fromCartesian(item);
    let longitude = Cesium.Math.toDegrees(cartographic.longitude);
    let latitude = Cesium.Math.toDegrees(cartographic.latitude);
    return {
      longitude: longitude,
      latitude: latitude,
      height: cartographic.height,
    };
  });
  resp.push(resp[0]);
  resp.forEach((item, index) => {
    if (resp[index + 1]?.longitude) {
      let longitude = (+item.longitude + +resp[index + 1].longitude) / 2;
      let latitude = (+item.latitude + +resp[index + 1].latitude) / 2;
      let height = (+item.height + +resp[index + 1].height) / 2;
      let position = [+longitude, +latitude, +height];
      let text = distanceApi(item, resp[index + 1]).toFixed(1) + "m";
      labelApis(`labelPoy_${buildUUID()}`, position, text);
    }
  });
  handler.setInputAction((event) => {
    // 获取屏幕坐标
    let windowPosition = event.position;
    // 通过屏幕坐标获取当前位置的实体信息
    let pickedObject = viewer.scene.pick(windowPosition);
    if (Cesium.defined(pickedObject)) {
      if (/editPoint/.test(pickedObject.id._id)) {
        downStatus = true;
        viewer.scene.screenSpaceCameraController.enableRotate = false;
        viewer.scene.screenSpaceCameraController.enableZoom = false;
        currentPoint = pickedObject.id;
        console.log(currentPoint);
      } else {
        viewer.scene.screenSpaceCameraController.enableRotate = true;
        viewer.scene.screenSpaceCameraController.enableZoom = true;
        return false;
      }
    } else {
      viewer.scene.screenSpaceCameraController.enableRotate = true;
      viewer.scene.screenSpaceCameraController.enableZoom = true;
      return false;
    }
  }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
  handler.setInputAction((event) => {
    if (!downStatus) {
      return;
    }
    removeEntities(viewer, {
      filterType: "id",
      filterReg: /labelPoy_|label_/,
    });
    let windowPosition = event.startPosition;
    // 将屏幕坐标转为笛卡尔坐标
    let ellipsoid = viewer.scene.globe.ellipsoid;
    let cartesian = viewer.camera.pickEllipsoid(windowPosition, ellipsoid);
    // 如果点击到地球外,那么返回
    if (!cartesian) {
      return;
    }
    // 更新编辑点的位置
    // console.log(currentPoint, cartesian);
    currentPoint.position._value = cartesian;
    let point: any = []; // 线的定位
    let polyData: any = [];
    for (let id of pointId) {
      // console.log(viewer.entities.getById(id), "0");
      point.push(viewer.entities.getById(id).position._value);
      polyData.push(viewer.entities.getById(id).position._value);
    }
    // const data = viewer.entities.getById(polyId)
    positions = point;

    point.push({ x: point[0]["x"], y: point[0]["y"], z: point[0]["z"] });

    const resp = point.map((item) => {
      let cartographic = Cesium.Cartographic.fromCartesian(item);
      let longitude = Cesium.Math.toDegrees(cartographic.longitude);
      let latitude = Cesium.Math.toDegrees(cartographic.latitude);
      return {
        lon: longitude,
        lat: latitude,
        height: cartographic.height,
      };
    });

    points.value = resp;
    const resps = points.value.map((item) => {
      return {
        longitude: item.lon,
        latitude: item.lat,
        height: item.height,
      };
    });
    // resp.push(resp[0])
    resps.forEach((item, index) => {
      if (resps[index + 1]?.longitude) {
        let longitude = (+item.longitude + +resps[index + 1].longitude) / 2;
        let latitude = (+item.latitude + +resps[index + 1].latitude) / 2;
        let height = (+item.height + +resps[index + 1].height) / 2;
        let position = [+longitude, +latitude, +height];
        let text = distanceApi(item, resps[index + 1]).toFixed(1) + "m";
        labelApis(`labelPoy_${buildUUID()}`, position, text);
      }
    });
    pick.polyline.positions = point;
    pick.polygon.hierarchy = polyData;
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
  handler.setInputAction(() => {
    if (!downStatus) {
      return;
    }
    // removeEntities(viewer, {
    //   filterType: "id",
    //   filterReg: /label_/,
    // });
    console.log(points.value, "value");
    console.log("positions", positions);
    // 重新计算面积
    getCalculateArea(positions);

    viewer.scene.screenSpaceCameraController.enableRotate = true;
    viewer.scene.screenSpaceCameraController.enableZoom = true;
    downStatus = false;
    currentPoint = undefined;
  }, Cesium.ScreenSpaceEventType.LEFT_UP);
  // }
};
const pickClear = (pickData: any) => {
  pickData.polyline.width = 5;
  pickData.polyline.material.outlineWidth = 2;
  pickData.polyline.material.outlineColor = Cesium.Color.WHITE.withAlpha(0.4);
  removeEntities(viewer, {
    filterType: "id",
    filterReg: /(editPoint)|labelPoy_/,
  });
};
//结束绘制
const stopDraw = () => {
  if (handler) {
    handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
    handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOWN);
    handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_UP);
    handler?.destroy();
    startPicking.value = true;
    handler = null;
  }
};
// 随机数字
const buildUUID = () => {
  const hexList: string[] = [];
  for (let i = 0; i <= 15; i++) {
    hexList[i] = i.toString(16);
  }
  let uuid = "";
  for (let i = 1; i <= 36; i++) {
    if (i === 9 || i === 14 || i === 19 || i === 24) {
      uuid += "-";
    } else if (i === 15) {
      uuid += 4;
    } else if (i === 20) {
      uuid += hexList[(Math.random() * 4) | 8];
    } else {
      uuid += hexList[(Math.random() * 16) | 0];
    }
  }
  return uuid.replace(/-/g, "");
};
/**
 * @description: cesium获取两点之间距离 (m)
 * @param {*} root 当前组件的根实例
 * @param {*} point1 坐标1
 * @param {*} point2  坐标2
 * @return {*} 距离
 */
const distanceApi = (position1: any, position2: any) => {
  let cartesian1 = Cesium.Cartesian3.fromDegrees(
    position1.longitude,
    position1.latitude,
    position1.height
  );
  let cartesian2 = Cesium.Cartesian3.fromDegrees(
    position2.longitude,
    position2.latitude,
    position2.height
  );

  var point1cartographic = Cesium.Cartographic.fromCartesian(cartesian1);
  var point2cartographic = Cesium.Cartographic.fromCartesian(cartesian2);

  /**根据经纬度计算出距离**/
  var geodesic = new Cesium.EllipsoidGeodesic();
  geodesic.setEndPoints(point1cartographic, point2cartographic);
  var distance = geodesic.surfaceDistance;
  //返回两点之间的距离
  return (distance = Math.sqrt(
    Math.pow(distance, 2) +
      Math.pow(point2cartographic.height - point1cartographic.height, 2)
  ));
};
/**
 * 删除地图上的实体
 * @param viewer
 * @param option
 */
const removeEntities = (viewer: Cesium.Viewer, option: any) => {
  if (!viewer) {
    return;
  }
  const removedId: string[] = [];
  viewer.entities.values.map((item) => {
    if (option.filterType == "id") {
      if (option.filterReg.test(item.id)) {
        removedId.push(item.id);
      }
    }
  });
  removedId.sort(function (a, b) {
    return b.indexOf("measureLineXL") !== -1 ? 1 : -1;
  });
  removedId.map(function (item) {
    viewer.entities.removeById(item);
  });
};
/**
 * cartesian3转gps
 * @param viewer
 * @param cartesian
 * @returns
 */
const cartesian3ToGps = (
  viewer: Cesium.Viewer,
  cartesian: Cesium.Cartesian3
): number[] => {
  const cartographic =
    viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian);
  return [
    Cesium.Math.toDegrees(cartographic.longitude),
    Cesium.Math.toDegrees(cartographic.latitude),
    cartographic.height,
  ];
};
/**
 * 拾取球面坐标
 * @param viewer  场景视图
 * @param position 屏幕坐标
 * @returns array 地理坐标数组
 */
const pickEllisoidPosition = (
  viewer: Cesium.Viewer,
  position: Cesium.Cartesian2
) => {
  const pickRay = viewer.scene.camera.getPickRay(position);
  if (pickRay) {
    const cartesian = viewer.scene.globe.pick(pickRay, viewer.scene);
    if (cartesian) {
      const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
      const result = {
        geoPositon: [
          Cesium.Math.toDegrees(cartographic.longitude),
          Cesium.Math.toDegrees(cartographic.latitude),
          cartographic.height,
        ],
        cartesian: cartesian,
      };
      return result;
    }
  }
};

const labelApis = (id, position, text) => {
  viewer.entities.add({
    id: id,
    name: "labelApi",
    position: Cesium.Cartesian3.fromDegrees(...position),
    label: {
      text: text,
      showBackground: true, //显示背景
      backgroundColor: new Cesium.Color.fromCssColorString("rgba(0,0,0,0.7)"),
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER, //对齐方式
      font: "16px sans-serif",
      fillColor: Cesium.Color.MIDNIGHTBLUE,
      outlineColor: Cesium.Color.WHITE,
      style: Cesium.LabelStyle.FILL_AND_OUTLINE,
      outlineWidth: 4,
      pixelOffset: new Cesium.Cartesian2(0, -10), // 视角偏移
      verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
      distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 400000), // 可视范围
      eyeOffset: new Cesium.Cartesian3(0, 0, -30),
    },
  });
};

const clean = () => {
  removeEntities(viewer, {
    filterType: "id",
    filterReg: /(editPoint)|planBy|labelPoy_|label_/,
  });
  // 停止绘制

  stopDraw();

  // console.log(handler, "handler");
};
// 彻底清除
function thoroughClean() {
  tableDataObj.drawList = [];
  clean();
}
const echoEditing = () => {
  //   let square=ref()
  // console.log("square",square)
  clean();
  let polyObj: any = null;
  let polyId = "planBy" + buildUUID();
  // 点位存储

  let polygon = new Cesium.PolygonHierarchy();
  let dynamicPolygon: any = new Cesium.Entity();
  let pointData: any = [];
  pointData = tableDataObj.drawList;
  let points: any = [];
  // console.log("drawList",tableDataObj.drawList)
  // console.log("pointData",pointData)
  if (pointData.length == 0) {
    alert("没有点位数据,无法回显!!!");
    return;
  }
  for (let i = 0; i < pointData.length; i++) {
    const tmp = cartesian3ToGps(viewer, pointData[i]);
    points.push(tmp[0], tmp[1], tmp[2]);
  }
  // console.log(points, "lll");

  if (!polyObj) {
    dynamicPolygon = {
      id: polyId,
      polyline: {
        width: 7,
        // ...lineStyle,
        material: new Cesium.PolylineOutlineMaterialProperty({
          color: Cesium.Color.AQUA.withAlpha(0.7), // 线的颜色
          outlineWidth: 4,
          outlineColor: Cesium.Color.WHITE.withAlpha(0.6),
        }),
        show: true,
        clampToGround: true,
        positions: Cesium.Cartesian3.fromDegreesArrayHeights(points),
      },
      polygon: {
        hierarchy: Cesium.Cartesian3.fromDegreesArrayHeights(points),
        material: Cesium.Color.STEELBLUE.withAlpha(0.4),
        clampToGround: true,
      },
    };
    polyObj = viewer.entities.add(dynamicPolygon);
    handlePolyClick();
    // 计算面积
    getCalculateArea(pointData);
    // 右键删除
    handlePolyRightClick();
  }
};

//调用第三方插件计算面积 turf
function getAreaAndCenter(positions: any) {
  if (!positions || positions.length < 1) return;
  var cartographics = [];
  var turfPoints = [];
  for (var i = 0; i < positions.length; i++) {
    var cartesian3 = positions[i];
    var cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
    cartographics.push([
      Cesium.Math.toDegrees(cartographic.longitude),
      Cesium.Math.toDegrees(cartographic.latitude),
    ]);
    turfPoints.push(
      turf.point([
        Cesium.Math.toDegrees(cartographic.longitude),
        Cesium.Math.toDegrees(cartographic.latitude),
      ])
    );
  }
  if (!cartographics.length) return;
  cartographics = cartographics.concat([cartographics[0]]);
  var polygon = turf.polygon([cartographics]);
  var area = turf.area(polygon);
  //获取当前范围的中心点
  var features = turf.featureCollection(turfPoints);
  var turfCenter = turf.center(features);
  var center = turfCenter.geometry.coordinates;

  return {
    area: area,
    center: Cesium.Cartesian3.fromDegrees(center[0], center[1]),
  };
}
function formateArea(val: any, dw: string) {
  if (val == undefined) return;
  let dwStr = "";
  dw = dw || "m";
  if (dw == "km" || dw == "平方千米") {
    dwStr += (Number(val) / 1000000).toFixed(2) + "km²";
  } else if (dw == "m" || dw == "平方米") {
    dwStr += Number(val).toFixed(2) + "m²";
  } else {
  }
  return dwStr;
}
onMounted(() => {
  // 本地假数据
  getLooklook();
  // 假数据
  // falseDataLook()
});
// 背地造的数据
let dataGPSList =reactive({
  dataGPSListAPI:[
    {
      id: 1,
      name:"测试数据1",
      dataval: {
        startList: {
          Lon: 115.9931488639,
          Lat: 39.0063934815,
        },
        endList: {
          Lon: 115.99045942,
          Lat: 39.0063929,
        },
        carryoutList: [
          {
            Lon: 115.99299873,
            Lat: 39.006393800000005,
          },
          {
            Lon: 115.992,
            Lat: 39.0063932,
          },
          {
            Lon: 115.9916123,
            Lat: 39.0063931,
          },
        ],
      },
    },
    {
      id: 2,
      name:"测试数据2",
      dataval: {
        startList: {
          Lon: 115.99045942,
          Lat: 39.0063929,
        },
        endList: {
          Lon: 115.9884542,
          Lat: 39.0063931,
        },
        carryoutList: [
          {
            Lon: 115.9898,
            Lat: 39.0063938005,
          },
          {
            Lon: 115.9894,
            Lat: 39.0063932,
          },
          {
            Lon: 115.9889542,
            Lat: 39.0063931,
          },
        ],
      },
    },
  ]
});
function getClickLook(itemval?:any){
  let destination = Cesium.Cartesian3.fromDegrees(
    itemval.dataval.endList.Lon,
    itemval.dataval.endList.Lat,
    1000
  ); // 设置目标位置

  // 设置相机位置
  viewer.camera.flyTo({
    destination: destination,
    duration: 2, // 飞行动画持续时间(单位:秒)
  });
}
// 查看
function getLooklook() {

  let destination = Cesium.Cartesian3.fromDegrees(
    dataGPSList.dataGPSListAPI[0].dataval.startList.Lon,
    dataGPSList.dataGPSListAPI[0].dataval.startList.Lat,
    1000
  ); // 设置目标位置

  // 设置相机位置
  viewer.camera.flyTo({
    destination: destination,
    duration: 2, // 飞行动画持续时间(单位:秒)
  });
  // const point2 = viewer.entities.add({
  //   id: "point",
  //   position: Cesium.Cartesian3.fromDegrees( 115.9898, 39.0063931),
  //   point: {
  //     pixelSize: 20, //像素大小
  //     color: Cesium.Color.RED,
  //     outlineColor: Cesium.Color.WHITE,
  //     // outlineWidth: 20,
  //     heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
  //   },
  // });

 
dataGPSList.dataGPSListAPI.map((item:any)=>{
  let   itemdata=item.dataval
  let   endListData=itemdata.endList
  let   carryoutListData=itemdata.carryoutList
  let   startListData=itemdata.startList
  let   carryoutListLengthMinusone=carryoutListData[carryoutListData.length-1]
    // 总长度
    const totalData = getFlatternDistance(startListData.Lat, startListData.Lon, endListData.Lat, endListData.Lon);
  // 【面】
  // 未完成
  funPolygon(buildUUID(), "#e90707", [endListData.Lat, endListData.Lon, carryoutListData[carryoutListData.length - 1].Lat, carryoutListData[carryoutListData.length - 1].Lon]);
  // 完成第一阶段(最右边开始)
  funPolygon(buildUUID(), "#00D764", [carryoutListData[0].Lat, carryoutListData[0].Lon,startListData.Lat, startListData.Lon]);
  //已完成中间段(去除第一阶段)  
  for(let i=0;i<carryoutListData.length-1;i++){
    funPolygon(buildUUID(), "#00D764", [ carryoutListData[i+1].Lat, carryoutListData[i+1].Lon,carryoutListData[i].Lat, carryoutListData[i].Lon]);
    // 【竖线下#fff】
    funLine(buildUUID(), "#fff", [carryoutListData[i].Lon,carryoutListData[i].Lat]);
    // 【箭头百分比】
    //中间已完成
    let yesData = getFlatternDistance(carryoutListData[i].Lat, carryoutListData[i].Lon,carryoutListData[i+1].Lat, carryoutListData[i+1].Lon);
    //中间已完成 百分比
    let yesPercent=((yesData / totalData) * 100).toFixed(2);
    // 中间已完成
    funArrowLin(buildUUID(), "#33CC00", [carryoutListData[i].Lon, carryoutListData[i].Lat,carryoutListData[i+1].Lon,carryoutListData[i+1].Lat], yesPercent);



  }
  // 【竖线-下】
  // 最右边的竖线
  funLine(buildUUID(), "#fff", [endListData.Lon,endListData.Lat])
  // 最左边的竖线
  funLine(buildUUID(), "#fff", [startListData.Lon,startListData.Lat]);
  // 为了不多写一个循环加上(靠右的第二个竖线) 【竖线下#fff】
  funLine(buildUUID(), "#fff", [carryoutListLengthMinusone.Lon,carryoutListLengthMinusone.Lat]);

  // // 竖线循环 多一个循环 若使用次循环则注释掉【竖线下#fff】
  // for(let i=0;i<carryoutListData.length;i++){
  //   funLine(buildUUID(), "#fff", [carryoutListData[i].Lon,carryoutListData[i].Lat]);
  // }

  // 【竖线-上】
  funLine(buildUUID(), "#33FFFF", [startListData.Lon, startListData.Lat], true);
  funLine(buildUUID(), "#33FFFF", [carryoutListLengthMinusone.Lon, carryoutListLengthMinusone.Lat], true);

  // 【箭头百分比】
  // // 总长度
  // const totalData = getFlatternDistance(startListData.Lat, startListData.Lon, endListData.Lat, endListData.Lon);
  
  // 未完成
  const notData = getFlatternDistance(endListData.Lat, endListData.Lon, carryoutListLengthMinusone.Lat, carryoutListLengthMinusone.Lon);
  // 未完成百分比
  const notPercent = ((notData / totalData) * 100).toFixed(2);
  // 未完成
  funArrowLin(buildUUID(), "#FF0033", [carryoutListLengthMinusone.Lon, carryoutListLengthMinusone.Lat,endListData.Lon, endListData.Lat], notPercent);
  // 第一阶段已完成
  const alreadyData = getFlatternDistance(startListData.Lat, startListData.Lon, carryoutListData[0].Lat, carryoutListData[0].Lon);
  // 第一阶段已完成
   const alreadyPercent = ((alreadyData / totalData) * 100).toFixed(2);
  funArrowLin(buildUUID(), "#33CC00", [startListData.Lon,startListData.Lat, carryoutListData[0].Lon, carryoutListData[0].Lat], alreadyPercent);
  //已完成所有【上】 
  funArrowLin(buildUUID(),"#33FF00",[startListData.Lon,startListData.Lat,carryoutListLengthMinusone.Lon,carryoutListLengthMinusone.Lat],(100 - Number(notPercent)).toString(),true);
})

 
}
function falseDataLook(){

  let nowLat = 39.0063934815; // 最右边
  let nowLon = 115.9931488639;
  let startLat = 39.0063929; //最左边
  let startLon = 115.99045942;
  let endLat = 39.006393800000005; //右1
  let endLon = 115.99299873;

  let endLat1 = 39.0063932;
  let endLon1 = 115.992;
  let endLat2 = 39.0063931;
  let endLon2 = 115.9916123;
    
 
 
 
  let destination = Cesium.Cartesian3.fromDegrees(
    115.9931488639,
    39.0063934815,
    1000
  ); // 设置目标位置

  // 设置相机位置
  viewer.camera.flyTo({
    destination: destination,
    duration: 2, // 飞行动画持续时间(单位:秒)
  });
 // 面
  const arrone = [startLat, startLon, endLat2, endLon2];
  const arrtwo = [endLat, endLon, nowLat, nowLon];
  funPolygon(buildUUID(), "#e90707", arrone);
  funPolygon(buildUUID(), "#00D764", arrtwo);
  funPolygon(buildUUID(), "#00D764", [endLat1, endLon1, nowLat, nowLon]);
  funPolygon(buildUUID(), "#00D764", [endLat2, endLon2, endLat1, endLon1]);

  // 线
  const arrthtee = [startLon, startLat];
  const arrfour = [endLon, endLat];
  const arrfive = [nowLon, nowLat];
  funLine(buildUUID(), "#fff", arrthtee);
  funLine(buildUUID(), "#fff", arrfour);
  funLine(buildUUID(), "#fff", arrfive);
  funLine(buildUUID(), "#fff", [endLon1, endLat1]);

  // //总长度
  const totalData = getFlatternDistance(nowLat, nowLon, startLat, startLon);
  // 已
  const alreadyData = getFlatternDistance(nowLat, nowLon, endLat, endLon);
  const alreadyData1 = getFlatternDistance(endLat1, endLon1, endLat, endLon);
  const alreadyData2 = getFlatternDistance(endLat1, endLon1,endLat2, endLon2);
  // 未
  const notData = getFlatternDistance(startLat, startLon, endLat2, endLon2);

  // 计算百分比
  const alreadyPercent = ((alreadyData / totalData) * 100).toFixed(2);
  // 显示百分比
  const notPercent = ((notData / totalData) * 100).toFixed(2);

  const alreadyPercent1 = ((alreadyData1 / totalData) * 100).toFixed(2);
  const alreadyPercent2 = ((alreadyData2 / totalData) * 100).toFixed(2);
  
  // 第一阶段已完成
  let arrowLinyes = [nowLon, nowLat, endLon, endLat];
  funArrowLin(buildUUID(), "#33CC00", arrowLinyes, alreadyPercent);
  // 第二阶段已完成
  let arrowLinyes1 = [endLon, endLat, endLon1, endLat1];
  funArrowLin(buildUUID(), "#00CC00", arrowLinyes1, alreadyPercent1);
  let arrowLinyes2 = [endLon1, endLat1,endLon2, endLat2];
  funArrowLin(buildUUID(), "#00CC00", arrowLinyes2, alreadyPercent2);
  
  // 未完成
  let arrowLinnot = [endLon1, endLat1, startLon, startLat];
  funArrowLin(buildUUID(), "#FF0033", arrowLinnot, notPercent);

  funLine(buildUUID(), "#33FFFF", [nowLon, nowLat], true);
  funLine(buildUUID(), "#33FFFF", [endLon2, endLat2], true);
  let arrowLinyesall = [nowLon, nowLat, endLon2, endLat2];
  console.log(notPercent);
  funArrowLin(
    buildUUID(),
    "#33FF00",
    arrowLinyesall,
    (100 - Number(notPercent)).toString(),
    true
  );
}

// 绘制竖线
const funLine = (
  id: string,
  color: string,
  pointsList: any,
  topisno?: boolean
) => {
  // 计算偏移后的经纬度
  let offsetDistance1 = 0.0001; // 调整偏移距离以满足您的需求
  let offsetDistance = 0.00025; // 调整偏移距离以满足您的需求
  if (topisno) {
    offsetDistance1 = -0.00035;
    offsetDistance = -0.0002;
  }
  // 提取经纬度
  const lon1 = pointsList[0];
  const lat1 = pointsList[1] - offsetDistance1;
  const lon2 = pointsList[0];
  const lat2 = pointsList[1] - offsetDistance;

  const positionsData = [lon1, lat1, lon2, lat2];

  let line = viewer.entities.add({
    id: "Linecolor_" + id,
    name: "Vertical",
    polyline: {
      positions: Cesium.Cartesian3.fromDegreesArray(positionsData),
      width: 2,

      material: new Cesium.PolylineOutlineMaterialProperty({
        color: Cesium.Color.fromCssColorString(color),
        outlineColor: Cesium.Color.fromCssColorString(color),
      }),
      // 是否贴地显示
      clampToGround: true,
      // 显示在距相机的距离处的属性,多少区间内是可以显示的
      distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500), // 可视范围,
      // 是否显示
      show: true,
    },
  });
};
// 箭头线
function funArrowLin(
  id: string,
  color: string,
  pointsList: any,
  percentage?: string,
  topisno?: boolean
) {
  // 计算偏移后的经纬度
  let offsetDistance = 0.0002; // 调整偏移距离以满足您的需求
  if (topisno) {
    offsetDistance = -0.0003;
  }
  // 提取经纬度
  const lon1 = pointsList[0];
  const lat1 = pointsList[1] - offsetDistance;
  const lon2 = pointsList[2];
  const lat2 = pointsList[3] - offsetDistance;
  const positions = [lon1, lat1, lon2, lat2];

  // 计算线段中点的经纬度坐标
  const midLon = (lon1 + lon2) / 2;
  const midLat = (lat1 + lat2) / 2;

  // 添加百分比数值标签
  let label = viewer.entities.add({
    id: "ArrowLin_" + id,
    position: Cesium.Cartesian3.fromDegrees(midLon, midLat),
    label: {
      text: percentage + "%",
      font: "14px sans-serif",
      fillColor: Cesium.Color.WHITE,
      outlineColor: Cesium.Color.WHITE,
      outlineWidth: 1,
      style: Cesium.LabelStyle.FILL_AND_OUTLINE,
      pixelOffset: new Cesium.Cartesian2(0, topisno ? -10 : 10), // 垂直偏移量,使其看起来在线段中间
      // 显示在距相机的距离处的属性,多少区间内是可以显示的
      distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500), // 可视范围,
      eyeOffset: new Cesium.Cartesian3(0, 0, -30),
    },
  });
  let line = viewer.entities.add({
    id: id,
    name: "schedule",
    polyline: {
      positions: Cesium.Cartesian3.fromDegreesArray(positions),
      width: 12,
      material: new Cesium.PolylineArrowMaterialProperty(
        Cesium.Color.fromCssColorString(color)
      ),
      // 是否贴地显示
      clampToGround: true,
      // 显示在距相机的距离处的属性,多少区间内是可以显示的
      distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500), // 可视范围,
      // 是否显示
      show: true,
    },
  });
}
//计算两点间距离
function getFlatternDistance(lat1, lng1, lat2, lng2) {
  var EARTH_RADIUS = 6378137.0; //单位M
  var PI = Math.PI;

  function getRad(d) {
    return (d * PI) / 180.0;
  }

  var f = getRad((lat1 + lat2) / 2);
  var g = getRad((lat1 - lat2) / 2);
  var l = getRad((lng1 - lng2) / 2);

  var sg = Math.sin(g);
  var sl = Math.sin(l);
  var sf = Math.sin(f);

  var s, c, w, r, d, h1, h2;
  var a = EARTH_RADIUS;
  var fl = 1 / 298.257;

  sg = sg * sg;
  sl = sl * sl;
  sf = sf * sf;

  s = sg * (1 - sl) + (1 - sf) * sl;
  c = (1 - sg) * (1 - sl) + sf * sl;

  w = Math.atan(Math.sqrt(s / c));
  r = Math.sqrt(s * c) / w;
  d = 2 * w * a;
  h1 = (3 * r - 1) / 2 / c;
  h2 = (3 * r + 1) / 2 / s;

  return d * (1 + fl * (h1 * sf * (1 - sg) - h2 * (1 - sf) * sg));
}
// 绘制面积
function funPolygon(id: string, color: string, pointsList: any) {
  // let latone = 39.0063929; //buildBeginMileageLat  1
  // let lonone = 115.99045942; //buildBeginMileageLon  0
  // let lattwo = 39.0063934815; //nowlat  3
  // let lontwo = 115.9931488639; //nowlon 2
  let latone = pointsList[0];
  let lonone = pointsList[1];
  let lattwo = pointsList[2];
  let lontwo = pointsList[3];
  // let destination = Cesium.Cartesian3.fromDegrees(lontwo, lattwo, 1000); //
  // //  添加小手
  // // pointerdefault();
  // viewer.camera.flyTo({
  //   destination: destination,
  //   duration: 2, // 飞行动画持续时间(单位:秒)
  // });
  // 计算偏移后的经纬度
  const offsetDistance = 0.0001; // 调整偏移距离以满足您的需求
  //   // 提取经纬度
  // const lon1 = lonone;
  // const lat1 = latone - offsetDistance;
  // const lon2 = lontwo;
  // const lat2 = lattwo - offsetDistance;

  // const lon1Offset = lon1;
  // const lat1Offset = lat1 + offsetDistance+ offsetDistance;
  // const lon2Offset = lon2;
  // const lat2Offset = lat2 + offsetDistance+ offsetDistance;

  // // 添加四个点的经纬度数组
  // // const positionsList = [
  // //   lon1, lat1,
  // //   lon2, lat2,
  // //   lon2Offset, lat2Offset,
  // //   lon1Offset, lat1Offset,
  // //   lon1, lat1 // 闭合面
  // // ];

  const leftTop = [lonone, latone - offsetDistance]; //左上角经度
  const leftBottom = [lontwo, lattwo - offsetDistance]; //左下角经度
  const rightTop = [lontwo, lattwo + offsetDistance * 2]; //右上角经度
  const rightBottom = [lonone, latone + offsetDistance * 2]; //右下角经度

  let dataList = [leftTop, rightBottom, rightTop, leftBottom, leftTop];
  let positionsList = dataList.flat(Infinity) as [];
  // console.log("positionsList", positionsList);
  // 创建多边形面
  let rectangleBox = viewer.entities.add({
    id: "Redcolor_" + id,
    name: "polygonMileage",
    polygon: {
      hierarchy: Cesium.Cartesian3.fromDegreesArray(positionsList),
      // 颜色
      material: Cesium.Color.fromAlpha(
        Cesium.Color.fromCssColorString(color), //#e90707
        0.5
      ),
      // 是否贴地显示
      clampToGround: true,
      // 显示在距相机的距离处的属性,多少区间内是可以显示的
      //  distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1500), // 可视范围,
      // 是否显示
      show: true,

      height: 1, // 高度
      extrudedHeight: 1, //获取或设置数字属性,该属性指定矩形拉伸的高度。设置此属性将创建从高处开始并在此高度处结束的体积
      // 表示相对于地形的位置。【CLAMP_TO_GROUND 该位置固定在地形上】【NONE 该位置是绝对的。】【RELATIVE_TO_GROUND 位置高度是指地形上方的高度。】
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      outline: true, //是否展示外线
      outlineColor: Cesium.Color.fromAlpha(
        Cesium.Color.fromCssColorString("#f30202"),
        0.5
      ), //外线颜色
      outlineWidth: 2, //外线宽度
      fill: true, //是否填充
    },
  });
  // viewer.zoomTo(rectangleBox);
}
</script>
  
  <style scoped>
#cesiumContainer {
  position: absolute;
  width: 100%;
  height: 100%;
  top: 0px;
  left: 0px;
  margin: 0;
  padding: 0;
  overflow: hidden;
}
.but {
  position: absolute;
  top: 50px;
  left: 100px;
  width: 200px;
  height: 20px;
  display: flex;
  justify-content: space-between;
  /* background-color: black; */
  z-index: 2;
}
.but div {
  height: 20px;
  font-size: 14px;
  z-index: 2;
  cursor: pointer;
  min-width: 100px;
  text-align: center;
  padding: 10px;
  background: rgba(0, 0, 0, 0.5);
  color: #fff;
  border-radius: 5px;
  margin-left: 10px;
}
</style>
<style lang="scss" scoped>
.but-boxone {
  position: absolute;
  top: 100px;
  left: 100px;
  width: 200px;
  display: flex;
  justify-content: space-between;
  .btn {
    font-size: 14px;
    z-index: 2;
    cursor: pointer;
    min-width: 100px;
    text-align: center;
    padding: 10px;
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    border-radius: 5px;
    margin-left: 10px;
  }
}
</style>

<style lang="scss" scoped>
.animated {
  -webkit-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}

.animated.infinite {
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}

.animated.hinge {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
}

/*the animation definition*/

@-webkit-keyframes fadeInDown {
  0% {
    opacity: 0;
    -webkit-transform: translate3d(0, -100%, 0);
    transform: translate3d(0, -100%, 0);
  }
  100% {
    opacity: 1;
    -webkit-transform: none;
    transform: none;
  }
}

@keyframes fadeInDown {
  0% {
    opacity: 0;
    -webkit-transform: translate3d(0, -100%, 0);
    -ms-transform: translate3d(0, -100%, 0);
    transform: translate3d(0, -100%, 0);
  }
  100% {
    opacity: 1;
    -webkit-transform: none;
    -ms-transform: none;
    transform: none;
  }
}

.fadeInDown {
  -webkit-animation-name: fadeInDown;
  animation-name: fadeInDown;
}

/*base code*/
.animated_two {
  -webkit-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
.animated_two.infinite {
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}
.animated_two.hinge {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
}
/*the animation definition*/
@-webkit-keyframes fadeOut {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
@keyframes fadeOut {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
.fadeOut {
  -webkit-animation-name: fadeOut;
  animation-name: fadeOut;
}

/*base code*/
.animated_three {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
.animated_three.infinite {
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}
.animated_three.hinge {
  -webkit-animation-duration: 3s;
  animation-duration: 3s;
}
/*the animation definition*/
@-webkit-keyframes zoomIn {
  0% {
    opacity: 0;
    -webkit-transform: scale3d(0.3, 0.3, 0.3);
    transform: scale3d(0.3, 0.3, 0.3);
  }
  50% {
    opacity: 1;
  }
}
@keyframes zoomIn {
  0% {
    opacity: 0;
    -webkit-transform: scale3d(0.3, 0.3, 0.3);
    -ms-transform: scale3d(0.3, 0.3, 0.3);
    transform: scale3d(0.3, 0.3, 0.3);
  }
  50% {
    opacity: 1;
  }
}
.zoomIn {
  -webkit-animation-name: zoomIn;
  animation-name: zoomIn;
}

/*base code*/
.animated_four {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
.animated_four.infinite {
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}
.animated_four.hinge {
  -webkit-animation-duration: 3s;
  animation-duration: 3s;
}
/*the animation definition*/
@-webkit-keyframes fadeInUpBig {
  0% {
    opacity: 0;
    -webkit-transform: translate3d(0, 2000px, 0);
    transform: translate3d(0, 2000px, 0);
  }
  100% {
    opacity: 1;
    -webkit-transform: none;
    transform: none;
  }
}
@keyframes fadeInUpBig {
  0% {
    opacity: 0;
    -webkit-transform: translate3d(0, 2000px, 0);
    -ms-transform: translate3d(0, 2000px, 0);
    transform: translate3d(0, 2000px, 0);
  }
  100% {
    opacity: 1;
    -webkit-transform: none;
    -ms-transform: none;
    transform: none;
  }
}
.fadeInUpBig {
  -webkit-animation-name: fadeInUpBig;
  animation-name: fadeInUpBig;
}

/*base code*/
.animated_six {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
.animated_six.infinite {
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}
.animated_six.hinge {
  -webkit-animation-duration: 3s;
  animation-duration: 3s;
}
/*the animation definition*/
@-webkit-keyframes fadeOutDownBig {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    -webkit-transform: translate3d(0, 2000px, 0);
    transform: translate3d(0, 2000px, 0);
  }
}
@keyframes fadeOutDownBig {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    -webkit-transform: translate3d(0, 2000px, 0);
    -ms-transform: translate3d(0, 2000px, 0);
    transform: translate3d(0, 2000px, 0);
  }
}
.fadeOutDownBig {
  -webkit-animation-name: fadeOutDownBig;
  animation-name: fadeOutDownBig;
}

/*base code*/
.animated_five {
  -webkit-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
.animated_five.infinite {
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}
.animated_five.hinge {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
}
/*the animation definition*/
@-webkit-keyframes rotateIn {
  0% {
    -webkit-transform-origin: center;
    transform-origin: center;
    -webkit-transform: rotate3d(0, 0, 1, -200deg);
    transform: rotate3d(0, 0, 1, -200deg);
    opacity: 0;
  }
  100% {
    -webkit-transform-origin: center;
    transform-origin: center;
    -webkit-transform: none;
    transform: none;
    opacity: 1;
  }
}
@keyframes rotateIn {
  0% {
    -webkit-transform-origin: center;
    -ms-transform-origin: center;
    transform-origin: center;
    -webkit-transform: rotate3d(0, 0, 1, -200deg);
    -ms-transform: rotate3d(0, 0, 1, -200deg);
    transform: rotate3d(0, 0, 1, -200deg);
    opacity: 0;
  }
  100% {
    -webkit-transform-origin: center;
    -ms-transform-origin: center;
    transform-origin: center;
    -webkit-transform: none;
    -ms-transform: none;
    transform: none;
    opacity: 1;
  }
}
.rotateIn {
  -webkit-animation-name: rotateIn;
  animation-name: rotateIn;
}

/*base code*/
.animated_seven {
  -webkit-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
.animated_seven.infinite {
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}
.animated_seven.hinge {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
}
/*the animation definition*/
@-webkit-keyframes rotateOut {
  0% {
    -webkit-transform-origin: center;
    transform-origin: center;
    opacity: 1;
  }
  100% {
    -webkit-transform-origin: center;
    transform-origin: center;
    -webkit-transform: rotate3d(0, 0, 1, 200deg);
    transform: rotate3d(0, 0, 1, 200deg);
    opacity: 0;
  }
}
@keyframes rotateOut {
  0% {
    -webkit-transform-origin: center;
    -ms-transform-origin: center;
    transform-origin: center;
    opacity: 1;
  }
  100% {
    -webkit-transform-origin: center;
    -ms-transform-origin: center;
    transform-origin: center;
    -webkit-transform: rotate3d(0, 0, 1, 200deg);
    -ms-transform: rotate3d(0, 0, 1, 200deg);
    transform: rotate3d(0, 0, 1, 200deg);
    opacity: 0;
  }
}
.rotateOut {
  -webkit-animation-name: rotateOut;
  animation-name: rotateOut;
}

/*base code*/
.animated_eight {
  -webkit-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}
.animated_eight.infinite {
  -webkit-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}
.animated_eight.hinge {
  -webkit-animation-duration: 2s;
  animation-duration: 2s;
}
/*the animation definition*/
@-webkit-keyframes wobble {
  0% {
    -webkit-transform: none;
    transform: none;
  }
  15% {
    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
  }
  30% {
    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
  }
  45% {
    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
  }
  60% {
    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
  }
  75% {
    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
  }
  100% {
    -webkit-transform: none;
    transform: none;
  }
}
@keyframes wobble {
  0% {
    -webkit-transform: none;
    -ms-transform: none;
    transform: none;
  }
  15% {
    -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
    -ms-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
    transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
  }
  30% {
    -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
    -ms-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
    transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
  }
  45% {
    -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
    -ms-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
    transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
  }
  60% {
    -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
    -ms-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
    transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
  }
  75% {
    -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
    -ms-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
    transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
  }
  100% {
    -webkit-transform: none;
    -ms-transform: none;
    transform: none;
  }
}
.wobble {
  -webkit-animation-name: wobble;
  animation-name: wobble;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1715646.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Windows配置nginx开机自启】

Windows配置nginx开机自启 方式一&#xff1a;将nginx加入到windows服务中方式二&#xff1a;通过windows任务计划设定nginx开机自启 方式一&#xff1a;将nginx加入到windows服务中 下载window service wraper&#xff08;https://github.com/winsw/winsw/releases&#xff0…

【环境配置】windows的磁盘分区、VMware下的ubuntu20的安装、虚拟机系统界面过小的处理

这段时间在折腾自己的笔记本&#xff0c;刚好也有同学新买台式机咨询安装VMware软件&#xff0c;就顺便记录下windows的环境的一些操作。方便自己需要时查阅。 1 windows磁盘分区 在Windows系统中&#xff0c;磁盘分区和管理可以通过【磁盘管理】工具进行。要打开磁盘管理&…

【5.基础知识和程序编译及调试】

一、GCC概述&#xff1a;是GUN推出的多平台编译器&#xff0c;可将C/C源程序编译成可执行文件。编译流程分为以下四个步骤&#xff1a; 1、预处理 2、编译 3、汇编 4、链接 注&#xff1a;编译器根据程序的扩展名来分辨编写源程序所用的语言。根据不同的后缀名对他们进行相…

IDEA 2024.1.2安装与破解

官网下载 官网地址 安装 直接下一步 破解 破解网站 第一步 第二步 第三步 第四步 第五步

【图像处理与机器视觉】图像处理概述与像素

什么是数字图像处理 改善图像信息&#xff0c;便于作出解释 方便对图像传输&#xff0c;储存&#xff0c;方便机器理解 什么是数字图像 &#xff08;1&#xff09;模拟图像&#xff1a;连续二维函数 f&#xff08;x&#xff0c;y&#xff09;表示&#xff0c;其中 x&#xf…

猫狗分类识别模型建立②模型建立

一、导入依赖库 pip install opencv-python pip install numpy pip install tensorflow pip install keras 二、模型建立 pip install opencv-python pip install numpy pip install tensorflow pip install kerasimport os import xml.etree.ElementTree as ETimpor…

【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版6(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言方法一、使用excel配置表excel转txt文本读取txt数据按配置信息生成僵尸 方法二、使用ScriptableObject 配置关卡信息源码结束语 前言 本节主要是推荐两种实现配置关卡信息&#xff0c;并按表生成僵尸和关卡波次 方法一、使用…

202474读书笔记|《我自我的田渠归来》——愿你拥有向上的力量,一切的好事都应该有权利发生

202474读书笔记|《我自我的田渠归来》——愿你拥有向上的力量 《我自我的田渠归来》作者张晓风&#xff0c;被称为华语散文温柔的一支笔&#xff0c;她的短文很有味道&#xff0c;角度奇特&#xff0c;温柔慈悲而敏锐。 很幸运遇到了这本书&#xff0c;以她的感受重新认识一些事…

手机拍照扫描成电子版,这三款软件助你轻松搞定!

在数字化时代&#xff0c;将手机拍照的内容快速转换为电子版已经成为许多人日常生活和工作中不可或缺的技能。无论是快速记录文档、合同&#xff0c;还是将纸质照片、笔记转化为电子格式&#xff0c;手机拍照扫描功能都为我们提供了极大的便利。今天&#xff0c;就为大家介绍三…

视频智能分析平台LntonCVS视频安防平台智慧农场应用方案

随着乡村振兴战略的深入实施&#xff0c;数字化发展已经成为农业生产的新方向和突破。在聚焦数字发展、探索数字应用、感受数字赋能的新发展模式下&#xff0c;“数字大田”融合了视频监控技术、5G通信技术、物联网技术和AI智能技术等先进技术&#xff0c;为春季农耕农管提供了…

失落的方舟 命运方舟台服封号严重 游戏封IP怎么办

步入《失落的方舟》&#xff08;Lost Ark&#xff09;&#xff0c;这款由Smilegate精心打造的宏大规模在线角色扮演游戏&#xff08;MMORPG&#xff09;&#xff0c;您将启程前往阿克拉西亚这片饱经沧桑的奇幻大陆&#xff0c;展开一场穿越时空的壮阔探索。在这里&#xff0c;一…

人脸识别——探索戴口罩对人脸识别算法的影响

1. 概述 人脸识别是一种机器学习技术&#xff0c;广泛应用于各种领域&#xff0c;包括出入境管制、电子设备安全登录、社区监控、学校考勤管理、工作场所考勤管理和刑事调查。然而&#xff0c;当 COVID-19 引发全球大流行时&#xff0c;戴口罩就成了日常生活中的必需品。广泛使…

实战解析:爬取音乐每日推荐歌单并自动分享

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、引言 二、准备阶段 三、实战步骤 四、总结与展望 一、引言 在数字化时代&#xff0c…

揭开神秘的“位移主题”面纱 no.16

Kafka中神秘的内部主题&#xff08;Internal Topic&#xff09;__consumer_offsets。 consumer_offsets在Kafka源码中有个更为正式的名字&#xff0c;叫*位移主题*&#xff0c;即Offsets Topic。为了方便今天的讨论&#xff0c;我将统一使用位移主题来指代consumer_offsets。需…

新疆 | 金石商砼效率革命背后的逻辑

走进标杆企业&#xff0c;感受名企力量&#xff0c;探寻学习优秀企业领先之道。 本期要跟砼行们推介的标杆企业是新疆砼行业的龙头企业&#xff1a;新疆兵团建工金石商品混凝土有限责任公司&#xff08;以下简称&#xff1a;新疆金石&#xff09;。 从年产80万方到120万方&am…

OpenMv图片预处理

本博客讲述的是获取一张图片首先对图像进行处理,比如畸形矫正,图像滤波等操作。 1.histeq()自适应直方图均衡 # 自适应直方图均衡例子 # # 此示例展示了如何使用自适应直方图均衡来改善图像中的对比度。 #自适应直方图均衡将图像分割成区域,然后均衡这些区域中的直方图,…

React基础知识笔记

Reat简介 React&#xff1a;用于构建用户界面的 JavaScript 库。由 Facebook 开发且开源。是一个将视图渲染为html视图的开源库 第一章&#xff1a;React入门 相关js库 react.development.js &#xff1a;React 核心库react-dom.development.js &#xff1a;提供 DOM 操作的…

5月岚庭工人大会“安全就是效率、形象即是品质”

2024年5月18日、19日岚庭一月一期的“产业工人大会”和“工程大会”圆满举行初夏正当时&#xff0c;此次大会主要围绕“安全”与“形象”展开六场专题培训只为精益求精产业工人和装修管家全体到场。 岚庭 以绝对【安全】护家护园 安全就是生命&#xff0c;违章就是事故&#x…

想知道股指期货和期权有什么不同吗?

市场上目前有中金所的沪深300ETF&#xff0c;中证500和中证1000股指期货&#xff0c;期权市场有上证50ETF&#xff0c;沪深300etf和中证500ETF期权&#xff0c;股指期货和期权在买卖双方的权利义务、风险收益特征、保证金制度、上市合约数量等方面均有较大区别&#xff0c;下文…

地市新质生产力最新测算数据集-2005至2024年(基于工作BG)

数据简介&#xff1a;参考肖有智等&#xff08;2024&#xff09;的做法&#xff0c;查找各个地级市年工作BG进行词频分析&#xff0c;加总得到新质生产力总词频数据。数据来源&#xff1a;工作BG 时间范围&#xff1a;2005-2024年 数据范围&#xff1a;各地级市包含指标&…