<template>
<div ref="resizeDom" class="canvas-size-controller" :style="sizeStyle">
<slot></slot>
<div ref="resize" class="canvas-resize-handle" @mousedown.stop="onMouseDown">
<div class="handle right-handle">
<div class="gutter-handle"></div>
<div class="tab-handle"></div>
</div>
</div>
</div>
</template>
<script>
import { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'
import { useLayout, useCanvas } from '@opentiny/tiny-engine-meta-register'
import { canvasState } from '../container'
export default {
setup() {
const sizeStyle = computed(() => {
const { width, height, maxWidth, minWidth } = useLayout().getDimension()
return {
width,
height,
maxWidth,
minWidth
}
})
const mouseDown = ref(false)
const resizeDom = ref(null)
const calculateSize = ({ movementX }) => {
const dimension = useLayout().getDimension()
const { maxWidth, minWidth, width } = dimension
const newWidth = parseInt(width) + movementX * 2
useLayout().setDimension({
width: `${parseInt(Math.min(Math.max(newWidth, parseInt(minWidth)), parseInt(maxWidth)), 10)}px`
})
}
const onMouseMove = (event) => {
if (mouseDown.value) {
event.preventDefault()
calculateSize(event)
}
}
const onMouseUp = () => {
const iframe = canvasState.iframe
if (iframe) {
iframe.style['pointer-events'] = 'auto'
mouseDown.value = false
document.removeEventListener('mousemove', onMouseMove, { passive: false })
document.removeEventListener('mouseup', onMouseUp)
}
}
const bindEvents = () => {
document.addEventListener('mousemove', onMouseMove, { passive: false })
document.addEventListener('mouseup', onMouseUp)
}
const onMouseDown = () => {
const iframe = canvasState.iframe
if (iframe) {
iframe.style['pointer-events'] = 'none'
bindEvents()
mouseDown.value = true
}
}
const setScale = () => {
useLayout().setDimension({ scale: 1 })
nextTick(() => {
const canvasWrap = document.querySelector('#canvas-wrap')
if (!canvasWrap) {
return
}
const rate = canvasWrap.offsetWidth / resizeDom.value.offsetWidth
useLayout().setDimension({
scale: Math.min(rate, 1)
})
})
}
const draggablePanel = ref(null)
watch(() => useLayout().getPluginWidth(draggablePanel.value), setScale, { flush: 'post' })
watch(() => useLayout().getDimension().width, setScale, { flush: 'post', immediate: true })
watch(() => useLayout().leftFixedPanelsStorage.value, setScale, { flush: 'post' })
watch(
() => useLayout().getPluginState().render,
(value) => {
const currentFixed = useLayout().getPluginState().fixedPanels.includes(value)
const isPanelResizable = useLayout().isPanelWidthResizable(value)
if (isPanelResizable) {
draggablePanel.value = value
}
if (!value || currentFixed) {
setScale()
}
},
{ flush: 'post' }
)
watch(() => useLayout().rightFixedPanelsStorage.value, setScale, { flush: 'post' })
watch(() => useLayout().layoutState.toolbars.render, setScale, { flush: 'post' })
watch(
() => useLayout().getSettingState().render,
(value) => {
const currentFixed = useLayout().rightFixedPanelsStorage.value.includes(value)
if (!value || currentFixed) {
setScale()
}
},
{ flush: 'post' }
)
watch(
() => sizeStyle.value,
() => {
nextTick(() => {
useCanvas().canvasApi.value?.updateRect?.()
})
}
)
const handleResize = () => {
setScale()
}
onMounted(() => {
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
return {
onMouseDown,
onMouseMove,
sizeStyle,
resizeDom
}
}
}
</script>
<style lang="less" scoped>
.canvas-size-controller {
height: 100%;
.canvas-resize-handle {
position: relative;
.handle {
position: absolute;
top: 0;
bottom: 0;
z-index: 13;
&::before {
content: '';
position: absolute;
top: 0;
left: -3px;
width: 4px;
height: 100%;
background: var(--te-canvas-container-bg-color-checked);
display: none;
}
&:hover::before {
display: block;
}
&:hover {
.tab-handle {
background: var(--te-canvas-container-bg-color-checked);
}
.tab-handle:before,
.tab-handle:after {
background: #ffffff;
}
}
.gutter-handle {
position: absolute;
top: 0;
left: -3px;
width: 4px;
height: 100%;
cursor: col-resize;
pointer-events: all;
}
.tab-handle {
position: fixed;
top: 50%;
width: 14px;
height: 38px;
margin-top: -19px;
background: var(--te-canvas-container-canvas-size-tab-bg-color);
cursor: col-resize;
pointer-events: all;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
&::before,
&::after {
content: '';
position: absolute;
top: 8px;
bottom: 8px;
left: 8px;
width: 1px;
background: var(--te-canvas-container-tab-handle-color);
}
&::before {
left: 5px;
}
}
}
.right-handle {
right: -14px;
width: 14px;
}
}
}
</style>