dataDynamicEffectHandler.ts 5.54 KB
import type { App } from 'vue'
import type { SubscriptionUpdateMsg } from '../type/message'
import type { CommandSource, LightboxModeWebsocketService } from '.'
import { getMeetTheConditionsRange } from '@/core/Library/utils'
import { ActRangListItemTypeEnum, ActTypeEnum } from '@/enums/datasource'
import { getAppInstanceId } from '@/utils/draw'
import type { RenderComponentExposeType } from '@/core/Library/types'
import type { DisplayActDataType, DynamicActDataType, FlashActDataType, RotateActDataType } from '@/api/node/model'
import { useLatestMessageValue } from '@/core/Library/hook/useLatestMessageValue'

export class DataDynamicEffectHandler {
  constructor(public service: LightboxModeWebsocketService) {
  }

  get nodeUtils() {
    return this.service.nodeUtils
  }

  setNodeAnimation(node: SVGAElement, animationName: string, remove = false) {
    const dataSetSaveFields = 'actMultipleAnimationList'
    const animationNameListString = node.dataset?.[dataSetSaveFields] || ''
    const animationNameSet = new Set(animationNameListString.split(','))
    remove ? animationNameSet.delete(animationName) : animationNameSet.add(animationName)
    const animation = Array.from(animationNameSet.values()).filter(Boolean).join(',')
    node.setAttribute(`data-${dataSetSaveFields}`, animation)
    node.style.animation = animation
  }

  [ActTypeEnum.FLASH](commandSource: CommandSource, message: SubscriptionUpdateMsg) {
    const { node, data } = commandSource
    const cell = this.nodeUtils.getCellById(node)
    if (!cell) return
    const { attr } = data as FlashActDataType
    const { latestValue } = useLatestMessageValue(message.data, attr)
    const { flag } = getMeetTheConditionsRange((data as FlashActDataType).rangeList, latestValue)

    const nodeEl = this.nodeUtils.getNodesForCells<SVGAElement>([cell])

    const FLASH_ANIMATION = 'act-flash infinite 1.5s'
    nodeEl.forEach((item: SVGAElement) => {
      if (flag)
        this.setNodeAnimation(item, FLASH_ANIMATION)
      else
        this.setNodeAnimation(item, FLASH_ANIMATION, true)
    })
  }

  [ActTypeEnum.DISPLAY](commandSource: CommandSource, message: SubscriptionUpdateMsg) {
    const { node, data } = commandSource
    const cell = this.nodeUtils.getCellById(node)
    if (!cell) return
    const { attr } = data as DisplayActDataType
    const { latestValue } = useLatestMessageValue(message.data, attr)
    const { flag, record } = getMeetTheConditionsRange((data as DisplayActDataType).rangeList, latestValue)
    if (flag) {
      const nodeEl = this.nodeUtils.getNodesForCells([cell])
      const { type } = record!
      if (type === ActRangListItemTypeEnum.SHOW) {
        nodeEl.forEach((node) => {
          node.classList.add('act-visible')
          node.classList.remove('act-hidden')
        })
      }
      else if (type === ActRangListItemTypeEnum.HIDDEN) {
        nodeEl.forEach((node) => {
          node.classList.remove('act-visible')
          node.classList.add('act-hidden')
        })
      }
    }
  }

  [ActTypeEnum.ROTATE](commandSource: CommandSource, message: SubscriptionUpdateMsg) {
    const { node, data } = commandSource
    const cell = this.nodeUtils.getCellById(node)
    if (!cell) return
    const { attr } = data as RotateActDataType
    const { latestValue } = useLatestMessageValue(message.data, attr)
    const { flag } = getMeetTheConditionsRange((data as RotateActDataType).rangeList, latestValue)
    const nodeEl = this.nodeUtils.getNodesForCells<SVGAElement>([cell])

    const ROTATE_ANIMATION = 'act-spin infinite 2s'
    const cellState = this.nodeUtils.getCellState(cell)
    const { x, y, width, height } = cellState.cellBounds
    nodeEl.forEach((item: SVGAElement) => {
      if (flag) {
        item.style.transformOrigin = `${x + width / 2}px ${y + height / 2}px`
        this.setNodeAnimation(item, ROTATE_ANIMATION)
      }
      else {
        this.setNodeAnimation(item, ROTATE_ANIMATION, true)
      }
    })
  }

  [ActTypeEnum.DYNAMIC](commandSource: CommandSource, message: SubscriptionUpdateMsg) {
    const { node, data } = commandSource
    const cell = this.nodeUtils.getCellById(node)
    if (!cell) return
    const { attr } = data as DynamicActDataType
    const { latestValue } = useLatestMessageValue(message.data, attr)
    const { flag, record } = getMeetTheConditionsRange((data as DynamicActDataType).rangeList, latestValue)

    const nodeEl = this.nodeUtils.getNodeForCell<SVGAElement>(cell)
    if (flag) {
      const { type } = record!
      if (type === ActRangListItemTypeEnum.RUN)
        (nodeEl?.querySelectorAll('path')?.[1] as SVGPathElement).classList.add('water-flow-animation')

      else
        (nodeEl?.querySelectorAll('path')?.[1] as SVGPathElement).classList.remove('water-flow-animation')
    }
  }

  [ActTypeEnum.STATUS_SETTING](commandSource: CommandSource, message: SubscriptionUpdateMsg) {
    const { node } = commandSource
    const cell = this.nodeUtils.getCellById(node)
    if (!cell) return
    const instanceId = getAppInstanceId(cell)
    const instance = window?.VueInstanceMap?.[instanceId] as App
    if (instance)
      (instance._instance?.exposed as RenderComponentExposeType)?.onMessage?.(commandSource, message)
  }

  [ActTypeEnum.VARIABLE_IMAGE](commandSource: CommandSource, message: SubscriptionUpdateMsg) {
    const { node } = commandSource
    const cell = this.nodeUtils.getCellById(node)
    if (!cell) return
    const instanceId = getAppInstanceId(cell)
    const instance = window?.VueInstanceMap?.[instanceId] as App
    if (instance)
      (instance._instance?.exposed as RenderComponentExposeType)?.onMessage?.(commandSource, message)
  }
}