一些简单有规则的图形,比如矩形,椭圆,多边形......我们可以使用一些数学函数来计算判断。
这种方式非常棒,当你的画布上没有大量的图形时,他可能是非常快的。
但是这种方式很难处理那些非常复杂的几何图形。比如说,你正在使用具有二次曲线的线。
点击区域的思路很简单,我们只需要获取点击区域的像素,并且找到拥有相同颜色的图形即可。
但是这种方式可能无效,因为不同的图形可能拥有相同的颜色。为了避免这种问题,我们应该创建一个隐藏的“点击canvas画布”,它将跟主canvas画布拥有几乎相同的图形,并且每一个图形都拥有唯一的颜色。因此我们需要对每一个圆圈生成随机的颜色。
然后,我们需要绘制每个图形2次。第一次在主画布上(可见的),然后在“点击canvas画布”上(不可见)。
当你点击主canvas时,你需要做的就是获取到你点击处的位置坐标,然后在“点击canvas画布”上找到跟主cavnas同样位置的像素的颜色。
这种方式最主要的瓶颈在于你需要绘制2次。因此性能可能下降2倍!
但是我们可以简化hitCanvas的绘制,比如,跳过shadows或者strokes绘制,简化图形,比如,用矩形来代替文本。简化绘制后的方式可能是非常快的。因为从canvas上去一像素和从一个颜色hash对象(colorsHash)中取值是非常快的操作。
// 主canvas
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 点击canvas
const hitCanvas = document.createElement('canvas');
const hitCtx = hitCanvas.getContext('2d');
// 颜色对象
const colorsHash = {};
// 生成随机颜色
function getRandomColor() {
const r = Math.round(Math.random() * 255);
const g = Math.round(Math.random() * 255);
const b = Math.round(Math.random() * 255);
return `rgb(${r},${g},${b})`;
}
// 要绘制的图形对象数组
const circles = [{
id: '1', x: 40, y: 40, radius: 10, color: 'rgb(255,0,0)'
}, {
id: '2', x: 100, y: 70, radius: 10, color: 'rgb(0,255,0)'
}];
circles.forEach(circle => {
while(true) {
const colorKey = getRandomColor();
if (!colorsHash[colorKey]) {
circle.colorKey = colorKey;
colorsHash[colorKey] = circle;
return;
}
}
});
// 绘制图形
circles.forEach(circle => {
// 主canvas
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.radius, 0, 2 * Math.PI, false);
ctx.fillStyle = circle.color;
ctx.fill();
// 点击canvas
hitCtx.beginPath();
hitCtx.arc(circle.x, circle.y, circle.radius, 0, 2 * Math.PI, false);
hitCtx.fillStyle = circle.colorKey;
hitCtx.fill();
});
// 监听点击事件
canvas.addEventListener('click', (e) => {
// 获取鼠标点击位置坐标
const mousePos = {
x: e.clientX - canvas.offsetLeft,
y: e.clientY - canvas.offsetTop
};
// 获取点击位置的像素
const pixel = hitCtx.getImageData(mousePos.x, mousePos.y, 1, 1).data;
const color = `rgb(${pixel[0]},${pixel[1]},${pixel[2]})`;
const shape = colorsHash[color];
// 判断是否颜色对象为空
if (shape) {
alert('click on circle: ' + shape.id);
}
});
众所周知,json对象是没有顺序的。只有数组才有排序功能。
但我们遇到的业务场景里面,不仅仅需要对数组排序,也有需要对对象排序的情况。
let data = {
a: {age: 18, height: 189},
b: {age: 18, height: 175}
}
let map = new Map()
for (let k in data) {
map.set(k, data[k])
}
let arrayObj = Array.from(map)
// 根据 age 排序
arrayObj.sort((a, b) => {
return b[1]['age'] -a[1]['age']
})
此时会获得一个新的数组,你打印出来发现,格式变了,但我们想要的还是一开始那样的json格式,那就再把它转回来就好了。
let obj = {}
for (let i in arrayObj) {
let k = arrayObj[i][0]
let value = arrayObj[i][1]
obj[k] = value
}
想要转成map的话,可以如下:
var result = new Map(arrayObj.map(i => [i[0], i[1]]));
// 默认分辨率
let defaultRealResolutionPower = '720*1280'
// 转化分辨率
function formResolutionPower(resolutionPower: String = defaultRealResolutionPower) {
// 分辨率
if (resolutionPower) {
let _sarr = resolutionPower.split("*");
let _arr = [Number(_sarr[0]), Number(_sarr[1])];
// 设置在画板里绘制的实际分辨率
this.realResolutionPower = _arr
// 获取包裹canvas的外层标签的属性
const winBox = document.getElementById('winBox')?.getBoundingClientRect()
// 判断横竖屏
if (_arr[0] > _arr[1]) {
this.sDpi = _arr[0] / winBox?.width
// 编辑分辨率
this.resolutionPower = JSON.parse(JSON.stringify([715, _arr[1] / this.sDpi]))
} else {
this.sDpi = _arr[1] / winBox?.height
// 编辑分辨率
this.resolutionPower = JSON.parse(JSON.stringify([_arr[0] / this.sDpi, 512]))
}
this.$nextTick(() => {
const canvasBox = document.getElementById('canvasBox')?.getBoundingClientRect()
// 设置模版可编辑区域的宽高和左上角坐标
this.toucheWrap = {
width: this.resolutionPower[0],
height: this.resolutionPower[1],
top: canvasBox.top,
left: canvasBox.left
}
console.log(this.toucheWrap)
})
this.callBack('formResolutionPower')
}
}
// 初始化画板
initCanvas() {
console.log('初始化画板', this.realResolutionPower)
// 真实画板
if(!this.canvas) {
this.canvas = document.getElementById('canvas')
this.ctx = this.canvas.getContext('2d')
}
this.canvas.width = this.realResolutionPower[0]
this.canvas.height = this.realResolutionPower[1]
// 模拟画板
if(!this._canvas) {
this._canvas = document.createElement('canvas')
this._ctx = this._canvas.getContext('2d')
}
this._canvas.width = this.realResolutionPower[0]
this._canvas.height = this.realResolutionPower[1]
// 初始化video
if(!this._video) {
this._video = document.createElement('video')
this._video.setAttribute('autoplay', true)
this._video.setAttribute('loop', true)
}
},
// 生成随机颜色
getRandomColor() {
const r = Math.round(Math.random() * 255)
const g = Math.round(Math.random() * 255)
const b = Math.round(Math.random() * 255)
// const a = Math.round(Math.random() * 255)
return `rgb(${r},${g},${b})`
},
// 绘制视频片段
drawSpPartItem() {
const _items = JSON.parse(JSON.stringify(this.items))
_items.sort((a, b) => a.zIndex - b.zIndex)
// console.log('绘制图层:', _items)
this.ctx.clearRect(0, 0, this.realResolutionPower[0], this.realResolutionPower[1])
this._ctx.clearRect(0, 0, this.realResolutionPower[0], this.realResolutionPower[1])
this._tcList = [] // 模拟点击的图层列表
let activeItem = null;
for (let i = 0; i < _items.length; i++) {
let item = _items[i]
if (!item.display || !item.show) {
continue
}
if (['bg', 'tt', 'ai'].includes(item.type)) {
// 视频
if (item.iobsType == 'video') {
if (this._video.src !== item.content) {
this._video.src = item.content
console.log(this._video)
}
this.ctx.drawImage(this._video, item.left, item.top, item.width, item.height)
} else {
// 图片
const img = new Image()
// img.crossOrigin = 'anonymous'
img.src = item.content
// const img = await this.loadImage(item.content)
this.ctx.drawImage(img, item.left, item.top, item.width, item.height)
}
// 锁定
if(!item.lock) {
// 绘制模拟canvas
const _color = this.getRandomColor()
this._tcList.push({
id: item.id,
color: _color
})
this._ctx.save()
this._ctx.fillStyle = _color
this._ctx.fillRect(item.left, item.top, item.width, item.height)
this._ctx.restore()
}
} else if (['zm', 'bt'].includes(item.type)) {
this.ctx.save()
this.ctx.font = item.fontSize + 'px ' + item.fontFamily
this.ctx.textAlign = item.align
let showStroke = false
if (item.strokeShow && item.strokeSize) {
this.ctx.strokeStyle = item.strokeColor
this.ctx.lineWidth = item.strokeSize
showStroke = true
}
this.ctx.textBaseline = 'top'
this.ctx.fillStyle = item.fontBgColor
// const measureText = this.ctx.newMeasureText(item.content)
// 绘制文字背景色
this.ctx.fillRect(item.left, item.top, item.width, item.height)
// 绘制文字
this.ctx.fillStyle = item.fontColor
const _content = item.type == 'zm' ? '智能字幕' : item.content
// this.ctx.strokeText(item.content, item.left, item.top)
if (item.align == 'center') {
this.ctx.wrapText(showStroke, _content, item.left + item.width / 2, item.top, item.width, item.fontSize)
}
else if (item.align == 'right') {
this.ctx.wrapText(showStroke, _content, item.left + item.width, item.top, item.width, item.fontSize)
}
else {
this.ctx.wrapText(showStroke, _content, item.left, item.top, item.width, item.fontSize)
}
this.ctx.restore()
// 锁定
if(!item.lock) {
// 绘制模拟canvas
const _color = this.getRandomColor()
this._tcList.push({
id: item.id,
color: _color
})
this._ctx.save()
this._ctx.fillStyle = _color
this._ctx.fillRect(item.left, item.top, item.width, item.height)
this._ctx.restore()
}
}
// 绘制编辑框
if (item.active && !item.lock) {
activeItem = item
}
}
if (activeItem) {
this.drawEditBox(activeItem)
}
},
// 绘制图层
async drawItems() {
cancelAnimationFrame(this.requestAnimationFrameId)
if(this.previewStatus === -1) {
this.drawSpPartItem()
} else {
this.drawPreview()
}
this.requestAnimationFrameId = requestAnimationFrame(this.drawItems)
},
// 绘制编辑边框
drawEditBox(item) {
this.ctx.save()
const r = 10 // 圆半径
const w = 20 // 矩形宽度
// 绘制矩形
this.ctx.lineWidth = 5
this.ctx.strokeStyle = '#779BF1'
this.ctx.strokeRect(item.left, item.top, item.width, item.height)
// 阴影
this.ctx.shadowBlur = 5;
this.ctx.shadowColor = "#779BF1";
let _color
/**
*
* 拉伸按钮
*
*/
if(item.type === 'zm') {
// 中上
this.ctx.fillStyle = 'white'
this.ctx.fillRect(item.left + item.width/2 - w/2, item.top - w/2, w, w)
// 绘制模拟canvas
_color = this.getRandomColor()
this._tcList.push({
type: 'lh-btn',
cursor: 'ns-resize', // 上下
id: item.id,
color: _color
})
this._ctx.fillStyle = _color
this._ctx.fillRect(item.left + item.width/2 - w/2, item.top - w/2, w, w)
// 中下
this.ctx.fillStyle = 'white'
this.ctx.fillRect(item.left + item.width/2 - w/2, item.top + item.height - w/2, w, w)
// 绘制模拟canvas
_color = this.getRandomColor()
this._tcList.push({
type: 'lh-btn',
cursor: 'ns-resize', // 上下
id: item.id,
color: _color
})
this._ctx.fillStyle = _color
this._ctx.fillRect(item.left + item.width/2 - w/2, item.top + item.height - w/2, w, w)
// 中左
this.ctx.fillStyle = 'white'
this.ctx.fillRect(item.left - w/2, item.top + item.height/2 - w/2, w, w)
// 绘制模拟canvas
_color = this.getRandomColor()
this._tcList.push({
type: 'lw-btn',
cursor: 'ew-resize', // 左右
id: item.id,
color: _color
})
this._ctx.fillStyle = _color
this._ctx.fillRect(item.left - w/2, item.top + item.height/2 - w/2, w, w)
// 中右
this.ctx.fillStyle = 'white'
this.ctx.fillRect(item.left + item.width - w/2, item.top + item.height/2 - w/2, w, w)
// 绘制模拟canvas
_color = this.getRandomColor()
this._tcList.push({
type: 'lw-btn',
cursor: 'ew-resize', // 左右
id: item.id,
color: _color
})
this._ctx.fillStyle = _color
this._ctx.fillRect(item.left + item.width - w/2, item.top + item.height/2 - w/2, w, w)
}
/**
*
* 缩放按钮
*
* */
// 左上
this.ctx.beginPath()
this.ctx.arc(item.left, item.top, r, 0, 2 * Math.PI)
this.ctx.stroke()
this.ctx.fillStyle = 'white'
this.ctx.fill()
// 绘制模拟canvas
_color = this.getRandomColor()
this._tcList.push({
type: 's-btn',
cursor: 'nwse-resize', // 左上角
id: item.id,
color: _color
})
this._ctx.beginPath()
this._ctx.arc(item.left, item.top, r, 0, 2 * Math.PI)
this._ctx.stroke()
this._ctx.fillStyle = _color
this._ctx.fill()
// 右上
this.ctx.beginPath()
this.ctx.arc(item.left + item.width, item.top, r, 0, 2 * Math.PI)
this.ctx.stroke()
this.ctx.fillStyle = 'white'
this.ctx.fill()
// 绘制模拟canvas
_color = this.getRandomColor()
this._tcList.push({
type: 's-btn',
cursor: 'nesw-resize', // 右上角
id: item.id,
color: _color
})
this._ctx.beginPath()
this._ctx.arc(item.left + item.width, item.top, r, 0, 2 * Math.PI)
this._ctx.stroke()
this._ctx.fillStyle = _color
this._ctx.fill()
// 左下
this.ctx.beginPath()
this.ctx.arc(item.left, item.top + item.height, r, 0, 2 * Math.PI)
this.ctx.stroke()
this.ctx.fillStyle = 'white'
this.ctx.fill()
// 绘制模拟canvas
_color = this.getRandomColor()
this._tcList.push({
type: 's-btn',
cursor: 'nesw-resize', // 左下角
id: item.id,
color: _color
})
this._ctx.beginPath()
this._ctx.arc(item.left, item.top + item.height, r, 0, 2 * Math.PI)
this._ctx.stroke()
this._ctx.fillStyle = _color
this._ctx.fill()
// 右下
this.ctx.beginPath()
this.ctx.arc(item.left + item.width, item.top + item.height, r, 0, 2 * Math.PI)
this.ctx.stroke()
this.ctx.fillStyle = 'white'
this.ctx.fill()
// 绘制模拟canvas
_color = this.getRandomColor()
this._tcList.push({
type: 's-btn',
cursor: 'nwse-resize', // 右下角
id: item.id,
color: _color
})
this._ctx.beginPath()
this._ctx.arc(item.left + item.width, item.top + item.height, r, 0, 2 * Math.PI)
this._ctx.stroke()
this._ctx.fillStyle = _color
this._ctx.fill()
this.ctx.restore()
},
// 鼠标开始点击
wrapStart(e, _isRightClick = false) {
// 右键点击
if(_isRightClick) {
console.log('右键点击')
this.mousePos = {
x: e.clientX,
y: e.clientY
}
this.showRmenu = true
}
// 判断画板上的点击区域
const mousePos = {
x: (e.pageX - this.toucheWrap.left) * this.sDpi,
y: (e.pageY - this.toucheWrap.top) * this.sDpi
}
const pixel = this._ctx.getImageData(mousePos.x, mousePos.y, 1, 1).data
const color = `rgb(${pixel[0]},${pixel[1]},${pixel[2]})`
for (let i = 0; i < this._tcList.length; i++) {
if (this._tcList[i].color == color) {
const id = this._tcList[i].id
// 缩放按钮
if (this._tcList[i].type == 's-btn') {
this.oTouchStart(e, id)
}
// 拉伸(高度)按钮
else if(this._tcList[i].type == 'lh-btn') {
this.oLwhStart(e, id, 'h')
}
// 拉伸(宽度)按钮
else if(this._tcList[i].type == 'lw-btn') {
this.oLwhStart(e, id, 'w')
}
else {
// 点击图层
this.wraptouchStart(e, id, _isRightClick)
}
break
}
}
this.drag = true;
},
// 鼠标放开
wrapUp(e) {
// console.log("wrapUp");
this.drag = false;
this.oTouchUp();
this.xMLine = false;
this.yMLine = false;
},
// 鼠标取消
oTouchUp(e, id) {
if (this.items && this.items[this.index]) {
// console.log("oTouchUp");
this.items[this.index].lMoveabled = false;
this.items[this.index].sMoveabled = false;
this.items[this.index].moveabled = false;
}
},
// 点击图层
wraptouchStart(e, id, _isRightClick) {
console.log("点击图层", e, e.target.focus);
// 循环图片数组获取点击的图片信息
for (let i = 0; i < this.items.length; i++) {
this.items[i].active = false;
this.items[i].moveabled = false;
this.items[i].sMoveabled = false;
if (id == this.items[i].id) {
// 不是编辑封面的时候
if(!this.isCoverEdit) {
this.selectSpPartIndex = this.spPartIndex
this.selectItemId = id
}
this.canvas.style.cursor = 'move'
this.index = i
this.items[this.index].active = true
this.items[this.index].moveabled = true
if (this.items[this.index].isEdit) {
e.stopPropagation()
} else {
e.preventDefault()
}
}
}
let editType = "";
if (this.items[this.index].type == "bg") {
editType = "bg";
} else if (this.items[this.index].type == "ai") {
editType = "ai";
} else if (this.items[this.index].type == "tt") {
editType = "tt";
} else if (this.items[this.index].type == "bt") {
editType = "bt";
} else if (this.items[this.index].type == "zm") {
editType = "zm";
}
if (this.isCoverEdit) {
this.fmItems = this.items;
} else {
this.spPart[this.spPartIndex] = this.items;
}
this.editType = editType;
this.isInitEdit = false;
// 获取点击的坐标值
this.items[this.index].lx = e.pageX;
this.items[this.index].ly = e.pageY;
this.items = JSON.parse(JSON.stringify(this.items));
},
// 鼠标移动
wrapMove(e) {
if (!this.canvas || !this.items[this.index]) {
return
}
// 判断画板上的点击区域
const mousePos = {
x: (e.pageX - this.toucheWrap.left) * this.sDpi,
y: (e.pageY - this.toucheWrap.top) * this.sDpi
}
const pixel = this._ctx.getImageData(mousePos.x, mousePos.y, 1, 1)?.data
const color = `rgb(${pixel[0]},${pixel[1]},${pixel[2]})`
if (!this.items[this.index]?.sMoveabled && !this.items[this.index]?.moveabled && !this.items[this.index]?.lMoveabled) {
this.canvas.style.cursor = 'auto'
for (let i = 0; i < this._tcList.length; i++) {
if (this._tcList[i].color == color) {
const id = this._tcList[i].id
// 编辑按钮
if (['s-btn', 'lh-btn', 'lw-btn'].includes(this._tcList[i].type)) {
this.canvas.style.cursor = this._tcList[i].cursor
}
else {
// 循环图片数组获取点击的图片信息
for (let j = 0; j < this.items.length; j++) {
if (this.items[j].id == id && this.items[j].active) {
if(this.items[j].type !== 'zm') {
this.canvas.style.cursor = 'move'
} else {
this.canvas.style.cursor = 'auto'
}
break
}
}
}
break
}
}
}
if (this.drag && this.items[this.index].type != "bg") {
if (this.items[this.index].active) {
// 缩放
if (this.items[this.index].sMoveabled) {
console.log("wrapMove-sMoveabled");
this.oTouchMove(e);
}
// 移动
else if (this.items[this.index].moveabled) {
if(this.items[this.index].type !== 'zm') {
console.log("wrapMove-moveabled")
this.wraptouchMove(e)
}
}
// 拉伸
else if (this.items[this.index].lMoveabled) {
console.log("wrapMove-lMoveabled");
this.oLwhMove(
e,
this.items[this.index].id,
this.items[this.index].lMoveType
);
}
}
}
},
// 拖动图层
wraptouchMove(e) {
let { items, index } = this;
if (!items[index].moveabled) {
return;
}
console.log("拖动图层", e);
items[index]._lx = e.pageX;
items[index]._ly = e.pageY;
let _getXDistancs = null
let _getYDistancs = null
if (Math.round(items[index].x) == this.realResolutionPower[0] / 2) {
this.xMLine = true;
_getXDistancs = this.getDistancs(
items[index].lx,
items[index].ly,
items[index]._lx,
items[index]._ly
)
} else {
this.xMLine = false;
}
if (Math.round(items[index].y) == this.realResolutionPower[1] / 2) {
this.yMLine = true;
_getYDistancs = this.getDistancs(
items[index].lx,
items[index].ly,
items[index]._lx,
items[index]._ly
)
} else {
this.yMLine = false;
}
if((_getXDistancs != null && _getXDistancs < 20) || (_getYDistancs != null && _getYDistancs < 20)){
return
}
items[index].left += (items[index]._lx - items[index].lx) * this.sDpi;
items[index].top += (items[index]._ly - items[index].ly) * this.sDpi;
items[index].x += (items[index]._lx - items[index].lx) * this.sDpi;
items[index].y += (items[index]._ly - items[index].ly) * this.sDpi;
items[index].lx = e.pageX;
items[index].ly = e.pageY;
this.items = JSON.parse(JSON.stringify(items))
if (this.isCoverEdit) {
this.fmItems = this.items;
} else {
this.spPart[this.spPartIndex] = this.items
this.spPart = JSON.parse(JSON.stringify(this.spPart))
}
},
// 点击伸缩图标
oTouchStart(e, id) {
console.log("点击伸缩图标", e);
// 找到点击的那个图片对象,并记录
for (let i = 0; i < this.items.length; i++) {
this.items[i].active = false;
this.items[i].moveabled = false;
this.items[i].sMoveabled = false;
if (id == this.items[i].id) {
this.index = i;
this.items[i].active = true;
this.items[i].sMoveabled = true;
}
}
// 获取作为移动前的坐标
this.items[this.index].tx = (e.pageX - this.toucheWrap.left) * this.sDpi;
this.items[this.index].ty = (e.pageY - this.toucheWrap.top) * this.sDpi;
// 获取图片半径
this.items[this.index].r = this.getDistancs(
this.items[this.index].x,
this.items[this.index].y,
this.items[this.index].tx,
this.items[this.index].ty
);
},
// 移动伸缩图标
oTouchMove(e) {
console.log("移动伸缩图标", e);
let { items, index, toucheWrap, sDpi } = this;
if (!items[index].sMoveabled) {
return;
}
// 记录移动后的位置
items[index]._tx = (e.pageX - toucheWrap.left) * this.sDpi;
items[index]._ty = (e.pageY - toucheWrap.top) * this.sDpi;
// 移动的点到圆心的距离
items[index].disPtoO = this.getDistancs(
items[index].x,
items[index].y,
items[index]._tx,
items[index]._ty
);
let _s = items[index].disPtoO / items[index].r
// 记录新旧数据
let _oiW = items[index].width
let _niW = _oiW * _s
let _oiS = _niW / _oiW
let _oiH = items[index].height
let _niH = _oiS * _oiH
// 使用缩放
// items[index].scale = items[index].disPtoO / items[index].r;
// 不使用缩放
if (items[index].type === "bt" || items[index].type === "zm") {
let _newFontSize = items[index].fontSize * _s
let maxFontSize = items[index].type == 'zm' ? 46 : 100;
let minFontSize = 12
if(_newFontSize < minFontSize) {
return
} else if(_newFontSize > maxFontSize) {
return
}
let _txt = TextNode(
items[index].type === 'zm' ? '智能字幕' : items[index].content,
`${_newFontSize}px ${items[index].fontFamily}`
)
_niW = _txt.width
_niH = _txt.height
items[index].fontSize = _newFontSize;
}
if(items[index].type === 'zm') {
// 距离底部间距
let _distance = this.realResolutionPower[1] * 0.1
items[index].height = _niH
// 中心坐标
items[index].y = this.realResolutionPower[1] - _distance - (items[index].height/2)
items[index].top = items[index].y - items[index].height / 2
} else {
items[index].width = _niW
items[index].height = _niH
items[index].top = items[index].y - items[index].height / 2
items[index].left = items[index].x - items[index].width / 2
}
// 获取图片半径
items[index].r = items[index].disPtoO;
this.items = JSON.parse(JSON.stringify(items));
if (this.isCoverEdit) {
this.fmItems = this.items;
} else {
this.spPart[this.spPartIndex] = this.items
this.spPart = JSON.parse(JSON.stringify(this.spPart))
}
},
// 点击文字拉宽高图标
oLwhStart(e, id, _type) {
// 找到点击的那个图片对象,并记录
for (let i = 0; i < this.items.length; i++) {
this.items[i].active = false;
this.items[i].moveabled = false;
this.items[i].sMoveabled = false;
this.items[i].lMoveabled = false;
if (id == this.items[i].id) {
this.index = i;
this.items[i].active = true;
this.items[i].lMoveabled = true;
this.items[i].lMoveType = _type;
}
}
// 获取作为移动前的坐标
this.items[this.index].tx = (e.pageX - this.toucheWrap.left) * this.sDpi;
this.items[this.index].ty = (e.pageY - this.toucheWrap.top) * this.sDpi;
// 获取触摸点到圆心距离
this.items[this.index].r = this.getDistancs(
this.items[this.index].x,
this.items[this.index].y,
this.items[this.index].tx,
this.items[this.index].ty
);
},
// 移动文字拉宽高图标
oLwhMove(e, id, _type) {
console.log('移动文字拉宽高图标', e)
let { items, index, toucheWrap } = this;
if (!items[index].lMoveabled) {
return;
}
// 记录移动后的位置
items[index]._tx = (e.pageX - toucheWrap.left) * this.sDpi
items[index]._ty = (e.pageY - toucheWrap.top) * this.sDpi
// 移动的点到圆心的距离
items[index].disPtoO = this.getDistancs(
items[index].x,
items[index].y,
items[index]._tx,
items[index]._ty
);
let _s = items[index].disPtoO / items[index].r;
// 拉宽度
if (_type === "w") {
let _sW = _s * items[index].width
if(['zm', 'bt'].includes(items[index].type)){
let _txt = TextNode(
items[index].type === 'zm' ? '智能字幕' : items[index].content,
`${items[index].fontSize}px ${items[index].fontFamily}`,
'',
items[index].height+'px'
)
if(_txt.width >= _sW) {
return
}
}
items[index].width = _sW
items[index].left = items[index].x - items[index].width / 2;
}
// 拉高度
else {
let _sH = _s * items[index].height
if(['zm', 'bt'].includes(items[index].type)){
let _txt = TextNode(
items[index].type === 'zm' ? '智能字幕' : items[index].content,
`${items[index].fontSize}px ${items[index].fontFamily}`,
items[index].width+'px',
''
)
if(_txt.height >= _sH) {
return
}
}
items[index].height = _sH
items[index].top = items[index].y - items[index].height / 2;
}
// 获取触摸点到圆心距离
items[index].r = items[index].disPtoO;
this.items = JSON.parse(JSON.stringify(items))
if (this.isCoverEdit) {
this.fmItems = this.items
} else {
this.spPart[this.spPartIndex] = this.items
this.spPart = JSON.parse(JSON.stringify(this.spPart))
}
},
// 点击旋转图标
oScaleStart(e, id) {
// 找到点击的那个图片对象,并记录
for (let i = 0; i < this.items.length; i++) {
this.items[i].active = false;
if (id == this.items[i].id) {
this.index = i;
this.items[this.index].active = true;
}
}
// 获取作为移动前角度的坐标
this.items[this.index].tx = e.layerX - this.toucheWrap.left;
this.items[this.index].ty = e.layerY - this.toucheWrap.top;
// 移动前的角度
this.items[this.index].anglePre = this.countDeg(
this.items[this.index].x,
this.items[this.index].y,
this.items[this.index].tx,
this.items[this.index].ty
);
},
// 移动旋转图标
oScaleMove(e, id) {
console.log('移动旋转图标')
let { items, index } = this;
// 记录移动后的位置
items[index]._tx = e.layerX - this.toucheWrap.left;
items[index]._ty = e.layerY - this.toucheWrap.top;
// 移动的点到圆心的距离
items[index].disPtoO = this.getDistancs(
items[index].x,
items[index].y,
items[index]._tx,
items[index]._ty - 10
);
// 移动后位置的角度
items[index].angleNext = this.countDeg(
items[index].x,
items[index].y,
items[index]._tx,
items[index]._ty
);
// 角度差
items[index].new_rotate = items[index].angleNext - items[index].anglePre;
//叠加的角度差
items[index].rotate += items[index].new_rotate;
items[index].angle = items[index].type == "tt" ? items[index].rotate : 0; //赋值
//用过移动后的坐标赋值为移动前坐标
items[index].tx = e.layerX - this.toucheWrap.left;
items[index].ty = e.layerY - this.toucheWrap.top;
// 下次移动前的角度
items[index].anglePre = this.countDeg(
items[index].x,
items[index].y,
items[index].tx,
items[index].ty
);
this.items = items;
if (this.isCoverEdit) {
this.fmItems = items;
} else {
this.spPart[this.spPartIndex] = items;
}
},
getDistancs(cx, cy, pointer_x, pointer_y) {
var ox = pointer_x - cx;
var oy = pointer_y - cy;
return Math.sqrt((ox * ox) + (oy * oy));
},
/*
* 参数cx和cy为图片圆心坐标
* 参数pointer_x和pointer_y为手点击的坐标
* 返回值为手点击的坐标到圆心的角度
*/
countDeg(cx, cy, pointer_x, pointer_y) {
var ox = pointer_x - cx;
var oy = pointer_y - cy;
var to = Math.abs(ox / oy);
var angle = (Math.atan(to) / (2 * Math.PI)) * 360;
// 相对在左上角,第四象限,js中坐标系是从左上角开始的,这里的象限是正常坐标系
if (ox < 0 && oy < 0) {
angle = -angle;
}
// 左下角,3象限
else if (ox <= 0 && oy >= 0) {
angle = -(180 - angle);
}
// 右上角,1象限
else if (ox > 0 && oy < 0) {
angle = angle;
}
// 右下角,2象限
else if (ox > 0 && oy > 0) {
angle = 180 - angle;
}
return angle;
}
...