mirror of
https://github.com/dataease/dataease.git
synced 2026-06-16 20:42:07 +08:00
Pr@dev v3@feat transform (#17950)
* refactor: 样式调整 * feat: 数据大屏支持transform画布
This commit is contained in:
@@ -33,6 +33,7 @@ import {
|
||||
componentPreSort,
|
||||
findDragComponent,
|
||||
findNewComponent,
|
||||
getTransformParams,
|
||||
isDashboard,
|
||||
isGroupOrTabCanvas,
|
||||
isMainCanvas,
|
||||
@@ -407,6 +408,7 @@ let snapshotTimer = ref(null)
|
||||
|
||||
// 根据需要需要扩充外部scroll区域也可以进行组合的功能 此方法变更为外部组件调用
|
||||
const handleMouseDown = e => {
|
||||
const transformParams = getTransformParams()
|
||||
// 仪表板和预览状态不显示菜单和组创建
|
||||
if (dashboardActive.value || editMode.value === 'preview') {
|
||||
return
|
||||
@@ -426,20 +428,20 @@ const handleMouseDown = e => {
|
||||
|
||||
const startX = e.clientX
|
||||
const startY = e.clientY
|
||||
start.value.x = startX - editorX.value
|
||||
start.value.y = startY - editorY.value
|
||||
start.value.x = (startX - editorX.value) * transformParams.tOffsetSpeed
|
||||
start.value.y = (startY - editorY.value) * transformParams.tOffsetSpeed
|
||||
// 展示选中区域
|
||||
isShowArea.value = true
|
||||
|
||||
const move = moveEvent => {
|
||||
width.value = Math.abs(moveEvent.clientX - startX)
|
||||
height.value = Math.abs(moveEvent.clientY - startY)
|
||||
width.value = Math.abs((moveEvent.clientX - startX) * transformParams.tOffsetSpeed)
|
||||
height.value = Math.abs((moveEvent.clientY - startY) * transformParams.tOffsetSpeed)
|
||||
if (moveEvent.clientX < startX) {
|
||||
start.value.x = moveEvent.clientX - editorX.value
|
||||
start.value.x = (moveEvent.clientX - editorX.value) * transformParams.tOffsetSpeed
|
||||
}
|
||||
|
||||
if (moveEvent.clientY < startY) {
|
||||
start.value.y = moveEvent.clientY - editorY.value
|
||||
start.value.y = (moveEvent.clientY - editorY.value) * transformParams.tOffsetSpeed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,8 +579,8 @@ const handleContextMenu = event => {
|
||||
const offsetY = rect.top
|
||||
|
||||
// 计算鼠标相对于最外层 div 的坐标
|
||||
const left = mouseX - offsetX
|
||||
let top = mouseY - offsetY
|
||||
const left = (mouseX - offsetX) / canvasStyleData.value.tScale
|
||||
let top = (mouseY - offsetY) / canvasStyleData.value.tScale
|
||||
// 组件处于编辑状态的时候 如富文本 不弹出右键菜单
|
||||
if (!curComponent.value || (curComponent.value && !curComponent.value.editing)) {
|
||||
if (
|
||||
|
||||
@@ -122,6 +122,7 @@ const scaleWidthPoint = ref(100)
|
||||
const scaleHeightPoint = ref(100)
|
||||
const scaleMin = ref(100)
|
||||
const previewCanvas = ref(null)
|
||||
const previewCanvasInner = ref(null)
|
||||
const cellWidth = ref(10)
|
||||
const cellHeight = ref(10)
|
||||
const userViewEnlargeRef = ref(null)
|
||||
@@ -169,6 +170,24 @@ const baseComponentData = computed(() =>
|
||||
(!ele?.dashboardHidden || (ele?.dashboardHidden && isMobile()))
|
||||
)
|
||||
)
|
||||
const canvasStyleInner = computed(() => {
|
||||
if (
|
||||
dvInfo.value.type === 'dataV' &&
|
||||
['keep', 'widthFirst', 'heightFirst'].includes(canvasStyleData.value?.screenAdaptor)
|
||||
) {
|
||||
const curScale = scaleMin.value / 100
|
||||
return {
|
||||
position: 'absolute',
|
||||
height: 100 / curScale + '%!important',
|
||||
width: 100 / curScale + '%!important',
|
||||
left: 50 * (1 - 1 / curScale) + '%', // 放大余量 除以 2
|
||||
top: 50 * (1 - 1 / curScale) + '%', // 放大余量 除以 2
|
||||
transform: 'scale(' + curScale + ') translateZ(0)'
|
||||
}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
const canvasStyle = computed(() => {
|
||||
let style = {}
|
||||
if (isMainCanvas(canvasId.value) && !isDashboard()) {
|
||||
@@ -290,13 +309,26 @@ const resetLayout = () => {
|
||||
// 需要保持宽高比例时 高度伸缩和宽度伸缩保持一致 否则 高度伸缩单独计算
|
||||
// tip 当当前画布是tab时 使用的事 outerScale.value 因为 canvasStyleData.value为 {} 此处取数逻辑需进一步优化
|
||||
const scaleMinHeight = dataVKeepRadio.value ? scaleMin.value : scaleHeightPoint.value
|
||||
changeRefComponentsSizeWithScalePoint(
|
||||
baseComponentData.value,
|
||||
canvasStyleData.value,
|
||||
scaleMin.value || outerScale.value * 100,
|
||||
scaleMinHeight || outerScale.value * 100,
|
||||
outerScale.value * 100
|
||||
)
|
||||
if (
|
||||
dvInfo.value.type === 'dataV' &&
|
||||
['keep', 'widthFirst', 'heightFirst'].includes(canvasStyleData.value?.screenAdaptor)
|
||||
) {
|
||||
changeRefComponentsSizeWithScalePoint(
|
||||
baseComponentData.value,
|
||||
canvasStyleData.value,
|
||||
100,
|
||||
100,
|
||||
100
|
||||
)
|
||||
} else {
|
||||
changeRefComponentsSizeWithScalePoint(
|
||||
baseComponentData.value,
|
||||
canvasStyleData.value,
|
||||
scaleMin.value || outerScale.value * 100,
|
||||
scaleMinHeight || outerScale.value * 100,
|
||||
outerScale.value * 100
|
||||
)
|
||||
}
|
||||
scaleMin.value = isMainCanvas(canvasId.value) ? scaleMin.value : outerScale.value * 100
|
||||
}
|
||||
renderReady.value = true
|
||||
@@ -514,71 +546,77 @@ defineExpose({
|
||||
@scroll="scrollPreview"
|
||||
v-if="state.initState"
|
||||
>
|
||||
<!--弹框触发区域-->
|
||||
<canvas-filter-btn :is-fixed="isOverSize" v-if="filterBtnShow"></canvas-filter-btn>
|
||||
<!-- 弹框区域 -->
|
||||
<PopArea
|
||||
v-if="popAreaAvailable"
|
||||
:dv-info="dvInfo"
|
||||
:canvas-id="canvasId"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
:canvasViewInfo="canvasViewInfo"
|
||||
:pop-component-data="popComponentData"
|
||||
:scale="scaleMin"
|
||||
:canvas-state="canvasState"
|
||||
:show-position="'preview'"
|
||||
></PopArea>
|
||||
<canvas-opt-bar
|
||||
v-if="showLinkageButton"
|
||||
:canvas-id="canvasId"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
:component-data="baseComponentData"
|
||||
:is-fixed="isOverSize"
|
||||
></canvas-opt-bar>
|
||||
<template v-if="renderReady && !showUnpublishFlag">
|
||||
<component-wrapper
|
||||
v-for="(item, index) in baseComponentData"
|
||||
v-show="item.isShow"
|
||||
:active="item.id === (curComponent || {})['id']"
|
||||
<div ref="previewCanvasInner" :style="canvasStyleInner">
|
||||
<!--弹框触发区域-->
|
||||
<canvas-filter-btn :is-fixed="isOverSize" v-if="filterBtnShow"></canvas-filter-btn>
|
||||
<!-- 弹框区域 -->
|
||||
<PopArea
|
||||
v-if="popAreaAvailable"
|
||||
:dv-info="dvInfo"
|
||||
:canvas-id="canvasId"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
:dv-info="dvInfo"
|
||||
:canvas-view-info="canvasViewInfo"
|
||||
:view-info="canvasViewInfo[item.id]"
|
||||
:key="index"
|
||||
:config="item"
|
||||
:style="getShapeItemShowStyle(item)"
|
||||
:show-position="showPosition"
|
||||
:search-count="curSearchCount"
|
||||
:scale="mobileInPc && isDashboard() ? 100 : scaleMin"
|
||||
:is-selector="props.isSelector"
|
||||
:font-family="canvasStyleData.fontFamily || fontFamily"
|
||||
:scroll-main="state.scrollMain"
|
||||
@userViewEnlargeOpen="userViewEnlargeOpen($event, item)"
|
||||
@datasetParamsInit="datasetParamsInit(item)"
|
||||
@onPointClick="onPointClick"
|
||||
:index="index"
|
||||
/>
|
||||
</template>
|
||||
<empty-background
|
||||
v-if="showUnpublishFlag"
|
||||
:description="t('visualization.resource_not_published')"
|
||||
img-type="none"
|
||||
>
|
||||
</empty-background>
|
||||
<user-view-enlarge ref="userViewEnlargeRef"></user-view-enlarge>
|
||||
:canvasViewInfo="canvasViewInfo"
|
||||
:pop-component-data="popComponentData"
|
||||
:scale="scaleMin"
|
||||
:canvas-state="canvasState"
|
||||
:show-position="'preview'"
|
||||
></PopArea>
|
||||
<canvas-opt-bar
|
||||
v-if="showLinkageButton"
|
||||
:canvas-id="canvasId"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
:component-data="baseComponentData"
|
||||
:is-fixed="isFixedFlag"
|
||||
></canvas-opt-bar>
|
||||
<template v-if="renderReady && !showUnpublishFlag">
|
||||
<component-wrapper
|
||||
v-for="(item, index) in baseComponentData"
|
||||
v-show="item.isShow"
|
||||
:active="item.id === (curComponent || {})['id']"
|
||||
:canvas-id="canvasId"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
:dv-info="dvInfo"
|
||||
:canvas-view-info="canvasViewInfo"
|
||||
:view-info="canvasViewInfo[item.id]"
|
||||
:key="index"
|
||||
:config="item"
|
||||
:style="getShapeItemShowStyle(item)"
|
||||
:cur-style="getShapeItemShowStyle(item)"
|
||||
:show-position="showPosition"
|
||||
:search-count="curSearchCount"
|
||||
:scale="mobileInPc && isDashboard() ? 100 : scaleMin"
|
||||
:is-selector="props.isSelector"
|
||||
:font-family="canvasStyleData.fontFamily || fontFamily"
|
||||
:scroll-main="state.scrollMain"
|
||||
@userViewEnlargeOpen="userViewEnlargeOpen($event, item)"
|
||||
@datasetParamsInit="datasetParamsInit(item)"
|
||||
@onPointClick="onPointClick"
|
||||
:index="index"
|
||||
/>
|
||||
</template>
|
||||
<empty-background
|
||||
v-if="showUnpublishFlag"
|
||||
:description="t('visualization.resource_not_published')"
|
||||
img-type="none"
|
||||
>
|
||||
</empty-background>
|
||||
<user-view-enlarge ref="userViewEnlargeRef"></user-view-enlarge>
|
||||
</div>
|
||||
<empty-background v-if="!state.initState" description="参数不能为空" img-type="noneWhite" />
|
||||
<de-fullscreen ref="fullScreeRef"></de-fullscreen>
|
||||
<dataset-params-component ref="customDatasetParamsRef"></dataset-params-component>
|
||||
<XpackComponent
|
||||
ref="openHandler"
|
||||
jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI="
|
||||
/>
|
||||
<link-opt-bar
|
||||
v-if="linkOptBarShow"
|
||||
ref="link-opt-bar"
|
||||
:terminal="'pc'"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
@link-export-pdf="downloadAsPDF"
|
||||
/>
|
||||
</div>
|
||||
<empty-background v-if="!state.initState" description="参数不能为空" img-type="noneWhite" />
|
||||
<de-fullscreen ref="fullScreeRef"></de-fullscreen>
|
||||
<dataset-params-component ref="customDatasetParamsRef"></dataset-params-component>
|
||||
<XpackComponent ref="openHandler" jsname="L2NvbXBvbmVudC9lbWJlZGRlZC1pZnJhbWUvT3BlbkhhbmRsZXI=" />
|
||||
<link-opt-bar
|
||||
v-if="linkOptBarShow"
|
||||
ref="link-opt-bar"
|
||||
:terminal="'pc'"
|
||||
:canvas-style-data="canvasStyleData"
|
||||
@link-export-pdf="downloadAsPDF"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -148,6 +148,7 @@ import dvHidden from '@/assets/svg/dv-hidden.svg'
|
||||
import { groupSizeStyleAdaptor, groupStyleRevert, tabInnerStyleRevert } from '@/utils/style'
|
||||
import {
|
||||
checkJoinTab,
|
||||
getTransformParams,
|
||||
isDashboard,
|
||||
isGroupCanvas,
|
||||
isMainCanvas,
|
||||
@@ -553,6 +554,7 @@ const handleMouseDownOnShape = e => {
|
||||
e.stopPropagation()
|
||||
return
|
||||
}
|
||||
const { tOffsetX, tOffsetY, tOffsetSpeed } = getTransformParams()
|
||||
dashboardActive.value && emit('onStartMove', e)
|
||||
// 将当前点击组件的事件传播出去
|
||||
nextTick(() => eventBus.emit('componentClick'))
|
||||
@@ -569,8 +571,8 @@ const handleMouseDownOnShape = e => {
|
||||
cursors.value = getCursor() // 根据旋转角度获取光标位置
|
||||
|
||||
const pos = { ...defaultStyle.value }
|
||||
const startY = e.clientY
|
||||
const startX = e.clientX
|
||||
const startY = e.clientY - tOffsetY
|
||||
const startX = e.clientX - tOffsetX
|
||||
|
||||
const offsetY = e.offsetY
|
||||
const offsetX = e.offsetX
|
||||
@@ -594,10 +596,10 @@ const handleMouseDownOnShape = e => {
|
||||
const curDom = document.getElementById(domId.value)
|
||||
const move = moveEvent => {
|
||||
hasMove = true
|
||||
const curX = moveEvent.clientX
|
||||
const curY = moveEvent.clientY
|
||||
const top = curY - startY + startTop
|
||||
const left = curX - startX + startLeft
|
||||
const curX = moveEvent.clientX - tOffsetX
|
||||
const curY = moveEvent.clientY - tOffsetY
|
||||
const top = (curY - startY) * tOffsetSpeed + startTop
|
||||
const left = (curX - startX) * tOffsetSpeed + startLeft
|
||||
pos['top'] = top
|
||||
pos['left'] = left
|
||||
// 非主画布非分组画布的情况 需要检测是否从Tab中移除组件(向左移除30px 或者向右移除30px 向左移除30px)
|
||||
@@ -733,6 +735,7 @@ const handleMouseDownOnPoint = (point, e) => {
|
||||
dvMainStore.setClickComponentStatus(true)
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
const { tOffsetX, tOffsetY, tOffsetSpeed, tScale } = getTransformParams()
|
||||
const style = { ...defaultStyle.value }
|
||||
|
||||
// 组件宽高比
|
||||
@@ -754,14 +757,12 @@ const handleMouseDownOnPoint = (point, e) => {
|
||||
// 当前点击圆点相对于画布的中心坐标
|
||||
const curPoint = {
|
||||
x: Math.round(
|
||||
pointRect.left -
|
||||
editorRectInfo.left +
|
||||
(pointRect.left - editorRectInfo.left) * tOffsetSpeed +
|
||||
e.target.offsetWidth / 2 +
|
||||
offsetGapAdaptor('x', point) / 2
|
||||
),
|
||||
y: Math.round(
|
||||
pointRect.top -
|
||||
editorRectInfo.top +
|
||||
(pointRect.top - editorRectInfo.top) * tOffsetSpeed +
|
||||
e.target.offsetHeight / 2 +
|
||||
offsetGapAdaptor('y', point) / 2
|
||||
)
|
||||
@@ -802,8 +803,12 @@ const handleMouseDownOnPoint = (point, e) => {
|
||||
|
||||
needSave = true
|
||||
const curPosition = {
|
||||
x: moveEvent.clientX - Math.round(editorRectInfo.left) + offsetGapAdaptor('x', point),
|
||||
y: moveEvent.clientY - Math.round(editorRectInfo.top) + offsetGapAdaptor('y', point)
|
||||
x:
|
||||
(moveEvent.clientX - Math.round(editorRectInfo.left)) * tOffsetSpeed +
|
||||
offsetGapAdaptor('x', point),
|
||||
y:
|
||||
(moveEvent.clientY - Math.round(editorRectInfo.top)) * tOffsetSpeed +
|
||||
offsetGapAdaptor('y', point)
|
||||
}
|
||||
calculateComponentPositionAndSize(point, style, curPosition, proportion, needLockProportion, {
|
||||
center,
|
||||
|
||||
@@ -4,7 +4,7 @@ import { propTypes } from '@/utils/propTypes'
|
||||
import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
|
||||
const VisualizationEditor = defineAsyncComponent(
|
||||
() => import('@/views/data-visualization/index.vue')
|
||||
() => import('@/views/data-visualization/indexV3.vue')
|
||||
)
|
||||
const DashboardEditor = defineAsyncComponent(() => import('@/views/dashboard/index.vue'))
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ export const routes: AppRouteRecordRaw[] = [
|
||||
name: 'dvCanvas',
|
||||
hidden: true,
|
||||
meta: {},
|
||||
component: () => import('@/views/data-visualization/index.vue')
|
||||
component: () => import('@/views/data-visualization/indexV3.vue')
|
||||
},
|
||||
{
|
||||
path: '/dashboard',
|
||||
|
||||
@@ -1654,6 +1654,21 @@ export const dvMainStore = defineStore('dataVisualization', {
|
||||
|
||||
this.canvasStyleData = deepCopy(canvasStyleDataNew)
|
||||
this.canvasStyleData.dvType = dvType
|
||||
if (dvType === 'dataV') {
|
||||
this.canvasStyleData.scale = 100
|
||||
this.canvasStyleData.scaleWidth = 100
|
||||
this.canvasStyleData.scaleHeight = 100
|
||||
this.canvasStyleData.tScale = 0.6
|
||||
this.canvasStyleData.tScaleWidth = 0.6
|
||||
this.canvasStyleData.tScaleHeight = 0.6
|
||||
} else {
|
||||
this.canvasStyleData.scale = 60
|
||||
this.canvasStyleData.scaleWidth = 60
|
||||
this.canvasStyleData.scaleHeight = 60
|
||||
this.canvasStyleData.tScale = 1
|
||||
this.canvasStyleData.tScaleWidth = 1
|
||||
this.canvasStyleData.tScaleHeight = 1
|
||||
}
|
||||
this.componentData = []
|
||||
this.canvasViewInfo = {}
|
||||
},
|
||||
|
||||
@@ -300,6 +300,19 @@ export function historyAdaptor(
|
||||
componentItem.canvasId = 'canvas-main'
|
||||
})
|
||||
}
|
||||
canvasStyleResult['dvType'] = attachInfo.dvType
|
||||
if (attachInfo.dvType === 'dataV') {
|
||||
// 首次赋值
|
||||
canvasStyleResult['tScale'] = canvasStyleResult['tScale'] || canvasStyleResult.scale / 100
|
||||
canvasStyleResult['tScaleWidth'] =
|
||||
canvasStyleResult['tScaleWidth'] || canvasStyleResult.scaleWidth / 100
|
||||
canvasStyleResult['tScaleHeight'] =
|
||||
canvasStyleResult['tScaleHeight'] || canvasStyleResult.scaleHeight / 100
|
||||
} else {
|
||||
canvasStyleResult['tScale'] = 1
|
||||
canvasStyleResult['tScaleWidth'] = 1
|
||||
canvasStyleResult['tScaleHeight'] = 1
|
||||
}
|
||||
const curVersion = wsCache.get('x-de-execute-version')
|
||||
|
||||
// 含有定时报告过滤项每次都需要匹配
|
||||
|
||||
@@ -17,7 +17,7 @@ const { close } = useLoading()
|
||||
const currentComponent = shallowRef()
|
||||
const Preview = defineAsyncComponent(() => import('@/views/data-visualization/PreviewCanvas.vue'))
|
||||
const VisualizationEditor = defineAsyncComponent(
|
||||
() => import('@/views/data-visualization/index.vue')
|
||||
() => import('@/views/data-visualization/indexV3.vue')
|
||||
)
|
||||
const DashboardEditor = defineAsyncComponent(() => import('@/views/dashboard/index.vue'))
|
||||
|
||||
|
||||
@@ -98,6 +98,10 @@ export const DEFAULT_CANVAS_STYLE_DATA_BASE = {
|
||||
scale: 60,
|
||||
scaleWidth: 60,
|
||||
scaleHeight: 60,
|
||||
dvType: 'dashboard', // screen
|
||||
tScale: 0.6, // transformScale
|
||||
tScaleWidth: 0.6,
|
||||
tScaleHeight: 0.6,
|
||||
backgroundColorSelect: true,
|
||||
backgroundImageEnable: false,
|
||||
backgroundType: 'backgroundColor', // 废弃
|
||||
|
||||
Reference in New Issue
Block a user