index.vue 8.32 KB
<script lang="ts" setup>
  import { ComponentPropsConfigType, DataFetchUpdateFn } from '/@/views/visual/packages/index.type';
  import { option } from './config';
  import { useDataFetch } from '/@/views/visual/packages/hook/useSocket';
  import { ref } from 'vue';
  import { computed } from 'vue';
  import { unref } from 'vue';

  const props = defineProps<{
    config: ComponentPropsConfigType<typeof option>;
  }>();

  const currentValue = ref(50);

  const getValue = computed(() => {
    const maxHeight = 190;
    const minHeight = 15;
    const height = maxHeight - minHeight;
    const rangeNumber = 7;
    const itemRange = 20;
    const itemHeight = height / (rangeNumber * itemRange);
    const value = unref(currentValue);
    const transformValue =
      maxHeight - (value >= 0 ? value + 20 : itemRange - Math.abs(value)) * itemHeight;

    return transformValue >= maxHeight
      ? maxHeight
      : transformValue <= minHeight
      ? minHeight
      : transformValue;
  });

  const updateFn: DataFetchUpdateFn = (message, attribute) => {
    const { data = {} } = message;
    const [latest] = data[attribute] || [];
    const [_, value] = latest;

    currentValue.value = Number(value);
  };

  useDataFetch(props, updateFn);
</script>

<template>
  <main class="w-full h-full flex flex-col justify-center items-center relative">
    <svg class="flowmeter-thermometer" viewBox="0 0 200 250" xmlns="http://www.w3.org/2000/svg">
      <defs>
        <radialGradient id="thermometerdiv_meter_2" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
          <stop offset="0%" style="stop-color: rgb(230, 200, 200)" />
          <stop offset="90%" style="stop-color: rgb(230, 0, 0)" />
        </radialGradient>
        <clipPath id="over">
          <rect width="100" height="190" x="100" y="10" />
        </clipPath>
      </defs>
      <circle
        r="9.25"
        cx="109"
        cy="14.25"
        style="fill: rgb(255, 255, 255); stroke: rgb(136, 136, 136); stroke-width: 1px"
      />
      <rect
        x="99.75"
        y="14.25"
        height="192.75"
        width="18.5"
        style="
          shape-rendering: crispEdges;
          fill: rgb(255, 255, 255);
          stroke: rgb(136, 136, 136);
          stroke-width: 1px;
        "
      />
      <circle r="8.75" cx="109" cy="14.25" style="fill: rgb(255, 255, 255); stroke: none" />
      <circle
        r="18"
        cx="109"
        cy="207"
        style="fill: rgb(255, 255, 255); stroke: rgb(136, 136, 136)"
      />
      <rect
        x="100.25"
        y="14.25"
        height="192.75"
        width="17.5"
        style="shape-rendering: crispEdges; fill: rgb(255, 255, 255); stroke: none"
      />
      <line
        class="thermometer-min-line"
        x1="99.75"
        x2="140.25"
        y1="165"
        y2="165"
        style="stroke: rgb(136, 136, 136); stroke-width: 1px; shape-rendering: crispEdges"
      />
      <text
        class="thermometer-min-label"
        x="120.25"
        y="168.46428571428572"
        dy="0.72em"
        style="fill: rgb(0, 0, 230); font-size: 10px"
      >
        min
      </text>
      <line
        class="thermometer-max-line"
        x1="99.75"
        x2="140.25"
        y1="40"
        y2="40"
        style="stroke: rgb(136, 136, 136); stroke-width: 1px; shape-rendering: crispEdges"
      />
      <text
        class="thermometer-max-label"
        x="120.25"
        y="35.285714285714306"
        style="fill: rgb(230, 0, 0); font-size: 10px"
      >
        max
      </text>
      <rect
        class="thermometer-mercury-column"
        x="104"
        :y="getValue"
        width="10.5"
        height="190"
        style="shape-rendering: crispEdges; fill: rgb(230, 0, 0)"
        clip-path="url(#over)"
      />
      <circle
        r="13"
        cx="109"
        cy="207"
        style="fill: url('#thermometerdiv_meter_2'); stroke: rgb(230, 0, 0); stroke-width: 2px"
      />
      <foreignObject>
        <div></div>
      </foreignObject>
      <g
        class="thermometer-temperature-axis"
        transform="translate(99.75,0)"
        fill="none"
        font-size="10"
        font-family="sans-serif"
        text-anchor="end"
      >
        <g class="tick" opacity="1" transform="translate(0,190)">
          <line
            stroke="currentColor"
            x2="-7"
            style="stroke: rgb(136, 136, 136); shape-rendering: crispEdges; stroke-width: 1px"
          />
          <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20">
            <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">-20</div>
          </foreignObject>
        </g>
        <g class="tick" opacity="1" transform="translate(0,165)">
          <line
            stroke="currentColor"
            x2="-7"
            style="stroke: rgb(136, 136, 136); shape-rendering: crispEdges; stroke-width: 1px"
          />
          <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20">
            <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">0</div>
          </foreignObject>
        </g>
        <g class="tick" opacity="1" transform="translate(0,140)">
          <line
            stroke="currentColor"
            x2="-7"
            style="stroke: rgb(136, 136, 136); shape-rendering: crispEdges; stroke-width: 1px"
          />
          <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20">
            <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">20</div>
          </foreignObject>
        </g>
        <g class="tick" opacity="1" transform="translate(0,115)">
          <line
            stroke="currentColor"
            x2="-7"
            style="stroke: rgb(136, 136, 136); shape-rendering: crispEdges; stroke-width: 1px"
          />
          <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20">
            <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">40</div>
          </foreignObject>
        </g>
        <g class="tick" opacity="1" transform="translate(0,90)">
          <line
            stroke="currentColor"
            x2="-7"
            style="stroke: rgb(136, 136, 136); shape-rendering: crispEdges; stroke-width: 1px"
          />
          <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20">
            <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">60</div>
          </foreignObject>
        </g>
        <g class="tick" opacity="1" transform="translate(0,65)">
          <line
            stroke="currentColor"
            x2="-7"
            style="stroke: rgb(136, 136, 136); shape-rendering: crispEdges; stroke-width: 1px"
          />
          <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20">
            <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">80</div>
          </foreignObject>
        </g>
        <g class="tick" opacity="1" transform="translate(0,40)">
          <line
            stroke="currentColor"
            x2="-7"
            style="stroke: rgb(136, 136, 136); shape-rendering: crispEdges; stroke-width: 1px"
          />
          <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20">
            <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">100</div>
          </foreignObject>
        </g>
        <g class="tick" opacity="1" transform="translate(0,15)">
          <line
            stroke="currentColor"
            x2="-7"
            style="stroke: rgb(136, 136, 136); shape-rendering: crispEdges; stroke-width: 1px"
          />
          <foreignObject xmlns="http://www.w3.org/2000/svg" x="-55" y="-10" width="45" height="20">
            <div class="tick-label" xmlns="http://www.w3.org/1999/xhtml">120</div>
          </foreignObject>
        </g>
      </g>
    </svg>
    <!-- <div class="absolute w-full h-full flex justify-center items-center bg-transparent">
      <div class="transform translate-x-full text-lg text-gray-500">
        <span>{{ currentValue }}</span>
        <span>{{ '℃' }}</span>
      </div>
    </div> -->
  </main>
</template>

<style scoped lang="less">
  .tick-label {
    font-size: 12px;
    text-align: right;
    overflow: hidden;
    text-overflow: ellipsis;
    color: #5b6b73;
  }

  .thermometer-mercury-column {
    transition: y 0.5s cubic-bezier(0.19, 1, 0.22, 1);
  }
</style>