6.18
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
let penType = 'drawPen';
|
||||
Page({
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
scale: 1,
|
||||
imageList: [],
|
||||
showBars: false,
|
||||
selectSize: wx.getStorageSync('selectSize') || 5,
|
||||
selectColor: wx.getStorageSync('selectColor') || '#FFFFFF',
|
||||
colors: ["#FFFFFF", "#000000", "#ff0000", "#ffff00", "#00CC00", "#99CCFF", "#0000ff", "#ff00ff"],
|
||||
},
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad(options) {
|
||||
this.setData({
|
||||
cover: options["cover"] || "https://www4.bing.com//th?id=OHR.BaobabAvenue_ZH-CN5217451344_1920x1080.jpg&rf=LaDigue_1920x1080.jpg&pid=hp"
|
||||
})
|
||||
this.initCanvas();
|
||||
},
|
||||
// 页面卸载 把字号选择的颜色和透明度保存
|
||||
onUnload() {
|
||||
const This = this.data;
|
||||
penType = 'drawPen';
|
||||
wx.setStorageSync('selectSize', This.selectSize);
|
||||
wx.setStorageSync('selectColor', This.selectColor);
|
||||
},
|
||||
colorChange(e) {
|
||||
const color = e.currentTarget.dataset.color;
|
||||
this.setData({
|
||||
selectColor: color
|
||||
})
|
||||
penType = 'drawPen';
|
||||
},
|
||||
sizeHandler(e) {
|
||||
const size = e.detail.value;
|
||||
this.setData({
|
||||
selectSize: size
|
||||
})
|
||||
},
|
||||
// 使用橡皮檫
|
||||
rubberHandler() {
|
||||
penType = 'clearPen';
|
||||
this.setData({
|
||||
selectColor: ""
|
||||
})
|
||||
},
|
||||
//初始化画布
|
||||
initCanvas() {
|
||||
const This = this.data;
|
||||
const query = wx.createSelectorQuery("#myCanvas");
|
||||
query.select('#myCanvas').fields({
|
||||
node: true,
|
||||
size: true,
|
||||
context: true
|
||||
}).exec(res => {
|
||||
const canvas = res[0].node;
|
||||
const context = canvas.getContext('2d');
|
||||
// 获取设备像素比
|
||||
const dpr = wx.getSystemInfoSync().pixelRatio;
|
||||
const width = res[0].width * dpr;
|
||||
const height = res[0].height * dpr;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
// 填充背景颜色
|
||||
context.fillStyle = "transparent";
|
||||
context.fillRect(0, 0, width, height);
|
||||
// 缩放
|
||||
context.scale(dpr, dpr);
|
||||
// 设置默认属性
|
||||
context.strokeStyle = This.selectColor;
|
||||
context.lineWidth = This.selectSize;
|
||||
this.setData({
|
||||
canvasElement: canvas,
|
||||
canvasContext: context,
|
||||
})
|
||||
})
|
||||
},
|
||||
// 开始
|
||||
startTouchClick(e) {
|
||||
var that = this;
|
||||
const x = e.touches[0].x;
|
||||
const y = e.touches[0].y;
|
||||
that.setData({
|
||||
oldPosition: {
|
||||
x: x,
|
||||
y: y
|
||||
},
|
||||
}, () => {
|
||||
that.setData({
|
||||
isDraw: true,
|
||||
})
|
||||
})
|
||||
},
|
||||
// 移动
|
||||
moveClick(e) {
|
||||
if (this.data.isDraw) {
|
||||
let positionItem = e.touches[0]
|
||||
if (this.data.canvasContext) {
|
||||
this.drawCanvas(positionItem, true)
|
||||
} else {
|
||||
this.initCanvas(() => {
|
||||
this.drawCanvas(positionItem, true)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
// 描绘canvas
|
||||
drawCanvas(position) {
|
||||
const ctx = this.data.canvasContext;
|
||||
const size = this.data.selectSize;
|
||||
const color = this.data.selectColor;
|
||||
const This = this.data;
|
||||
if (ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = size;
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineCap = 'round';
|
||||
if (penType == 'clearPen') {
|
||||
const radius = size + 1;
|
||||
ctx.clearRect(position.x - (radius / 2), position.y - (radius / 2), radius, radius);
|
||||
} else {
|
||||
ctx.moveTo(This.oldPosition.x, This.oldPosition.y);
|
||||
ctx.lineTo(position.x, position.y);
|
||||
ctx.stroke()
|
||||
};
|
||||
ctx.closePath();
|
||||
this.setData({
|
||||
oldPosition: {
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
//触摸结束
|
||||
endTouchClick(e) {
|
||||
this.setData({
|
||||
isDraw: false
|
||||
})
|
||||
this.saveImage();
|
||||
},
|
||||
//误触事件
|
||||
errorClick(e) {
|
||||
console.log("误触事件:", e);
|
||||
},
|
||||
// 是否展示 操作栏
|
||||
showBarsHandler() {
|
||||
this.setData({
|
||||
showBars: !this.data.showBars
|
||||
})
|
||||
},
|
||||
hideBarsHandler() {
|
||||
this.setData({
|
||||
showBars: false
|
||||
})
|
||||
},
|
||||
// 回退一步 || 重绘
|
||||
restore() {
|
||||
// 实际上的回退就是取存储的最后一张图片 渲染出来
|
||||
// 所以会有抖动 暂未想到其他方案解决
|
||||
const ctx = this.data.canvasContext;
|
||||
const canvas = this.data.canvasElement;
|
||||
const dpr = wx.getSystemInfoSync().pixelRatio;
|
||||
let imgs = this.data.imageList;
|
||||
if (!imgs || imgs.length == 0) return false;
|
||||
if (imgs.length == 1) return this.clearRect();
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
// -2 是因为当前的也储存了
|
||||
const cover = imgs[imgs.length - 2];
|
||||
imgs.splice(imgs.length - 1, 1);
|
||||
let bg = canvas.createImage();
|
||||
bg.src = cover;
|
||||
bg.onload = () => {
|
||||
// 缩放【放大还原】
|
||||
ctx.scale(1 / dpr, 1 / dpr);
|
||||
ctx.drawImage(bg, 0, 0, canvas.width, canvas.height);
|
||||
// 再缩放
|
||||
ctx.scale(dpr, dpr);
|
||||
}
|
||||
},
|
||||
// 清空画布
|
||||
clearRect() {
|
||||
const ctx = this.data.canvasContext;
|
||||
const canvas = this.data.canvasElement;
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
this.setData({
|
||||
imageList: []
|
||||
})
|
||||
},
|
||||
// 保存图片
|
||||
saveImage() {
|
||||
const that = this;
|
||||
wx.canvasToTempFilePath({
|
||||
canvasId: 'myCanvas',
|
||||
canvas: this.data.canvasElement,
|
||||
success: function (res) {
|
||||
that.data.imageList.push(res.tempFilePath);
|
||||
},
|
||||
fail: function (err) {}
|
||||
})
|
||||
},
|
||||
// 图片预览 这边的思路是 首先将背景图片画上去 再将最后的涂鸦展示上去
|
||||
preview() {
|
||||
const that = this;
|
||||
wx.showLoading({
|
||||
title: '打包中...',
|
||||
})
|
||||
const images = that.data.imageList;
|
||||
if (!images && images.length == 0) return false;
|
||||
const img = images[images.length - 1];
|
||||
// 将背景图片画上去
|
||||
const ctx = this.data.canvasContext;
|
||||
const canvas = this.data.canvasElement;
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
const cover = this.data.cover;
|
||||
wx.getImageInfo({
|
||||
src: cover,
|
||||
success: e => {
|
||||
let realWidth = canvas.width;
|
||||
let realHeight = canvas.height;
|
||||
// 动态计算图片宽高
|
||||
if (e.width > e.height) {
|
||||
const ratio = canvas.height / e.height;
|
||||
realWidth = e.width * ratio;
|
||||
} else {
|
||||
const ratio = canvas.width / e.width;
|
||||
realHeight = e.height * ratio;
|
||||
}
|
||||
let bg = canvas.createImage();
|
||||
bg.src = cover;
|
||||
bg.onload = () => {
|
||||
const dpr = wx.getSystemInfoSync().pixelRatio;
|
||||
ctx.scale(1 / dpr, 1 / dpr);
|
||||
ctx.drawImage(bg, 0, (canvas.height - realHeight) / 2, realWidth, realHeight);
|
||||
let trajectory = canvas.createImage();
|
||||
trajectory.src = img;
|
||||
trajectory.onload = _ => {
|
||||
ctx.drawImage(trajectory, 0, 0, canvas.width, canvas.height);
|
||||
wx.canvasToTempFilePath({
|
||||
canvasId: 'myCanvas',
|
||||
canvas: that.data.canvasElement,
|
||||
success: function (res) {
|
||||
wx.previewImage({
|
||||
urls: [res.tempFilePath],
|
||||
showmenu: true,
|
||||
current: res.tempFilePath,
|
||||
complete: _ => {
|
||||
wx.hideLoading();
|
||||
ctx.scale(dpr, dpr);
|
||||
}
|
||||
})
|
||||
},
|
||||
fail: function (err) {}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "涂鸦",
|
||||
"navigationBarBackgroundColor": "#9cf",
|
||||
"navigationBarTextStyle": "white",
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<view style="height: 100vh;" class="flex_column" catch:tap="hideBarsHandler">
|
||||
<!-- 涂鸦区 -->
|
||||
<view style="flex: 1; position: relative;" catch:touchstart="hideBarsHandler">
|
||||
<image src="{{cover}}" mode="aspectFit" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: -1; width: 100%; height: 100%;" />
|
||||
<canvas style="width: 100%; height: 100%;;" id="myCanvas" canvas-id="myCanvas" type="2d" bindtouchstart="startTouchClick" bindtouchmove="moveClick" bindtouchend="endTouchClick" binderror="errorClick"></canvas>
|
||||
</view>
|
||||
<!-- 涂鸦工具区 -->
|
||||
<view style="padding: 30rpx 32rpx 50rpx;">
|
||||
<view class="space" style="padding-bottom: 20rpx; color: #FFF; font-size: 30rpx; line-height: 56rpx;">
|
||||
<view catch:tap="restore">回退</view>
|
||||
<view style="width: 30rpx;"></view>
|
||||
<view catch:tap="preview">预览</view>
|
||||
<view style="flex: 1;"></view>
|
||||
<view catch:tap="showBarsHandler">笔力</view>
|
||||
<view style="width: 30rpx;"></view>
|
||||
<view catch:tap="rubberHandler">橡皮擦</view>
|
||||
<view style="width: 30rpx;"></view>
|
||||
<view catch:tap="clearRect">清除</view>
|
||||
</view>
|
||||
<scroll-view scroll-x style="height: 90rpx;">
|
||||
<view style="white-space: nowrap;">
|
||||
<block wx:for="{{colors}}" wx:key="index">
|
||||
<view style="background-color: {{item}};" class="colorBtn {{selectColor == item && 'select'}}" catch:tap="colorChange" data-color="{{item}}"></view>
|
||||
</block>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bars {{showBars && 'show'}}" wx:if="{{showBars}}">
|
||||
<view class="space vertical_center">
|
||||
<view style="width: 136rpx;">字号:</view>
|
||||
<slider style="flex: 1;" value="{{selectSize}}" step="1" min="1" max="20" block-size="12" activeColor="#a88cf8" bindchange="sizeHandler" />
|
||||
<view style="width: 50rpx; text-align: right;">{{selectSize}}</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -0,0 +1,53 @@
|
||||
page {
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
padding-bottom: 0 !important;
|
||||
background-color: #242424 !important;
|
||||
}
|
||||
|
||||
.colorBtn {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 20rpx;
|
||||
display: inline-block;
|
||||
border: 6rpx solid #242424;
|
||||
}
|
||||
|
||||
.colorBtn.select {
|
||||
border: 6rpx solid #FFF;
|
||||
}
|
||||
|
||||
.bars {
|
||||
right: 1rem;
|
||||
width: 400rpx;
|
||||
padding: 20rpx;
|
||||
bottom: 7.5rem;
|
||||
color: #a88cf8;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
position: absolute;
|
||||
border-radius: 8rpx;
|
||||
background-color: #242424;
|
||||
box-shadow: 0 0 1.5rem 0 #FFFFFF20;
|
||||
}
|
||||
|
||||
slider {
|
||||
margin: 20rpx 20rpx 20rpx 0 !important;
|
||||
}
|
||||
|
||||
.flex_column {
|
||||
display: flex;
|
||||
flex-direction: column !important;
|
||||
}
|
||||
|
||||
.vertical_center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.space {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
Reference in New Issue
Block a user