Skip to content

Commit

Permalink
fix: 重构画布坐标系
Browse files Browse the repository at this point in the history
  • Loading branch information
gene9831 committed Apr 30, 2024
1 parent 60de1df commit c53fbde
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 78 deletions.
41 changes: 21 additions & 20 deletions packages/canvas/src/components/container/CanvasAction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ import {
IconEyeclose
} from '@opentiny/vue-icon'
import {
canvasState,
getCurrent,
removeNodeById,
selectNode,
Expand Down Expand Up @@ -379,15 +380,14 @@ export default {
}
}
const getStyleValues = (selectState, siteCanvasWidth, siteCanvasHeight) => {
const getStyleValues = (selectState, canvasSize, labelWidth, optionWidth) => {
const { left, top, width, height, doc } = selectState
const labelRect = labelRef.value.getBoundingClientRect()
const optionRect = optionRef.value.getBoundingClientRect()
const { width: canvasWidth, height: canvasHeight } = canvasSize
// 标签宽度和工具操作条宽度之和加上间距
const fullRectWidth = labelRect.width + optionRect.width + OPTION_SPACE
const fullRectWidth = labelWidth + optionWidth + OPTION_SPACE
// 是否 将label 标签放置到底部,判断 top 距离
const isLabelAtBottom = top <= LABEL_HEIGHT
const isLabelAtBottom = top < LABEL_HEIGHT
const labelAlign = new Align({
alignLeft: true,
horizontalValue: 0,
Expand All @@ -396,7 +396,7 @@ export default {
})
// 是否将操作栏放置到底部,判断当前选中组件底部与页面底部的距离。
const isOptionAtBottom = siteCanvasHeight - top - height > OPTION_BAR_HEIGHT
const isOptionAtBottom = canvasHeight - top - height >= OPTION_BAR_HEIGHT
const optionAlign = new Align({
alignLeft: false,
horizontalValue: 0,
Expand All @@ -410,39 +410,39 @@ export default {
// 选中框宽度小于标签宽度和工具操作条宽度之和加上间距
// 如果labe宽度大于选中框宽度,并且label右侧已经超出画布,则label对齐右侧
const isLabelAlignRight = labelRect.width > width && left + labelRect.width + scrollBarWidth > siteCanvasWidth
const isLabelAlignRight = labelWidth > width && left + labelWidth + scrollBarWidth > canvasWidth
if (isLabelAlignRight) {
labelAlign.align(positions.RIGHT)
}
// 如果option宽度大于选中框宽度,并且option左侧已经超出画布,则option对齐左侧
const isOptionAlignLeft = optionRect.width > width && left + width - optionRect.width < 0
const isOptionAlignLeft = optionWidth > width && left + width - optionWidth < 0
if (isOptionAlignLeft) {
optionAlign.align(positions.LEFT)
}
if (isLabelAtBottom === isOptionAtBottom) {
// 标签框和工具操作框都在顶部或者都在底部
if (left + fullRectWidth < siteCanvasWidth) {
if (left + fullRectWidth < canvasWidth) {
// 都放在左侧
labelAlign.align(positions.LEFT)
optionAlign.align(positions.LEFT, labelRect.width + OPTION_SPACE)
optionAlign.align(positions.LEFT, labelWidth + OPTION_SPACE)
} else {
// 都放在右侧
optionAlign.align(positions.RIGHT)
labelAlign.align(positions.RIGHT, optionRect.width + OPTION_SPACE)
labelAlign.align(positions.RIGHT, optionWidth + OPTION_SPACE)
}
}
} else {
if (left < 0) {
labelAlign.align(positions.LEFT, Math.min(-left, width - fullRectWidth))
}
if (left + width + scrollBarWidth > siteCanvasWidth) {
if (left + width + scrollBarWidth > canvasWidth) {
optionAlign.align(
positions.RIGHT,
Math.min(left + width + scrollBarWidth - siteCanvasWidth, width - fullRectWidth)
Math.min(left + width + scrollBarWidth - canvasWidth, width - fullRectWidth)
)
}
}
Expand All @@ -454,8 +454,7 @@ export default {
}
watchPostEffect(async () => {
let { left } = props.selectState
const { top, width, height, doc } = props.selectState
const { left, top, width, height, doc } = props.selectState
// nextTick后ref才能获取到元素。需要把监听的依赖放在await之前,否则无法监听变化
await nextTick()
Expand All @@ -470,15 +469,17 @@ export default {
return
}
const siteCanvasRect = document.querySelector('.site-canvas').getBoundingClientRect()
const scale = useLayout().getScale()
const canvasRect = canvasState.iframe.getBoundingClientRect()
const { width: labelWidth } = labelRef.value.getBoundingClientRect()
const { width: optionWidth } = optionRef.value.getBoundingClientRect()
left -= ((1 - scale) / 2) * siteCanvasRect.width
// canvas容器中,iframe以及iframe之外的元素clientRect的尺寸都是缩放过的,除以scale得到原始大小
const { labelStyleValue, optionStyleValue } = getStyleValues(
{ left, top, width, height, doc },
siteCanvasRect.width * scale,
siteCanvasRect.height
{ width: canvasRect.width / scale, height: canvasRect.height / scale },
labelWidth / scale,
optionWidth / scale
)
labelStyle.value = labelStyleValue
Expand Down
3 changes: 1 addition & 2 deletions packages/canvas/src/components/container/CanvasContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import {
updateRect,
getElement,
dragStart,
getOffset,
selectNode,
initCanvas,
clearLineState,
Expand Down Expand Up @@ -100,7 +99,7 @@ export default {
// 如果是点击右键则打开右键菜单
if (event.button === 2) {
openMenu(getOffset(event.target), event)
openMenu(event)
}
}
}
Expand Down
10 changes: 4 additions & 6 deletions packages/canvas/src/components/container/CanvasMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,11 @@ export const closeMenu = () => {
current.value = null
}
export const openMenu = (offset, event) => {
const { x, y } = offset
const { getScale } = useLayout()
export const openMenu = (event) => {
menuState.position = {
// 位置处于画布右侧边缘时需要调整显示方向 TODO
left: event.clientX * getScale() + x + 2 + 'px',
top: event.clientY * getScale() + y + 'px'
left: event.clientX + 2 + 'px',
top: event.clientY + 'px'
}
menuState.show = sessionStorage.getItem('pageInfo') ? true : false
Expand Down Expand Up @@ -235,7 +233,7 @@ export default {

<style lang="less" scoped>
.context-menu {
position: fixed;
position: absolute;
z-index: 10;
}
.menu-item {
Expand Down
7 changes: 3 additions & 4 deletions packages/canvas/src/components/container/CanvasResize.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@ import { canvasState } from './container'
export default {
setup() {
const sizeStyle = computed(() => {
const { width, maxWidth, minWidth, scale } = useLayout().getDimension()
const { width, height, maxWidth, minWidth } = useLayout().getDimension()
return {
width,
height,
maxWidth,
minWidth,
height: `${100 / scale}%`,
transform: `scale(${scale}) translateY(-${(100 / scale - 100) / 2}%)`
minWidth
}
})
Expand Down
30 changes: 10 additions & 20 deletions packages/canvas/src/components/container/CanvasResizeBorder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,17 @@ export default {
}
const handleResize = (event, type) => {
let { clientX, clientY } = event
if (!props.iframe) {
return
}
const siteCanvasRect = document.querySelector('.site-canvas').getBoundingClientRect()
let { clientX, clientY } = event
const iframeRect = props.iframe.getBoundingClientRect()
const scale = useLayout().getScale()
const offsetX = ((1 - scale) / 2) * siteCanvasRect.width
if (type === 'iframe' && props.iframe) {
clientX = clientX - offsetX
} else {
clientX = clientX - siteCanvasRect.left - offsetX
clientY = clientY - siteCanvasRect.top
if (scale < 1) {
clientX = clientX / scale - offsetX
clientY = clientY / scale
}
if (type !== 'iframe') {
clientX = (clientX - iframeRect.left) / scale
clientY = (clientY - iframeRect.top) / scale
}
const { parent, schema } = getCurrent()
Expand All @@ -76,14 +71,9 @@ export default {
const parentWidth = parseInt(window.getComputedStyle(parentDomNode).width, 10)
// 最大宽度不能大于父组件宽度
if (newWidth >= parentWidth) {
newWidth = parentWidth
}
newWidth = Math.min(newWidth, parentWidth)
// 最小宽度32
if (newWidth <= 32) {
newWidth = 32
}
newWidth = Math.max(newWidth, 32)
schema.props.flexBasis = `${newWidth}px`
schema.props.widthType = 'fixed'
Expand Down
39 changes: 16 additions & 23 deletions packages/canvas/src/components/container/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,16 +346,13 @@ const setSelectRect = (element) => {
element = element || getDocument().body

const { left, height, top, width } = getRect(element)
const { x, y } = getOffset(element)
const siteCanvasRect = document.querySelector('.site-canvas').getBoundingClientRect()
const componentName = getCurrent().schema?.componentName || ''
const scale = useLayout().getScale()
clearHover()
Object.assign(selectState, {
width: width * scale,
height: height * scale,
top: top * scale + y - siteCanvasRect.y,
left: left * scale + x - siteCanvasRect.x,
width,
height,
top,
left,
componentName,
doc: getDocument()
})
Expand Down Expand Up @@ -479,9 +476,6 @@ const setHoverRect = (element, data) => {
const configure = getConfigure(componentName)
const rect = getRect(element)
const { left, height, top, width } = rect
const { x, y } = getOffset(element)
const siteCanvasRect = document.querySelector('.site-canvas').getBoundingClientRect()
const scale = useLayout().getScale()

hoverState.configure = configure

Expand Down Expand Up @@ -510,23 +504,22 @@ const setHoverRect = (element, data) => {
if (childEle) {
const childRect = getRect(childEle)
const { left, height, top, width } = childRect
const { x, y } = getOffset(childEle)
const posLine = getPosLine(childRect, lineState.configure)
Object.assign(lineState, {
width: width * scale,
height: height * scale,
top: top * scale + y - siteCanvasRect.y,
left: left * scale + x - siteCanvasRect.x,
width,
height,
top,
left,
position: canvasState.type === 'absolute' || posLine.type,
forbidden: posLine.forbidden
})
} else {
const posLine = getPosLine(rect, configure)
Object.assign(lineState, {
width: width * scale,
height: height * scale,
top: top * scale + y - siteCanvasRect.y,
left: left * scale + x - siteCanvasRect.x,
width,
height,
top,
left,
position: canvasState.type === 'absolute' || posLine.type,
forbidden: posLine.forbidden
})
Expand All @@ -537,10 +530,10 @@ const setHoverRect = (element, data) => {

// 设置元素hover状态
Object.assign(hoverState, {
width: width * scale,
height: height * scale,
top: top * scale + y - siteCanvasRect.y,
left: left * scale + x - siteCanvasRect.x,
width,
height,
top,
left,
componentName
})
return undefined
Expand Down
15 changes: 12 additions & 3 deletions packages/design-core/src/DesignCanvas.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div id="canvas-wrap" ref="canvasRef">
<div ref="siteCanvas" class="site-canvas">
<div ref="siteCanvas" class="site-canvas" :style="siteCanvasStyle">
<canvas-container
:controller="controller"
:materials-panel="materialsPanel"
Expand All @@ -14,7 +14,7 @@
</template>

<script>
import { ref, onMounted, watch } from 'vue'
import { ref, onMounted, watch, computed } from 'vue'
import {
CanvasContainer,
CanvasFooter,
Expand Down Expand Up @@ -67,6 +67,14 @@ export default {
pageState.properties = null
}
const siteCanvasStyle = computed(() => {
const { scale } = useLayout().getDimension()
return {
height: `calc((100% - var(--base-bottom-panel-height, 30px) - 36px) / ${scale})`,
transform: `scale(${scale})`
}
})
watch(
[() => useCanvas().isSaved(), () => useLayout().layoutState.pageStatus, () => useCanvas().getPageSchema()],
([isSaved, pageStatus, pageSchema], [oldIsSaved, _oldPageStatus, oldPageSchema]) => {
Expand Down Expand Up @@ -166,6 +174,7 @@ export default {
request: useHttp(),
ast
},
siteCanvasStyle,
canvasRef
}
}
Expand All @@ -182,11 +191,11 @@ export default {
position: relative;
.site-canvas {
height: calc(100% - var(--base-bottom-panel-height, 30px) - 36px);
background: var(--ti-lowcode-breadcrumb-hover-bg);
position: absolute;
overflow: hidden;
margin: 18px 0;
transform-origin: top;
}
}
</style>

0 comments on commit c53fbde

Please sign in to comment.