cesium实现动态创建广告牌

import { globalColorList, globalTextColorList } from "../js/positionTools.js";
/**
 * 广告牌设备图标函数类
 */
export default class DeviceMarker {
  constructor(arg) {}
  /**
   * 初始化广告牌
   * @param {*} text 文字
   * @param {*} iconType 图表类型
   * @param {*} warningLevel 预警等级
   * @param {*} config 样式属性配置 fontSize文字大小 lineHeight线高
   * @param {*} posObj 经纬度高度对象
   * @param {*} id 主机或传感器Id
   * @param {*} targetData 整个节点的数据信息
   * @param {*} deviceType 设备类型,主机或传感器
   * @param {*} maxHeight 最大可见高度
   */
  _initMarker(
    text,
    iconType,
    warningLevel = 1,
    config = { fontSize: 24, lineHeight: 150 },
    posObj,
    targetData,
    deviceType,
    maxHeight = 6500
  ) {
    // 如果经纬度为空,则直接跳过
    if (!posObj.lng || !posObj.lat) {
      return;
    }
    let deviceImg = new Image();
    // 背景图的url
    deviceImg.src = `下面的第二张图片`;
    deviceImg.crossOrigin = "Anonymous";
    deviceImg.onload = () => {
      // 获取设备图片属性
      var deviceImagWidth = deviceImg.width;
      var deviceImagHeight = deviceImg.height;
      // 设置画布属性
      var radius = 5;
      var labelWidth = (config.fontSize + 2) * text.length;
      var labelHeight = config.fontSize * 1.5;
      let lineImg = new Image();
      lineImg.src = "下面的第一张图片";
      lineImg.crossOrigin = "Anonymous";
      lineImg.onload = () => {
        // 确定指标线的最低高度
        if (!!!config.lineHeight) {
          config.lineHeight = 20; // 最低高度默认为20px
        } else if (config.lineHeight < 20) {
          config.lineHeight = 20; // 最低高度默认为20px
        }
        // 获取指示线图片的属性
        var lineImageWidth = lineImg.width;
        var lineImageHeight = lineImg.height;
        var lineHeight = Math.min(lineImageHeight, config.lineHeight);
        // 重新计算画布大小
        var canvasWidth = Math.max(deviceImagWidth, labelWidth);
        canvasWidth = Math.max(canvasWidth, lineImageWidth);
        var canvasHeight = deviceImagHeight + labelHeight + lineHeight;
        // 创建画布
        let canvas = document.createElement("canvas");
        let ctx = canvas.getContext("2d");
        canvas.width = canvasWidth;
        canvas.height = canvasHeight;
        // 绘制标签文字
        var labelX = (canvasWidth - labelWidth) / 2;

        // 设备文字-圆角矩形
        var grad = ctx.createLinearGradient(0, 0, 0, labelHeight); // 创建一个渐变色线性对象
        grad.addColorStop(0, globalColorList[warningLevel].start); // 定义渐变色颜色(开始)
        grad.addColorStop(1, globalColorList[warningLevel].end); // 定义渐变色颜色(结束)
        // 设置fillStyle为当前的渐变对象
        ctx.fillStyle = grad;
        // ctx.shadowColor = "#fff";                           // 阴影颜色
        // ctx.shadowBlur = shadowBlur;                        // 阴影的模糊范围
        ctx.roundRect(labelX, 0, labelWidth, labelHeight, radius); // 设置圆角矩形
        ctx.fill(); // 填充圆角矩形

        // 设备文字-字体
        ctx.font = "bold " + config.fontSize + "px lion";
        ctx.textAlign = "center";
        ctx.textBaseline = "top";
        ctx.fillStyle = globalTextColorList[warningLevel];
        ctx.shadowBlur = 0; //阴影的模糊范围
        ctx.fillText(text, canvasWidth / 2, 10);

        // 合成设备图标
        var deviceImgX = (canvasWidth - deviceImagWidth) / 2;
        var deviceImgY = labelHeight;
        ctx.drawImage(deviceImg, deviceImgX, deviceImgY, deviceImagWidth, deviceImagHeight);

        // 合成指示线
        var lineImgHeight = Math.min(config.lineHeight, lineImageHeight);
        var lineImgdX = Math.round((canvasWidth - lineImageWidth) / 2);
        var lineImgdY = canvasHeight - lineImgHeight;
        var lineImgsX = -1;
        var lineImgsY = lineImageHeight - lineImgHeight;
        var lineImgWidth = lineImageWidth;

        ctx.drawImage(
          lineImg,
          lineImgsX,
          lineImgsY,
          lineImgWidth,
          lineImgHeight,
          lineImgdX,
          lineImgdY,
          lineImgWidth,
          lineImgHeight
        );

        // 动画参数
        let curScale = 1.0; // 当前缩放比例
        let speed = 1.0; // 初始变化速率(从1倍开始)
        let speedDelta = 0.005 * (warningLevel - 1); // 增量变化速率(速度越来越快)
        var timestamp = new Date().valueOf(); // 记录动画开始时间戳

        let base64 = canvas.toDataURL("image/png");
        let position = Cesium.Cartesian3.fromDegrees(Number(posObj.lng), Number(posObj.lat), Number(posObj.height));
        let entity = viewer.entities.add({
          position: position,
          targetData: targetData,
          // 设备:host/device
          deviceType: deviceType,
          show: true,
          billboard: {
            image: base64,
            // heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,    // 是否贴地
            horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // 水平对齐
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 重直对齐
            scaleByDistance: new Cesium.NearFarScalar(0, 1.0, 500, 0.3),
            eyeOffset: new Cesium.Cartesian3(0, 0, 0),
            scale:
              warningLevel == 1
                ? 1.0
                : new Cesium.CallbackProperty(function changeScale(time, result) {
                    let minScale = 1.0; // 最小缩放比例(默认1.0)
                    let maxScale = 1.05; // 最大缩放比例
                    let speedIntreval = 200; // 动画时间间隔(每隔100毫秒变换一次)
                    var curTimestamp = new Date().valueOf(); // 当次动画时间戳
                    if (curTimestamp - timestamp > speedIntreval) {
                      // 每隔100毫秒变换
                      speed += speedDelta; // 确定变化速率
                      curScale = speed ** 2; // 计算当前缩放比例(模拟重力加速度,speed相当(1/2)g(t^2)的时间t)
                      timestamp = curTimestamp; // 记录本次时间戳(用作计算动画时间间隔)
                      if (curScale >= maxScale) {
                        speedDelta *= -1; // 超过最大缩放比例,改为缩小
                      } else if (curScale <= minScale) {
                        speedDelta *= -1; // 低于最小缩放比例,改为放大
                      }
                    }
                    return curScale;
                  }, false),
            // pixelOffset: new Cesium.Cartesian2(offsetX, offsetY), //设置偏移量
            // pixelOffsetScaleByDistance: new Cesium.NearFarScalar(0, 1.0, 200, 0.3) //设置偏移量
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, maxHeight) // 设置最小和最大距离
          }
        });
        globalEntity.push(entity);
      };
    };
  }

  // 创建主机和传感器广告牌函数
  _createMarker(element, maxHeight, clampToGround) {
    if (element.deviceHostList && element.deviceHostList.length > 0) {
      element.deviceHostList.forEach(item => {
        try {
          let hostHeight = 0 == clampToGround ? item.height : 0;
          // 主机的情况
          this._initMarker(
            item.deviceTypeDict,
            item.deviceType,
            item.warnLevel || 1,
            { fontSize: 24, lineHeight: item.lineHeight || 150 },
            { lng: item.lng, lat: item.lat, height: hostHeight },
            item,
            "host",
            maxHeight - 100
          );
          item.deviceCollectorList.forEach(collectorItem => {
            try {
              // 传感器无经纬度高度信息,bimModelComponentList字段中取,bimModelComponentList有为空的情况
              if (collectorItem.bimModelComponentList) {
                let { lng, lat, height, lineHeight } = collectorItem.bimModelComponentList.find(
                  i => i.collectorId == collectorItem.id
                );
                // 如果clampToGround==0,则图标不贴地,否则将绘制贴地图标
                height = 0 == clampToGround ? height : 0;
                this._initMarker(
                  collectorItem.collectorTypeName,
                  collectorItem.deviceType,
                  collectorItem.warnLevel,
                  { fontSize: 24, lineHeight: lineHeight || 150 },
                  { lng: lng, lat: lat, height: height },
                  collectorItem,
                  "device",
                  maxHeight - 100
                );
              }
            } catch (err) {
              console.log(err);
            }
          });
        } catch (err) {
          console.log(err);
        }
      });
    }
  }

  // 创建设备图标函数函数
  createMarker(mointorPointInfo, clampToGround = 0) {
    if (mointorPointInfo.children && mointorPointInfo.children.length > 0) {
      mointorPointInfo.children.map(item => {
        this._createMarker(item, mointorPointInfo.areaHeight, clampToGround);
      });
    }
  }

  // 删除设备图标函数函数
  deleteMarker() {
    // 清除全部实体
    viewer.entities.removeAll();
  }
}

  

// 预警颜色常量字段
export const globalColorList = {
  5: { start: "#e21615", end: "#850000" },
  4: { start: "#fe7600", end: "#a83300" },
  3: { start: "#ffe045", end: "#eb8d00" },
  2: { start: "#56a2eb", end: "#1756ae" },
  1: { start: "#fdfffc", end: "#cbffe4" }
};

// 预警文字颜色常量字段
export const globalTextColorList = {
  5: "#fff",
  4: "#fff",
  3: "#fff",
  2: "#fff",
  1: "#333"
};

  代码中会用到的图片

 

posted on 2024-05-29 10:51  忘忧很努力呀~  阅读(95)  评论(0编辑  收藏  举报