cesium绘制编辑区域

 

 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>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI在肿瘤学临床决策中的应用:一种多模态方法

在临床肿瘤学领域&#xff0c;多模态人工智能&#xff08;AI&#xff09;系统通过解读各类医学数据&#xff0c;展现出提升临床决策的潜力。然而&#xff0c;这些模型在所有医学领域中的有效性尚未确定。本文介绍了一种新型的多模态医疗AI方法&#xff0c;该方法利用大型语言模…

97.网络游戏逆向分析与漏洞攻防-ui界面的设计-通过逆向分析确认角色信息

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

Day 6:2981. 找出出现至少三次的最长特殊子字符串 I

Leetcode 2981. 找出出现至少三次的最长特殊子字符串 I 给你一个仅由小写英文字母组成的字符串 s 。 如果一个字符串仅由单一字符组成&#xff0c;那么它被称为 特殊 字符串。例如&#xff0c;字符串 “abc” 不是特殊字符串&#xff0c;而字符串 “ddd”、“zz” 和 “f” 是特…

kafka的安装与简单使用

下载地址&#xff1a;Apache Kafka 1. 上传并解压安装包 tar -zxvf kafka_2.13-3.6.2.tgz 修改文件名&#xff1a;mv kafka_2.13-3.6.2 kafka 2. 配置环境变量 sudo vim /etc/profile #配置kafka环境变量 export KAFKA_HOME/export/server/kafka export PATH$PATH:$KAFKA…

echarts性能优化

echarts数据量多的时候优化方案&#xff1a; 渲染的数据太多时&#xff0c;渲染的速度会变慢。 let data [];for (let i 0; i < 100000; i) {let style {};if (i % 2 0) {style.color "red";}data.push({value: i,itemStyle: style,}); } myEcharts init(c…

07 FreeRTOS 事件组(event group)

1、事件组概念 1.1 基本概念 使用事件组可以等待某个事件、若干事件中的任意一个事件、若干事件中的所有事件&#xff0c;但是不能指定若干事件中的某些事件。 事件组可以简单地认为就是一个整数&#xff1a;这个整数的每一位表示一个事件&#xff1b;每一位事件的含义由程序员…

【B站 heima】小兔鲜Vue3 项目学习笔记 Day06

文章目录 购物车本地1. 列表购物车基础数据渲染2. 列表购物车单选功能3. 列表购物车全选功能4. 列表购物车统计列表实现5. 接口-加入购物车6. 接口-删除购物车7. 退出登录-清空购物车数据8. 合并购物车到服务器(重要) 结算1. 路由配置和基础数据渲染2. 地址切换-打开弹框交互实…

如何选择适合自己需求的云服务器

最近明月接了一个跨境电商的代维业务&#xff0c;发现他们的云服务器很有代表性&#xff0c;今天就以此为例给大家分享一下应该如何选择适合自己需求的云服务器。像明月这样专做代维业务的可以说什么云服务器都体验过了&#xff0c;也发现大家在选择自己的云服务器的时候有很大…

大模型“1元购”?AI公司加速奔向应用端“大航海时代”

自字节跳动发布豆包大模型&#xff0c;互联网大厂纷纷就位&#xff0c;击穿“地板价”的打法从C端向B端拓展。这也成为今年“618”最亮眼的价格战。 5月15日&#xff0c;字节跳动率先宣布豆包大模型已通过火山引擎开放给企业客户&#xff0c;大模型定价降至0.0008元/千Tokens&…

解读 | 上海房地产政策松绑,售楼电话被“打爆”

图片来源千图网 自5月27日晚间上海发布房地产政策松绑消息以来&#xff0c;城市楼市气氛仿佛被一股暖流席卷&#xff0c;售楼电话几乎在一夜之间被“打爆”。这一次调整的政策涉及到多个方面&#xff0c;包括首套房首付比例的下调、二套房首付比例的调整、房贷利率的优惠等&am…

二叉树的实现

一、结构体声明和函数声明 #pragma once#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include<stdlib.h> #include<assert.h> #include<string.h> #include<stdbool.h>//二叉树typedef char BTDataType; typedef struct BinaryT…

最新淘宝死店全自动采集私信筛选脚本,号称日赚500+【采集软件+使用教程】

原理&#xff1a; 利用脚本自动采集长时间未登录店铺&#xff0c;然后脚本自动私信对应的店铺&#xff0c;看看商家是不是不回消息来判断是否是死店&#xff0c;再下单购买死店的产品&#xff0c;超过48小时不发货就可以联系客服获得赔付&#xff0c;一单利润百分之5%-30%&…

STP19NF20 丝印 19NF20 场效应管19A 200V 直插 TO-220

STP19NF20 功率MOSFET的应用领域相当广泛&#xff0c;主要包括&#xff1a; 1. 电源管理&#xff1a;用于高效率电源管理电路&#xff0c;如直流-直流转换器和交流-直流电源适配器。 2. 开关模式电源&#xff08;SMPS&#xff09;&#xff1a;在需要高效能和紧凑型尺寸的开关…

【数据结构】二叉树的链式结构

目录 一.二叉树的遍历 1.前序遍历 2.中序遍历 3.后序遍历 4.层序遍历 二.二叉树查询的基本操作 1.二叉树节点的个数 2.二叉树叶子节点的个数 3.二叉树的高度 4.二叉树第k层节点的个数 5.二叉树查询值为x的节点 6.判断二叉树是否为完全二叉树 7.二叉树基础oj练习 三…

【Python编程实践2/3】Python图像处理模块(上)

目录 引言 目标 安装模块 Windows系统 macOS系统 路径 Windows路径 ​编辑macOS路径 windows路径报错 windows路径前的r 示例代码 windows快速查看路径 macOS快速查看路径 打开图片 展示图片 下节预告 总结 引言 欢迎各位大佬垂阅本篇Python实践博客&a…

一文读懂python同级目录的调用附Demo(详细解读)

目录 前言1. 问题所示2. 原理分析3. 解决方法3.1 添加父目录3.2 相对路径3.3 添加init 前言 通过制作简易的Demo&#xff0c;让其更加深入的了解如何使用 1. 问题所示 发现python的同级目录相互调用会出Bug E:\software\anaconda3\envs\py3.10\python.exe F:\python_project…

python之生成xmind

今天为啥要说这个呢&#xff0c;因为前几天做接口测试&#xff0c;还要写测试用例&#xff0c;我觉得麻烦&#xff0c;所以我就用了python里面xmind的插件。自动生成了测试用例&#xff0c;数据来源是json。 &#x1f366; 第一步安装 pip install xmind &#x1f366; 第二…

01_Spring Ioc(详解) + 思维导图

文章目录 思维导图一.概念实操Maven父子工程 二. IOC和DI入门案例【重点】1 IOC入门案例【重点】问题导入1.1 门案例思路分析1.2 实现步骤2.1 DI入门案例思路分析2.2 实现步骤2.3 实现代码2.4 图解演示 三、Bean的基础配置问题导入问题导入1 Bean是如何创建的【理解】2 实例化B…

【408真题】2009-26

“接”是针对题目进行必要的分析&#xff0c;比较简略&#xff1b; “化”是对题目中所涉及到的知识点进行详细解释&#xff1b; “发”是对此题型的解题套路总结&#xff0c;并结合历年真题或者典型例题进行运用。 涉及到的知识全部来源于王道各科教材&#xff08;2025版&…

Camunda BPM主要组件

Camunda BPM是使用java开发的,核心流程引擎运行在JVM里,纯java库,不依赖其他库或者底层操作系统。可以完美地与其他java框架融合,比如Spring。除了核心流程引擎外,还提供了一系列的管理,操作和监控工具。 1,工作流引擎 既适用于服务或者微服务编排,也适用于人工任务管…