<script setup lang="ts">
import { findNewComponentFromList } from '@/custom-component/component-list' // 左侧列表数据
import { computed, nextTick, onMounted, reactive, ref, toRefs, onBeforeUnmount, watch } from 'vue'
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
import { snapshotStoreWithOut } from '@/store/modules/data-visualization/snapshot'
import { storeToRefs } from 'pinia'
import eventBus from '../../utils/eventBus'
import { guid } from '@/views/visualized/data/dataset/form/util.js'
import elementResizeDetectorMaker from 'element-resize-detector'
import { getCanvasStyle, syncShapeItemStyle } from '@/utils/style'
import { adaptCurThemeCommonStyle } from '@/utils/canvasStyle'
import CanvasCore from '@/components/data-visualization/canvas/CanvasCore.vue'
import { isMainCanvas, isDashboard } from '@/utils/canvasUtils'
// change-begin
const props = defineProps({
canvasStyleData: {
type: Object,
required: true
},
componentData: {
type: Array,
required: true
},
canvasViewInfo: {
type: Object,
required: true
},
canvasId: {
type: String,
required: false,
default: 'canvas-main'
},
canvasActive: {
type: Boolean,
default: true
},
outerScale: {
type: Number,
required: false,
default: 1
},
// 仪表板字体
fontFamily: {
type: String,
required: false,
default: 'inherit'
},
// 画布位置
canvasPosition: {
type: String,
required: false,
default: 'main'
}
})
const { canvasStyleData, componentData, canvasViewInfo, canvasId, canvasActive, canvasPosition } =
toRefs(props)
const domId = ref('de-canvas-' + canvasId.value)
// change-end
const dvMainStore = dvMainStoreWithOut()
const snapshotStore = snapshotStoreWithOut()
const { pcMatrixCount, curOriginThemes, mobileInPc } = storeToRefs(dvMainStore)
const canvasOut = ref(null)
const canvasInner = ref(null)
const canvasInitStatus = ref(false)
const scaleWidth = ref(100)
const scaleHeight = ref(100)
const scaleMin = ref(100)
const state = reactive({
screenWidth: 1920,
screenHeight: 1080,
curScrollTop: 0
})
//仪表板矩阵信息适配,
const baseWidth = ref(0)
const baseHeight = ref(0)
const renderState = ref(false) // 仪表板默认
const baseMarginLeft = ref(0)
const baseMarginTop = ref(0)
const cyGridster = ref(null)
const editDomId = ref('edit-' + canvasId.value)
const editStyle = computed(() => {
if (canvasStyleData.value && isMainCanvas(canvasId.value)) {
return {
...getCanvasStyle(canvasStyleData.value)
}
} else {
return {}
}
})
// 通过实时监听的方式直接添加组件
const handleNewFromCanvasMain = newComponentInfo => {
const { componentName, innerType, staticMap } = newComponentInfo
if (componentName) {
const component = findNewComponentFromList(componentName, innerType, curOriginThemes, staticMap)
syncShapeItemStyle(component, baseWidth.value, baseHeight.value)
component.id = guid()
component.y = undefined
component.x = cyGridster.value.findPositionX(component)
dvMainStore.addComponent({
component: component,
index: undefined
})
adaptCurThemeCommonStyle(component)
nextTick(() => {
cyGridster.value.addItemBox(component) //在适当的时候初始化布局组件
nextTick(() => {
scrollTo(component.y)
})
})
snapshotStore.recordSnapshotCacheWithPositionChange('renderChart', component.id)
}
}
const handleDrop = e => {
if (isMainCanvas(canvasId.value)) {
e.preventDefault()
e.stopPropagation()
const addComponent = cyGridster.value.getMoveItem()
// 当前isShow = true 则确定已经移入画布中
addComponent.isShow = true
syncShapeItemStyle(addComponent, baseWidth.value, baseHeight.value)
cyGridster.value.handleMouseUp(e, addComponent, componentData.value.length - 1)
snapshotStore.recordSnapshotCacheWithPositionChange('renderChart', addComponent.id)
}
}
const handleDragOver = e => {
if (isMainCanvas(canvasId.value)) {
e.preventDefault()
e.dataTransfer.dropEffect = 'copy'
cyGridster.value.handleDragOver(e)
}
}
const handleMouseDown = e => {
if (isMainCanvas(canvasId.value)) {
e.stopPropagation()
dvMainStore.setClickComponentStatus(false)
dvMainStore.setInEditorStatus(true)
dvMainStore.setCurComponent({ component: null, index: null })
}
}
const canvasInitImmediately = () => {
cyGridster.value.canvasInit()
}
const canvasInit = (isFistLoad = true) => {
if (canvasActive.value || canvasPosition.value === 'tab') {
renderState.value = true
setTimeout(function () {
if (canvasOut.value) {
dashboardCanvasSizeInit()
nextTick(() => {
cyGridster.value.canvasInit() //在适当的时候初始化布局组件
cyGridster.value.afterInitOk(function () {
renderState.value = false
})
})
}
// afterInit
dvMainStore.setDataPrepareState(true)
if (isMainCanvas(canvasId.value) && isFistLoad) {
snapshotStore.recordSnapshotCache('renderChart')
}
}, 500)
}
}
const canvasSizeInit = () => {
nextTick(() => {
if (canvasOut.value) {
//div容器获取tableBox.value.clientWidth
dashboardCanvasSizeInit()
nextTick(() => {
cyGridster.value.canvasSizeInit() //在适当的时候初始化布局组件
// 缩放比例变化
scaleInit()
})
}
})
}
const scaleInit = () => {
nextTick(() => {
if (canvasOut.value) {
//div容器获取tableBox.value.clientWidth
let canvasWidth = canvasOut.value.clientWidth
let canvasHeight = canvasOut.value.clientHeight
scaleWidth.value = Math.floor((canvasWidth * 100) / canvasStyleData.value.width)
scaleHeight.value = Math.floor((canvasHeight * 100) / canvasStyleData.value.height)
scaleMin.value = Math.min(scaleWidth.value, scaleHeight.value)
if (isDashboard() && isMainCanvas(canvasId.value)) {
const offset = mobileInPc.value ? 4 : 1
dvMainStore.setCanvasStyleScale(scaleMin.value * offset)
}
}
})
}
const dashboardCanvasSizeInit = () => {
//div容器获取tableBox.value.clientWidth
state.screenWidth = canvasOut.value.clientWidth - 4
state.screenHeight = canvasOut.value.clientHeight
baseWidth.value = state.screenWidth / pcMatrixCount.value.x
baseHeight.value = state.screenHeight / pcMatrixCount.value.y
baseMarginLeft.value = 0
baseMarginTop.value = 0
canvasInitStatus.value = true
if (isMainCanvas(canvasId.value)) {
dvMainStore.setBashMatrixInfo({
baseWidth: baseWidth.value,
baseHeight: baseHeight.value,
baseMarginLeft: baseMarginLeft.value,
baseMarginTop: baseMarginTop.value
})
}
}
const addItemBox = component => {
cyGridster.value.addItemBox(component)
}
const moveOutFromTab = component => {
setTimeout(() => {
component.canvasId = canvasId.value
dvMainStore.addComponent({
component,
index: undefined,
isFromGroup: true
})
addItemBox(component)
canvasInit()
}, 500)
}
// 全局监听按键事件
onMounted(() => {
window.addEventListener('resize', canvasSizeInit)
const erd = elementResizeDetectorMaker()
erd.listenTo(document.getElementById(domId.value), () => {
canvasSizeInit()
})
canvasInit()
if (isMainCanvas(canvasId.value)) {
eventBus.on('handleNew', handleNewFromCanvasMain)
eventBus.on('event-canvas-size-init', canvasSizeInit)
}
eventBus.on('moveOutFromTab-' + canvasId.value, moveOutFromTab)
eventBus.on('matrix-canvasInit', canvasInit)
})
onBeforeUnmount(() => {
if (isMainCanvas(canvasId.value)) {
eventBus.off('handleNew', handleNewFromCanvasMain)
eventBus.off('event-canvas-size-init', canvasSizeInit)
}
eventBus.off('moveOutFromTab-' + canvasId.value, moveOutFromTab)
eventBus.off('matrix-canvasInit', canvasInit)
})
const getBaseMatrixSize = () => {
return {
baseWidth: baseWidth.value,
baseHeight: baseHeight.value
}
}
const scrollTo = (y = 1) => {
setTimeout(() => {
canvasInner.value.scrollTo({
top: (y - 1) * baseHeight.value,
behavior: 'smooth'
})
cyGridster.value?.watermarkUpdate()
})
}
const scrollCanvas = () => {
if (isMainCanvas(canvasId.value)) {
dvMainStore.mainScrollTop = canvasInner.value.scrollTop
}
}
watch(
() => canvasActive.value,
() => {
if (canvasActive.value) {
canvasSizeInit()
}
}
)
defineExpose({
addItemBox,
canvasInit,
canvasInitImmediately,
getBaseMatrixSize
})
</script>
<template>
<div ref="canvasOut" :id="editDomId" class="content" :class="{ 'render-active': renderState }">
<canvas-opt-bar
:canvas-style-data="canvasStyleData"
:component-data="componentData"
:canvas-id="canvasId"
></canvas-opt-bar>
<div
:id="domId"
ref="canvasInner"
class="db-canvas"
:class="{ 'db-canvas-dashboard': !isDashboard() }"
:style="editStyle"
@drop="handleDrop"
@dragover="handleDragOver"
@mousedown="handleMouseDown"
@scroll="scrollCanvas"
>
<canvas-core
ref="cyGridster"
v-if="canvasInitStatus"
:component-data="componentData"
:canvas-style-data="canvasStyleData"
:canvas-view-info="canvasViewInfo"
:canvas-id="canvasId"
:base-margin-left="baseMarginLeft"
:base-margin-top="baseMarginTop"
:base-width="baseWidth"
:base-height="baseHeight"
:font-family="fontFamily"
@scrollCanvasAdjust="scrollTo"
></canvas-core>
</div>
</div>
</template>
<style lang="less" scoped>
.db-canvas-dashboard {
padding: 0 !important;
}
.content {
width: 100%;
height: 100%;
.db-canvas {
padding: 2px;
background-size: 100% 100% !important;
overflow-y: auto;
width: 100%;
height: 100%;
}
::-webkit-scrollbar {
display: none;
}
}
.render-active {
opacity: 1;
}
</style>