


Use the small program canvas to write a simple picture application
Small program development tutorialThe column introduces the use of canvas to write a picture
Recommendation (free): Mini program development tutorial
##Application display
ScreenshotRequirements
Since it is a small application, I hope that the final product hasapplicable scenarios And it is a valuable
source of demandinspiration for this application requirement
In my previous work life, I often got # from my colleagues inadvertently. ##美photo
At this time we want to make this photo into an emoticon pack
Generally add a few captions to the picture
An interesting communication The tool (emoticon package) has completed the
Requirement analysis
Based on the dismantling of the above requirements
You can sort out the implementation of the application functions
- You can add text
- Text can be style adjusted
- and rotation and zoom In addition, we hope that we can also insert some stickers
- The stickers can be rotated and zoomed
- Users can export pictures to the album
- implementation
github warehouse
https://github.com/luosijie/f...If you like my project, please give me a star for encouragement Let’s take a look
This application is developed using mini programUsing framework: mpx
- Using technology: mini program canvas
- State Management
import { createStore } from '@mpxjs/core' const store = createStore({ state: { cavas: null, // cnavas实例 ctx: null, // canvas上下文实例 elements: [], // canvas元素 activeIndex: null, // 当前编辑中的元素索引 mode: 'background', // 当前编辑模式:background, text, sticker fontStyle: { // 文字默认样式 opacity: 1, fillStyle: '#000000', strokeStyle: '#000000' } }, mutations: { setCanvas (state, data) { state.canvas = data }, setCtx (state, data) { state.ctx = data }, setElements (state, data) { state.elements = data }, setMode (state, data) { state.mode = data }, setActiveIndex (state, data) { state.activeIndex = data }, setFontStyle (state, { key, data }) { state.fontStyle[key] = data }, // 添加文字 addText (state) { const size = 50 const string = '请输入文字' const text = { type: 'text', data: string, scale: 1, size, left: 100, top: 100, rotate: 0, opacity: state.fontStyle.opacity, fillStyle: state.fontStyle.fillStyle, strokeStyle: state.fontStyle.strokeStyle } state.elements.push(text) state.activeIndex = state.elements.length - 1 }, // 添加贴图 addSticker (state, data) { state.elements.push(data) state.activeIndex = state.elements.length - 1 }, // 删除当前选中 deleteActiveELement (state) { state.elements.splice(state.activeIndex, 1) state.activeIndex = null }, // 清空画布 clear (state) { state.elements = [] state.activeIndex = null } } }) export default storeCanvas Initialization
// 初始化画布 async initCanvas() { const query = this.createSelectorQuery() query .select('#canvas') .fields({ node: true, size: true }) .exec(async res => { const canvas = res[0].node const ctx = canvas.getContext('2d') store.commit('setCanvas', canvas) store.commit('setCtx', ctx) await this.loadImage('/images/icon-rotate.png').then(res => { this.image.rotate = res }) canvas.width = res[0].width * this.dpr canvas.height = res[0].height * this.dpr ctx.scale(this.dpr, this.dpr) this.drawGrid() }) }Draw Picture
/** * 绘制图片 * @param { Object } ele canvas元素 */ drawImage(ele) { this.ctx.save() const width = ele.width const height = ele.height const centerX = ele.left + ele.width / 2 const centerY = ele.top + ele.height / 2 this.ctx.translate(centerX, centerY) this.ctx.rotate(ele.rotate) this.ctx.drawImage(ele.data, ele.left - centerX, ele.top - centerY, width, height) this.ctx.restore() }Draw Text
/** * 绘制文字 * @param { Object } ele canvas元素 */ drawText(ele) { this.ctx.save() const width = ele.size * ele.data.length const height = ele.size const centerX = ele.left + width / 2 const centerY = ele.top + height / 2 this.ctx.translate(centerX, centerY) this.ctx.rotate(ele.rotate) this.ctx.font = `${ele.size}px bold sans-serif` this.ctx.globalAlpha = ele.opacity this.ctx.fillStyle = ele.fillStyle this.ctx.strokeStyle = ele.strokeStyle // this.ctx.lineWidth = 2 this.ctx.textBaseline = 'top' console.log('draw-text', ele) this.ctx.fillText(ele.data, ele.left - centerX, ele.top - centerY) this.ctx.strokeText(ele.data, ele.left - centerX, ele.top - centerY) this.ctx.restore() }Drawing control element
initController(ele) { const cs = this.convert2ControllerSize(ele) this.ctx.save() this.ctx.strokeStyle = '#eee' this.ctx.translate(cs.centerX, cs.centerY) this.ctx.rotate(cs.rotate) // 绘制虚线边框 this.ctx.setLineDash([10, 5], 5) this.ctx.strokeRect(cs.left - cs.centerX, cs.top - cs.centerY, cs.width, cs.height) // 绘制控制点-旋转 this.ctx.drawImage(this.image.rotate, cs.left + cs.width - 10 - cs.centerX, cs.top + cs.height - 10 - cs.centerY, 20, 20) this.ctx.restore() }Canvas rendering function
// 画布渲染函数 renderCanvas() { this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height) this.drawGrid() console.log('draw-background', this.background) if (this.background) this.drawImage(this.background) for (let i = 0; i <strong></strong>Event listening<p><strong></strong>Move</p><p></p><pre class="brush:php;toolbar:false">// 移动事件绑定函数 handleMove(e) { console.log('mouse-move', e) if (e.touches.length > 1) return const x = e.touches[0].x const y = e.touches[0].y const dx = this.startTouches[0].x - x const dy = this.startTouches[0].y - y const elements = this.elements.slice() elements[this.activeIndex || 0].left = this.startSelected.left - dx elements[this.activeIndex || 0].top = this.startSelected.top - dy store.commit('setElements', elements) }Rotate
// 旋转绑定函数 handleRotate(e) { console.log('handleRotate') const start = this.startTouches[0] const end = e.touches[0] const center = { x: this.startSelected.centerX, y: this.startSelected.centerY } const startLength = Math.sqrt((center.x - start.x) ** 2 + (center.y - start.y) ** 2) const endLength = Math.sqrt((center.x - end.x) ** 2 + (center.y - end.y) ** 2) const radian = this.convert2Radian(start, end, center) const scale = endLength / startLength const elements = this.elements.slice() const selected = elements[this.activeIndex] // 旋转 selected.rotate = this.startSelected.rotate - radian // 缩放 if (selected.type === 'text') { selected.left = this.startSelected.centerX - this.startSelected.size * this.startSelected.data.length * scale / 2 selected.top = this.startSelected.centerY - this.startSelected.size * scale / 2 selected.size = this.startSelected.size * scale } if (selected.type === 'sticker') { selected.left = this.startSelected.centerX - this.startSelected.width * scale / 2 selected.top = this.startSelected.centerY - this.startSelected.height * scale / 2 selected.width = this.startSelected.width * scale selected.height = this.startSelected.height * scale } store.commit('setElements', elements) }Zoom
// 缩放事件绑定函数
handleScale(e) {
if (e.touches.length !== 2 || this.mode !== 'background') return
const startLength = Math.sqrt(
(this.startTouches[0].x - this.startTouches[1].x) ** 2 +
(this.startTouches[0].y - this.startTouches[1].y) ** 2
)
const endLength = Math.sqrt(
(e.touches[0].x - e.touches[1].x) ** 2 + (e.touches[0].y - e.touches[1].y) ** 2
)
const scale = endLength / startLength
const elements = this.elements.slice()
const selected = elements[this.activeIndex || 0]
selected.left = this.startSelected.centerX - this.startSelected.width * scale / 2
selected.top = this.startSelected.centerY - this.startSelected.height * scale / 2
selected.width = this.startSelected.width * scale
selected.height = this.startSelected.height * scale
// elements[this.activeIndex || 0].scale = this.startSelected.scale * scale
store.commit('setElements', elements)
}
Export imageexport() {
if (!store.state.elements.length) {
wx.showToast({
title: '加点东西再导出吧',
icon: 'none'
})
return
}
wx.showModal({
title: '提示',
content: '图片将保存到手机相册',
success(res) {
if (res.confirm) {
console.log('export-canvas', store.state.ctx)
const canvas = store.state.canvas
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: canvas.width,
height: canvas.height,
canvas,
complete(res) {
if (res.errMsg === 'canvasToTempFilePath:ok') {
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success(res) {
wx.showToast({
title: '图片保存成功',
icon: 'none'
})
}
})
}
}
})
}
}
})
}
The above is the detailed content of Use the small program canvas to write a simple picture application. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

MantisBT
Mantis is an easy-to-deploy web-based defect tracking tool designed to aid in product defect tracking. It requires PHP, MySQL and a web server. Check out our demo and hosting services.

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

SublimeText3 Chinese version
Chinese version, very easy to use

EditPlus Chinese cracked version
Small size, syntax highlighting, does not support code prompt function

Atom editor mac version download
The most popular open source editor
