PainterCore/painter.js

383 lines
10 KiB
JavaScript
Raw Normal View History

2018-07-05 15:27:12 +08:00
import Pen from './lib/pen';
import Downloader from './lib/downloader';
2018-07-10 18:24:28 +08:00
const util = require('./lib/util');
2018-07-05 15:27:12 +08:00
const downloader = new Downloader();
// 最大尝试的绘制次数
const MAX_PAINT_COUNT = 5;
Component({
canvasWidthInPx: 0,
canvasHeightInPx: 0,
paintCount: 0,
2019-11-13 10:56:24 +08:00
currentPalette: {},
globalContext: {},
hasIdViews: [],
2018-07-05 15:27:12 +08:00
/**
* 组件的属性列表
*/
properties: {
customStyle: {
type: String,
},
palette: {
type: Object,
observer: function (newVal, oldVal) {
if (this.isNeedRefresh(newVal, oldVal)) {
this.paintCount = 0;
this.startPaint();
}
},
},
2019-11-06 17:20:44 +08:00
widthPixels: {
type: Number,
value: 0
},
// 启用脏检查,默认 false
dirty: {
type: Boolean,
2018-08-17 12:24:44 +08:00
value: false,
},
2019-11-13 10:56:24 +08:00
actions: {
type: Object,
observer: function (newVal, oldVal) {
this.doAction(newVal)
},
}
2018-07-05 15:27:12 +08:00
},
data: {
picURL: '',
showCanvas: true,
painterStyle: '',
},
methods: {
/**
* 判断一个 object 是否为
* @param {object} object
*/
isEmpty(object) {
for (const i in object) {
return false;
}
return true;
},
isNeedRefresh(newVal, oldVal) {
if (!newVal || this.isEmpty(newVal) || (this.data.dirty && util.equal(newVal, oldVal))) {
2018-07-05 15:27:12 +08:00
return false;
}
return true;
},
2019-11-13 10:56:24 +08:00
doAction(newVal) {
2019-11-13 18:28:46 +08:00
if (newVal && newVal.css) {
if (Array.isArray(this.touchedView.css)) {
this.touchedView.css = [...this.touchedView.css, newVal.css]
} else {
this.touchedView.css = [this.touchedView.css, newVal.css]
2019-11-13 10:56:24 +08:00
}
2019-11-13 18:28:46 +08:00
}
const draw = {
width: this.currentPalette.width,
height: this.currentPalette.height,
views: [this.touchedView]
}
const pen = new Pen(this.globalContext, draw);
2019-11-13 10:56:24 +08:00
pen.paint();
},
startX: 0,
startY: 0,
touchedView: {},
onTouchStart(event) {
const {
x,
y
} = event.touches[0]
this.startX = x
this.startY = y
2019-11-13 18:28:46 +08:00
const totalLayerCount = this.currentPalette.views.length
let findedIndex = -1;
this.touchedView = {}
for (let i = totalLayerCount - 1; i >= 0; i--) {
const view = this.currentPalette.views[i]
2019-11-13 10:56:24 +08:00
if (x > view.rect.left && y > view.rect.top && x < view.rect.right && y < view.rect.bottom) {
if (view.id) {
this.touchedView = view
2019-11-13 18:28:46 +08:00
this.triggerEvent('touchStart', {
2019-11-13 10:56:24 +08:00
id: view.id,
2019-11-13 18:28:46 +08:00
css: view.css,
rect: view.rect
2019-11-13 10:56:24 +08:00
})
}
2019-11-13 18:28:46 +08:00
findedIndex = i;
2019-11-13 10:56:24 +08:00
break;
}
}
2019-11-13 18:28:46 +08:00
if (findedIndex < 0) {
// 证明点击了背景
this.triggerEvent('touchStart', {})
} else if (this.touchedView.id) {
const bottomLayers = this.currentPalette.views.slice(0, findedIndex)
const topLayers = this.currentPalette.views.slice(findedIndex + 1)
const bottomDraw = {
width: this.currentPalette.width,
height: this.currentPalette.height,
background: this.currentPalette.background,
views: bottomLayers
}
new Pen(wx.createCanvasContext('bottom', this), bottomDraw).paint();
const topDraw = {
width: this.currentPalette.width,
height: this.currentPalette.height,
views: topLayers
}
new Pen(wx.createCanvasContext('top', this), topDraw).paint();
this.doAction()
}
2019-11-13 10:56:24 +08:00
},
onTouchEnd() {
this.touchedView = {}
2019-11-13 18:28:46 +08:00
this.triggerEvent('touchEnd')
2019-11-13 10:56:24 +08:00
},
onTouchCancel() {
this.touchedView = {}
2019-11-13 18:28:46 +08:00
this.triggerEvent('touchCancel')
2019-11-13 10:56:24 +08:00
},
onTouchMove(event) {
if (!this.touchedView.id) {
return
}
const {
x,
y
} = event.touches[0]
const offsetX = x - this.startX
const offsetY = y - this.startY
this.startX = x
this.startY = y
const css = {
left: `${this.touchedView.rect.x + offsetX}px`,
top: `${this.touchedView.rect.y + offsetY}px`,
right: undefined,
bottom: undefined
}
this.doAction({
id: this.touchedView.id,
css
})
2019-11-13 18:28:46 +08:00
this.triggerEvent('touchMove',{
id: this.touchedView.id,
css
})
2019-11-13 10:56:24 +08:00
},
2018-07-05 15:27:12 +08:00
startPaint() {
if (this.isEmpty(this.properties.palette)) {
return;
}
if (!(getApp().systemInfo && getApp().systemInfo.screenWidth)) {
2018-07-05 15:27:12 +08:00
try {
getApp().systemInfo = wx.getSystemInfoSync();
2018-07-05 15:27:12 +08:00
} catch (e) {
2018-07-10 18:24:28 +08:00
const error = `Painter get system info failed, ${JSON.stringify(e)}`;
2019-11-13 10:56:24 +08:00
this.triggerEvent('imgErr', {
2019-11-06 17:20:44 +08:00
error: error
});
2018-07-10 18:24:28 +08:00
console.error(error);
return;
2018-07-05 15:27:12 +08:00
}
}
2019-11-06 17:20:44 +08:00
let screenK = getApp().systemInfo.screenWidth / 750;
setStringPrototype(screenK, 1);
2019-11-13 10:56:24 +08:00
2018-07-05 15:27:12 +08:00
this.downloadImages().then((palette) => {
2019-11-13 10:56:24 +08:00
this.currentPalette = palette
this.hasIdViews = []
palette.views && palette.views.map(view => {
if (view.id) {
this.hasIdViews.push(view)
}
})
2019-11-06 17:20:44 +08:00
const {
width,
height
} = palette;
2019-11-13 10:56:24 +08:00
2018-07-05 15:27:12 +08:00
if (!width || !height) {
console.error(`You should set width and height correctly for painter, width: ${width}, height: ${height}`);
return;
}
2019-11-06 17:20:44 +08:00
this.canvasWidthInPx = width.toPx();
if (this.properties.widthPixels) {
// 如果重新设置过像素宽度,则重新设置比例
setStringPrototype(screenK, this.properties.widthPixels / this.canvasWidthInPx)
this.canvasWidthInPx = this.properties.widthPixels
}
2019-11-13 10:56:24 +08:00
2019-11-06 17:20:44 +08:00
this.canvasHeightInPx = height.toPx();
2018-07-05 15:27:12 +08:00
this.setData({
2019-11-06 17:20:44 +08:00
painterStyle: `width:${this.canvasWidthInPx}px;height:${this.canvasHeightInPx}px;`,
2018-07-05 15:27:12 +08:00
});
2019-11-13 10:56:24 +08:00
this.globalContext = wx.createCanvasContext('k-canvas', this);
const pen = new Pen(this.globalContext, palette);
2018-07-05 15:27:12 +08:00
pen.paint(() => {
2018-07-18 18:26:58 +08:00
this.saveImgToLocal();
2018-07-05 15:27:12 +08:00
});
2018-07-10 18:24:28 +08:00
});
2018-07-05 15:27:12 +08:00
},
downloadImages() {
return new Promise((resolve, reject) => {
let preCount = 0;
let completeCount = 0;
const paletteCopy = JSON.parse(JSON.stringify(this.properties.palette));
2018-07-27 14:39:36 +08:00
if (paletteCopy.background) {
2018-07-10 18:24:28 +08:00
preCount++;
2018-07-05 15:27:12 +08:00
downloader.download(paletteCopy.background).then((path) => {
paletteCopy.background = path;
2018-07-10 18:24:28 +08:00
completeCount++;
2018-07-05 15:27:12 +08:00
if (preCount === completeCount) {
resolve(paletteCopy);
}
}, () => {
2018-07-10 18:24:28 +08:00
completeCount++;
2018-07-05 15:27:12 +08:00
if (preCount === completeCount) {
resolve(paletteCopy);
}
});
}
if (paletteCopy.views) {
for (const view of paletteCopy.views) {
2018-07-27 14:39:36 +08:00
if (view && view.type === 'image' && view.url) {
2018-07-10 18:24:28 +08:00
preCount++;
/* eslint-disable no-loop-func */
2018-07-05 15:27:12 +08:00
downloader.download(view.url).then((path) => {
view.url = path;
2018-07-27 14:39:36 +08:00
wx.getImageInfo({
src: view.url,
success: (res) => {
// 获得一下图片信息,供后续裁减使用
view.sWidth = res.width;
view.sHeight = res.height;
},
fail: (error) => {
2018-09-21 15:27:06 +08:00
// 如果图片坏了,则直接置空,防止坑爹的 canvas 画崩溃了
view.url = "";
console.error(`getImageInfo ${view.url} failed, ${JSON.stringify(error)}`);
2018-07-27 14:39:36 +08:00
},
complete: () => {
completeCount++;
if (preCount === completeCount) {
resolve(paletteCopy);
}
},
});
2018-07-05 15:27:12 +08:00
}, () => {
2018-07-10 18:24:28 +08:00
completeCount++;
2018-07-05 15:27:12 +08:00
if (preCount === completeCount) {
resolve(paletteCopy);
}
});
}
}
}
if (preCount === 0) {
resolve(paletteCopy);
}
2018-07-10 18:24:28 +08:00
});
2018-07-05 15:27:12 +08:00
},
2018-07-18 18:26:58 +08:00
saveImgToLocal() {
2018-07-05 15:27:12 +08:00
const that = this;
setTimeout(() => {
wx.canvasToTempFilePath({
canvasId: 'k-canvas',
success: function (res) {
2018-07-18 18:26:58 +08:00
that.getImageInfo(res.tempFilePath);
2018-07-05 15:27:12 +08:00
},
fail: function (error) {
console.error(`canvasToTempFilePath failed, ${JSON.stringify(error)}`);
2019-11-06 17:20:44 +08:00
that.triggerEvent('imgErr', {
error: error
});
2018-07-05 15:27:12 +08:00
},
}, this);
}, 300);
},
2018-07-18 18:26:58 +08:00
getImageInfo(filePath) {
const that = this;
wx.getImageInfo({
src: filePath,
success: (infoRes) => {
if (that.paintCount > MAX_PAINT_COUNT) {
const error = `The result is always fault, even we tried ${MAX_PAINT_COUNT} times`;
console.error(error);
2019-11-06 17:20:44 +08:00
that.triggerEvent('imgErr', {
error: error
});
2018-07-18 18:26:58 +08:00
return;
}
// 比例相符时才证明绘制成功,否则进行强制重绘制
if (Math.abs((infoRes.width * that.canvasHeightInPx - that.canvasWidthInPx * infoRes.height) / (infoRes.height * that.canvasHeightInPx)) < 0.01) {
2019-11-06 17:20:44 +08:00
that.triggerEvent('imgOK', {
path: filePath
});
2018-07-18 18:26:58 +08:00
} else {
that.startPaint();
}
that.paintCount++;
},
fail: (error) => {
console.error(`getImageInfo failed, ${JSON.stringify(error)}`);
2019-11-06 17:20:44 +08:00
that.triggerEvent('imgErr', {
error: error
});
2018-07-18 18:26:58 +08:00
},
});
},
2018-07-05 15:27:12 +08:00
},
});
2019-11-06 17:20:44 +08:00
function setStringPrototype(screenK, scale) {
2018-07-10 18:24:28 +08:00
/* eslint-disable no-extend-native */
/**
* 是否支持负数
* @param {Boolean} minus 是否支持负数
*/
String.prototype.toPx = function toPx(minus) {
let reg;
if (minus) {
reg = /^-?[0-9]+([.]{1}[0-9]+){0,1}(rpx|px)$/g;
} else {
reg = /^[0-9]+([.]{1}[0-9]+){0,1}(rpx|px)$/g;
}
2018-07-10 18:24:28 +08:00
const results = reg.exec(this);
if (!this || !results) {
console.error(`The size: ${this} is illegal`);
return 0;
}
const unit = results[2];
const value = parseFloat(this);
2018-07-05 15:27:12 +08:00
2018-07-10 18:24:28 +08:00
let res = 0;
if (unit === 'rpx') {
2019-11-06 17:20:44 +08:00
res = Math.round(value * screenK * (scale || 1));
2018-07-10 18:24:28 +08:00
} else if (unit === 'px') {
2019-11-06 17:20:44 +08:00
res = Math.round(value * (scale || 1));
2018-07-10 18:24:28 +08:00
}
return res;
};
2019-11-06 17:20:44 +08:00
}