ArcGIS JS 自定义体积测量控件

ArcGIS 中只支持2D、3D的线、面的测量。

体积控件:基于面积测量控件,手动输入高度进行计算;

代码

VolumeMeasurement.vue

<template>
  <div class="volume-measurement esri-widget" v-show="widget" ref="parentRef">
    <div class="volume-measurement-content">
      <div>
        <span>面积:</span>
        <div class="esri-area-measurement-3d__measurement-item-value">{{ data.area }} m²</div>
      </div>
      <div>
        <span>高度:</span>
        <el-input mini v-model="data.height" placeholder="最大:9999.99" :formatter="handleFormatter" />
        <i class="esri-area-measurement-3d__measurement-item-value" style="margin-left: 5px; font-style: normal">m</i>
      </div>
      <div>
        <span>体积:</span>
        <div class="esri-area-measurement-3d__measurement-item-value">{{ volume }} m³</div>
      </div>
    </div>
  </div>
</template>

<script setup>
import Decimal from "decimal.js";
import AreaMeasurement3D from "@arcgis/core/widgets/AreaMeasurement3D.js";

// 父节点
const parentRef = ref(null);

// 控件实例
const widget = shallowRef(null);

// 体积数据
const data = reactive({
  area: 0,
  height: 0,
});

// 计算体积
const volume = computed(() => {
  const val = new Decimal(data.area).mul(data.height || 0);
  return val.toNumber() ? val.toFixed(2) : 0;
});

// 输入校验
function handleFormatter(val) {
  // 移除所有非数字字符,除了第一个出现的小数点
  let res = val.replace(/^(0|[1-9]\d{1,3})(\.\d{0,2})?.*/, "$1$2");

  // 如果结果为空或不是有效的数字,则将其设为''
  if (!res.match(/^\d*(\.\d{0,2})?$/)) return "";

  return res;
}

// 测量体积
function start(view) {
  // 创建节点
  const ele = document.createElement("div");
  parentRef.value.prepend(ele);
  ele.addEventListener("click", reset);

  // 创建控件
  const w = (widget.value = new AreaMeasurement3D({
    view,
    container: ele,
    unit: "square-meters",
    unitOptions: ["square-meters"],
  }));

  triggerMeasureVolume(ele);

  w.when(async () => {
    const analysisView = await view.whenAnalysisView(w.analysis);
    const handle = analysisView.watch("result", (r) => {
      data.area = r.area ? new Decimal(r.area.value).toFixed(2) : 0;
    });
    w.own(handle);
  });
}

// 触发测量
function triggerMeasureVolume(wrapper) {
  const esriBtn = wrapper?.querySelector(`button.esri-area-measurement-3d__clear-button`);

  if (esriBtn) esriBtn.click();
  else setTimeout(() => triggerMeasureVolume(wrapper), 30);
}

// 重置
function reset() {
  data.area = 0;
  data.height = 0;
}

// 销毁
function destroy() {
  widget.value?.destroy();
  widget.value = null;
  reset();
}

defineExpose({
  start,
  destroy,
});
</script>

<style lang="scss" scoped>
.volume-measurement {
  padding: 15px 12px;

  :deep() {
    .esri-area-measurement-3d__container {
      padding: 0;
      .esri-area-measurement-3d__settings,
      .esri-area-measurement-3d__measurement {
        display: none;
      }
    }
  }

  &-content {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin-top: 10px;

    & > div {
      display: flex;
      align-items: center;

      span {
        display: inline-block;
        flex-shrink: 0;
        width: 42px;
      }
    }
  }
}
</style>

使用

通过点击`体积测量工具`的 div,触发控件的 start 和 destroy 方法;

map.vue

<template>
  <div id="map">
    <div
      class="esri-widget--button esri-interactive esri-icon-elevation-profile m-widget m-widget-volume"
      :class="[activeWidget === 'volume' ? 'active' : '']"
      title="体积测量工具"
      @click="handleMeasureVolume()"
    ></div>

    <!-- 体积控件 -->
    <volume-measurement class="m-widget m-widget-measure-volume" ref="volumeMeasureRef" />
  </div>
</template>

<script setup>
import VolumeMeasurement from "./widgets/VolumeMeasurement.vue";
// other imports

const view = shallowRef(null);

const activeWidget = ref(null);

onMounted(()=>{
  view.value = createSceneView();
})

function handleMeasureVolume() {
  activeWidget.value = activeWidget.value === "volume" ? null : "volume";

  if (activeWidget.value) volumeMeasureRef.value.start(view.value);
  else volumeMeasureRef.value.destroy();
}
</script>

效果 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值