1.画布实现思路
HTML结构
<template>
<div id="wrapper" class="wrapper">
<SketchRule
:lang="lang"
:thick="thick"
:scale="scale"
:width="width"
:height="height"
:start-x="startX"
:start-y="startY"
:palette="palette"
:corner-active="true"
:is-show-refer-line="isShowReferLine"
@handleLine="handleLine"
@onCornerClick="handleCornerClick"
/>
<div
id="screens"
ref="screensRef"
@wheel="handleWheel"
@scroll="handleScroll"
>
<div id="screen-container" ref="containerRef" class="screen-container">
<div id="canvas" ref="canvas" :style="canvasStyle" />
</div>
</div>
</div>
</template>
<script>
import { getElements } from '../netWork/editor'
import { pageInfo, screenList, themeColorOption } from '../netWork/page/pageSetting/index'
import SketchRule from 'vue-sketch-ruler'
import bus from '../assets/js/eventBus'
// const rectWidth = 1900
// const rectHeight = 720
export default {
name: 'Editor',
components: {
SketchRule
},
data() {
return {
timesx: 0.68,
timesy: 0.6,
maxScale: 4,
minScale: 0.3,
result: null,
timer: null,
nowTime: new Date(),
x: 0,
y: 0,
scale: 1, // 658813476562495, //1,
startX: 0,
startY: 0,
lines: {
},
palette: {
bgColor: '#13141c',
longfgColor: '#ffffff',
shortfgColor: '#C8CDD0',
fontColor: '#ffffff',
shadowColor: '#13141c',
lineColor: '#EB5648',
borderColor: '#DADADC',
cornerActiveColor: 'rgb(235, 86, 72, 0.6)'
},
initLeft: '',
initTop: '',
thick: 20,
width: 1319,
height: 830,
lang: 'zh-CN', // 中英文
isShowRuler: true, // 显示标尺
isShowReferLine: true, // 显示参考线
pageInfoObj: {},
screenSelectData: [],
colorData: [],
colorDataPlay: [],
screenName: '',
screenId: '',
screenwidth: '',
screenheight: '',
themeType: '',
bgUrl: ''
}
},
computed: {
shadow() {
return {
x: 0,
y: 0,
width: this.screenwidth,
height: this.screenheight
}
},
canvasStyle() {
return {
width: this.screenwidth + 'px',
height: this.screenheight + 'px',
// transform: `scale(${this.scale})`,
// width: 10000 + 'px',
// height: 5000 + 'px',
backgroundColor: this.pageInfoObj.bgColor + '!important',
backgroundImage: `url(${this.bgUrl})`,
opacity: this.pageInfoObj.bgOpacity / 100,
backgroundSize: this.pageInfoObj.overviewType === 2 ? `100% 100%` : (this.pageInfoObj.overviewType === 3 ? null : 'contain'),
backgroundRepeat: this.pageInfoObj.overviewType === 3 ? 'repeat' : 'no-repeat'
// transform: `translate3d(${this.x}, ${this.y}, 0) scale(${(this.scale - 0.005)})`
}
}
},
created() {
this.init(this.$store.state.currentPageId, 1)
// 滚动居中
this.$nextTick(() => {
this.scrollInit() // 将鼠标滚动换为拖拽的方式
this.initSize()
})
},
mounted() {
},
methods: {
scrollInit() {
// 获取要绑定事件的元素
const nav = document.getElementById('screens')
var flag // 鼠标按下
var downX // 鼠标点击的x下标
var downY
var scrollLeft // 当前元素滚动条的偏移量
var scrollTop
nav.addEventListener('mousedown', function(event) {
// event.stopPropagation()
flag = true
downX = event.clientX // 获取到点击的x下标
downY = event.clientY
scrollLeft = this.scrollLeft // 获取当前元素滚动条的偏移量
scrollTop = this.scrollTop
})
nav.addEventListener('mousemove', function(event) {
// event.stopPropagation()
if (flag) { // 判断是否是鼠标按下滚动元素区域
var moveX = event.clientX // 获取移动的x轴
var moveY = event.clientY
var scrollX = moveX - downX // 当前移动的x轴下标减去刚点击下去的x轴下标得到鼠标滑动距离
var scrollY = moveY - downY
this.scrollLeft = scrollLeft - scrollX // 鼠标按下的滚动条偏移量减去当前鼠标的滑动距离
this.scrollTop = scrollTop - scrollY
}
})
// 鼠标抬起停止拖动
nav.addEventListener('mouseup', function() {
// event.stopPropagation()
flag = false
})
// 鼠标离开元素停止拖动
nav.addEventListener('mouseleave', function(event) {
// event.stopPropagation()
flag = false
})
},
init(id, params) {
const _this = this
if (id && id !== -1) {
// 获取页面的样式
pageInfo(id).then(async res => {
this.pageInfoObj = res.data
this.pageInfoObj.useBgPic === 1 ? this.bgUrl = this.pageInfoObj.url : this.bgUrl = ''
await screenList(this.pageInfoObj.id).then(res => {
this.screenSelectData = res.data
this.screenSelectData.forEach(ele => {
if (ele.id === this.pageInfoObj.screenId) {
this.screenName = ele.screenName
this.screenId = ele.id
this.screenwidth = ele.width
this.screenheight = ele.height
this.scale = 1
this.$nextTick(() => {
if (_this.screenwidth >= 3000) {
_this.timesx = 0.262
} else if (_this.screenwidth >= 2000 && _this.screenwidth < 3000) {
_this.timesx = 0.85
} else {
_this.timesx = 0.5
}
if (_this.screenheight >= 3000) {
_this.timesy = 1.52
} else if (_this.screenheight >= 1800 && _this.screenheight < 2400) {
_this.timesy = 1.1
} else {
_this.timesy = 0.5
}
var box = document.getElementById('canvas')
this.result = {
width: getComputedStyle(box).width.slice(0, -2) * 1,
height: getComputedStyle(box).height.slice(0, -2) * 1
}
// 初始页面的滚动条偏移量
_this.$refs.screensRef.scrollLeft =
(_this.$refs.containerRef.getBoundingClientRect().width + _this.$refs.canvas.style.width.slice(0, -2) * 1 - 1319) / 2 // 1319 为screen的宽度
_this.$refs.screensRef.scrollTop =
(_this.$refs.canvas.style.height.slice(0, -2) * 1 - 898) / 2 // 898 为screen的高度加上21
})
if (params) {
_this.computedScale()
}
}
})
})
themeColorOption({ type: this.pageInfoObj.themeType, id: '' }).then(res => {
this.colorData = res.data
this.colorData.forEach(ele => {
if (ele.id === this.pageInfoObj.themeColorId) {
this.colorDataPlay = ele.children
}
})
this.themeType = this.colorData[0].themeType
})
})
}
},
// 初始化计算缩放比展示全页面
computedScale() {
var dom = document.getElementById('screens')
var height = getComputedStyle(dom).height.substr(0, getComputedStyle(dom).height.indexOf('p')) * 1
var width = getComputedStyle(dom).width.substr(0, getComputedStyle(dom).width.indexOf('p')) * 1
var dom2 = document.getElementById('canvas')
if (width < this.screenwidth) {
this.initScale = this.scale = (width / this.screenwidth).toFixed(2) * 1
} else if (height < this.screenheight) {
this.initScale = this.scale = (height / this.screenheight).toFixed(2) * 1
} else {
this.initScale = this.scale = 1
dom2.style.transform = `translate3d(${this.x}px, ${this.y}px, 0) scale(${(this.scale)})`
return
}
dom2.style.transform = `translate3d(${this.x}px, ${this.y}px, 0) scale(${(this.scale - 0.03)})`
this.$store.commit('changeGlobalScale', this.scale)
this.initLeft = dom2.style.left
this.initTop = dom2.style.top
},
handleLine(lines) {
this.lines = lines
},
handleCornerClick() {
return
},
// 修改标尺刻度
handleScroll() {
const screensRect = document
.querySelector('#screens')
.getBoundingClientRect()
const canvasRect = document
.querySelector('#canvas')
.getBoundingClientRect()
// 标尺开始的刻度
const startX = (screensRect.left + this.thick - canvasRect.left) / this.scale
const startY = (screensRect.top + this.thick - canvasRect.top) / this.scale
this.startX = startX >> 0
this.startY = startY >> 0
// this.startX = startX
// this.startY = startY
},
// 控制缩放值
handleWheel(e) {
var box = document.getElementById('canvas')
if (e.ctrlKey || e.metaKey) {
this.flag = true
e.preventDefault()
let ratio = 1.1
// 缩小
if (e.deltaY > 0) {
ratio = 1 / 1.1
}
// 限制缩放倍数
const _scale = this.scale * ratio
if (_scale > this.maxScale) {
ratio = this.maxScale / this.scale
this.scale = this.maxScale
} else if (_scale < this.minScale) {
ratio = this.minScale / this.scale
this.scale = this.minScale
} else {
this.scale = _scale
}
console.log(this.scale, box.getBoundingClientRect())
const origin = {
x: (ratio - 1) * this.result.width * this.timesx,
y: (ratio - 1) * this.result.height * this.timesy
}
this.x -= (ratio - 1) * (e.clientX - this.x) - origin.x
this.y -= (ratio - 1) * (e.clientY - this.y) - origin.y
box.style.transform = 'translate3d(' + this.x + 'px, ' + this.y + 'px, 0) scale(' + this.scale + ')'
this.$store.commit('changeGlobalScale', this.scale)
}
this.$nextTick(() => {
this.handleScroll()
})
},
initSize() {
const wrapperRect = document
.querySelector('#wrapper')
.getBoundingClientRect()
const borderWidth = 1
this.width = wrapperRect.width - this.thick - borderWidth
this.height = wrapperRect.height - this.thick - borderWidth
}
}
}
</script>
<style scoped lang="scss">
@import "../assets/css/handle";
@import '../assets/css/common';
.wrapper {
background-color: #f5f5f5;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 1px solid #DADADC; }
#screens {
position: absolute;
width: 100%;
height: 100%;
overflow: auto;
background-color: #7e7a7a;}
.screen-container {
position: absolute;
width: 8000px;
height: 3000px;
background: url('../assets/image/canvasBgPicture.png') repeat;
}
.scale-value {
position: absolute;
left: 0;
bottom: 100%; }
.button {
position: absolute;
left: 100px;
bottom: 100%; }
.button-ch {
position: absolute;
left: 200px;
bottom: 100%; }
.button-en {
position: absolute;
left: 230px;
bottom: 100%; }
#canvas {
position: absolute;
/*top: 20px;*/
left: 50%;
margin-left: 21px;
/*transform-origin: 50% 0;*/
transform-origin: center;
}
/*定义滚动条样式*/
::v-deep ::-webkit-scrollbar {
width: 0!important;
height: 100% !important;
background-color: white !important;
}
/*定义滚动条轨道 内阴影+圆角*/
::v-deep ::-webkit-scrollbar-track {
box-shadow: inset 0 0 0 rgba(240, 240, 240, .5);
border-radius: 0.1rem;
background-color:#909399;
}
/*定义滑块 内阴影+圆角*/
::v-deep ::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 0 rgba(240, 240, 240, .5);
background-color: #282D38;
/*border-radius: 15px;*/
}
</style>
1.借用了标尺插件## vue-sketch-ruler
github地址: github.com/chuxiaoguo/…