优化文字移动性能

This commit is contained in:
0JARVIS0 2019-11-18 14:08:07 +08:00
parent d85be378c4
commit b613dd610b
2 changed files with 200 additions and 111 deletions

View File

@ -9,17 +9,23 @@ export default class Painter {
this.globalHeight = {};
}
paint(callback) {
isMoving = false
movingCache = {}
paint(callback, isMoving, movingCache) {
this.style = {
width: this.data.width.toPx(),
height: this.data.height.toPx(),
};
if (isMoving) {
this.isMoving = true
this.movingCache = movingCache
}
this._background();
for (const view of this.data.views) {
this._drawAbsolute(view);
}
this.ctx.draw(false, () => {
callback && callback();
callback && callback(this.callbackInfo);
});
}
@ -420,6 +426,7 @@ export default class Painter {
this._doBorder(view, width, height);
}
callbackInfo = {}
_fillAbsText(view) {
if (!view.text) {
return;
@ -434,7 +441,32 @@ export default class Painter {
height,
extra,
} = this._preProcess(view, view.css.background && view.css.borderRadius);
if (this.isMoving && JSON.stringify(this.movingCache) !== JSON.stringify({})) {
this.globalWidth[view.id] = this.movingCache.globalWidth
this.ctx.setTextAlign(view.css.textAlign ? view.css.textAlign : 'left');
for (const i of this.movingCache.lineArray) {
const {
measuredWith,
text,
x,
y,
} = i
if (view.css.textStyle === 'stroke') {
this.ctx.strokeText(text, x, y, measuredWith);
} else {
this.ctx.fillText(text, x, y, measuredWith);
}
const fontSize = view.css.fontSize.toPx();
if (view.css.textDecoration) {
this.ctx.beginPath();
this.ctx.moveTo(...this.callbackInfo.textDecoration.moveTo);
this.ctx.lineTo(...this.callbackInfo.textDecoration.lineTo);
this.ctx.closePath();
this.ctx.strokeStyle = view.css.color;
this.ctx.stroke();
}
}
} else {
this.ctx.fillStyle = (view.css.color || 'black');
const {
lines,
@ -449,6 +481,11 @@ export default class Painter {
textWidth = this.ctx.measureText(textArray[i]).width > textWidth ? this.ctx.measureText(textArray[i]).width : textWidth;
}
this.globalWidth[view.id] = width ? (textWidth < width ? textWidth : width) : textWidth;
if (!this.isMoving) {
Object.assign(this.callbackInfo, {
globalWidth: this.globalWidth[view.id]
})
}
}
let lineIndex = 0;
for (let j = 0; j < textArray.length; ++j) {
@ -477,7 +514,7 @@ export default class Painter {
}
measuredWith = this.ctx.measureText(text).width;
}
start += text.length;
start += text.length
// 如果是最后一行了,发现还有未绘制完的内容,则加...
if (lineIndex === lines - 1 && (j < textArray.length - 1 || start < textArray[j].length)) {
while (this.ctx.measureText(`${text}...`).width > width) {
@ -516,19 +553,35 @@ export default class Painter {
if (/\bunderline\b/.test(view.css.textDecoration)) {
this.ctx.moveTo(x, y);
this.ctx.lineTo(x + measuredWith, y);
!this.isMoving && (this.callbackInfo.textDecoration = {
moveTo: [x, y],
lineTo: [x + measuredWith, y]
})
}
if (/\boverline\b/.test(view.css.textDecoration)) {
this.ctx.moveTo(x, y - fontSize);
this.ctx.lineTo(x + measuredWith, y - fontSize);
!this.isMoving && (this.callbackInfo.textDecoration = {
moveTo: [x, y - fontSize],
lineTo: [x + measuredWith, y - fontSize]
})
}
if (/\bline-through\b/.test(view.css.textDecoration)) {
this.ctx.moveTo(x, y - fontSize / 3);
this.ctx.lineTo(x + measuredWith, y - fontSize / 3);
!this.isMoving && (this.callbackInfo.textDecoration = {
moveTo: [x, y - fontSize / 3],
lineTo: [x + measuredWith, y - fontSize / 3]
})
}
this.ctx.closePath();
this.ctx.strokeStyle = view.css.color;
this.ctx.stroke();
}
if (!this.isMoving) {
this.callbackInfo.lineArray ? this.callbackInfo.lineArray.push({ text, x, y, measuredWith }) : this.callbackInfo.lineArray = [{ text, x, y, measuredWith }]
}
}
}
}
this.ctx.restore();

View File

@ -13,6 +13,7 @@ Component({
canvasHeightInPx: 0,
paintCount: 0,
currentPalette: {},
movingCache: {},
/**
* 组件的属性列表
*/
@ -22,7 +23,7 @@ Component({
},
palette: {
type: Object,
observer: function (newVal, oldVal) {
observer: function(newVal, oldVal) {
if (this.isNeedRefresh(newVal, oldVal)) {
this.paintCount = 0;
this.startPaint();
@ -31,7 +32,7 @@ Component({
},
dancePalette: {
type: Object,
observer: function (newVal, oldVal) {
observer: function(newVal, oldVal) {
if (!this.isEmpty(newVal)) {
this.initDancePalette(newVal);
}
@ -48,7 +49,7 @@ Component({
},
action: {
type: Object,
observer: function (newVal, oldVal) {
observer: function(newVal, oldVal) {
if (newVal) {
this.doAction(newVal)
}
@ -82,7 +83,7 @@ Component({
return true;
},
doAction(newVal) {
doAction(newVal, callback, isMoving) {
if (newVal && newVal.id && this.touchedView.id !== newVal.id) {
// 带 id 的动作给撤回时使用,不带 id表示对当前选中对象进行操作
const {
@ -118,17 +119,21 @@ Component({
const draw = {
width: this.currentPalette.width,
height: this.currentPalette.height,
views: [doView]
views: this.isEmpty(doView) ? [] : [doView]
}
const pen = new Pen(this.globalContext, draw);
pen.paint();
if (isMoving && this.currentPalette.views[0].type === 'text') {
pen.paint(callback, true, this.movingCache);
} else {
pen.paint(callback)
}
const {
rect
} = doView
const block = {
width: this.currentPalette.width,
height: this.currentPalette.height,
views: [{
views: this.isEmpty(this.touchedView) ? [] : [{
type: 'rect',
css: {
height: `${rect.bottom - rect.top}px`,
@ -151,6 +156,19 @@ Component({
}
}]
}
if (this.touchedView.type === 'text') {
block.views.push({
type: 'rect',
css: {
height: `${2 * ACTION_POINT_RADIUS}px`,
width: `${2 * ACTION_POINT_RADIUS}px`,
borderRadius: `${ACTION_POINT_RADIUS}px`,
color: '#0000ff',
left: `${rect.left - ACTION_POINT_RADIUS}px`,
top: `${rect.top - ACTION_POINT_RADIUS}px`
}
})
}
const topBlock = new Pen(this.frontContext, block)
topBlock.paint();
},
@ -173,34 +191,48 @@ Component({
)
},
isDelete(x, y, rect) {
return (x > rect.left - ACTION_POINT_RADIUS &&
y > rect.top - ACTION_POINT_RADIUS &&
x < rect.left + ACTION_POINT_RADIUS &&
y < rect.top + ACTION_POINT_RADIUS)
},
touchedView: {},
findedIndex: -1,
onClick(event) {
onClick() {
const x = this.startX
const y = this.startY
const totalLayerCount = this.currentPalette.views.length
const hasTouchedView = this.findedIndex !== -1
this.touchedView = {}
let canBeTouched = []
let isDelete = false
for (let i = totalLayerCount - 1; i >= 0; i--) {
const view = this.currentPalette.views[i]
const {
rect
} = view
if (this.inArea(x, y, rect, hasTouchedView)) {
if (this.touchedView && this.touchedView.id &&
this.touchedView.id === view.id &&
this.isDelete(x, y, rect)) {
canBeTouched.length = 0
this.currentPalette.views.splice(i, 1)
isDelete = true
break
}
if (this.inArea(x, y, rect, !this.isEmpty(this.touchedView))) {
canBeTouched.push({
view,
index: i
})
}
}
this.touchedView = {}
if (canBeTouched.length === 0) {
this.findedIndex = -1
} else {
let i = 0
const touchAble = canBeTouched.filter(item => Boolean(item.view.id))
if (touchAble.length === 0) {
this.touchedView = {}
this.findedIndex = canBeTouched[0].index
} else {
for (i = 0; i < touchAble.length; i++) {
@ -226,7 +258,6 @@ Component({
}
if (this.findedIndex < 0 || (this.touchedView && !this.touchedView.id)) {
// 证明点击了背景 或无法移动的view
this.touchedView = {}
const block = {
width: this.currentPalette.width,
height: this.currentPalette.height,
@ -234,7 +265,9 @@ Component({
}
const topBlock = new Pen(this.frontContext, block)
topBlock.paint();
if (this.findedIndex < 0) {
if (isDelete) {
this.doAction()
} else if (this.findedIndex < 0) {
this.triggerEvent('touchStart', {})
}
this.findedIndex = -1
@ -260,11 +293,15 @@ Component({
}
if (this.prevFindedIndex < this.findedIndex) {
new Pen(this.bottomContext, bottomDraw).paint();
this.doAction()
this.doAction(null, (callbackInfo) => {
this.movingCache = callbackInfo
})
new Pen(this.topContext, topDraw).paint();
} else {
new Pen(this.topContext, topDraw).paint();
this.doAction()
this.doAction(null, (callbackInfo) => {
this.movingCache = callbackInfo
})
new Pen(this.bottomContext, bottomDraw).paint();
}
this.prevFindedIndex = this.findedIndex
@ -290,6 +327,7 @@ Component({
} = this.touchedView
if (rect.right - ACTION_POINT_RADIUS < x && x < rect.right + ACTION_POINT_RADIUS && rect.bottom - ACTION_POINT_RADIUS < y && y < rect.bottom + ACTION_POINT_RADIUS) {
this.isScale = true
this.movingCache = {}
this.startH = rect.bottom - rect.top
this.startW = rect.right - rect.left
} else {
@ -357,7 +395,11 @@ Component({
}
this.doAction({
css
})
}, (callbackInfo) => {
if (this.isScale) {
this.movingCache = callbackInfo
}
}, !this.isScale)
},
initScreenK() {
@ -378,12 +420,6 @@ Component({
initDancePalette() {
this.initScreenK();
this.hasIdViews = []
this.properties.dancePalette && this.properties.dancePalette.views.map(view => {
if (view.id) {
this.hasIdViews.push(view)
}
})
this.downloadImages(this.properties.dancePalette).then((palette) => {
this.currentPalette = palette
@ -507,10 +543,10 @@ Component({
setTimeout(() => {
wx.canvasToTempFilePath({
canvasId: 'photo',
success: function (res) {
success: function(res) {
that.getImageInfo(res.tempFilePath);
},
fail: function (error) {
fail: function(error) {
console.error(`canvasToTempFilePath failed, ${JSON.stringify(error)}`);
that.triggerEvent('imgErr', {
error: error