您好,欢迎访问一九零五行业门户网

使用小程序canvas写一个简单的图片应用

小程序开发教程栏目介绍使用canvas写一个图片
推荐(免费):小程序开发教程
应用展示
截图
需求
既然是小应用,那就希望最终成品是有 适用的场景 且是 有价值 的
需求来源
这个应用需求的灵感
在以前工作生活中,经常会无意中获得同事的 美照
这时我们想要把这张照片做成表情包
一般给图片添加几个说明文字
一个有意思的沟通工具(表情包)就完成了
需求分析基于以上需求的拆解
可以将要应用功能实现整理一下
用户需要上传一张图片可以添加文字文字可以作 样式调整 和 旋转缩放另外我们希望还可以插入一些贴图贴图可以做 旋转缩放用户导出图片到相册实现
github仓库 https://github.com/luosijie/f...
如果喜欢我的项目,欢迎给个星星鼓励一下这个应用是用小程序开发的
使用框架:mpx使用技术:小程序canvas状态管理
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 store
画布初始化
// 初始化画布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()    })}
绘制图片
/** * 绘制图片 * @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()}
绘制文字
/** * 绘制文字 * @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()}
绘制控制元件
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()}
画布渲染函数
// 画布渲染函数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 < this.elements.length; i++) { const ele = this.elements[i] // 渲染背景 if (ele.type === 'background') { this.drawimage(ele) } if (ele.type === 'sticker') { this.drawimage(ele) } // 渲染文字 if (ele.type === 'text') { this.drawtext(ele) } // 选中元素添加控制元件 if (this.activeindex === i) { this.initcontroller(ele) } }}
事件监听
移动
// 移动事件绑定函数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)}
旋转// 旋转绑定函数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)}
缩放// 缩放事件绑定函数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() {  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'                  })                }              })            }          }        })      }    }  })}
以上就是使用小程序canvas写一个简单的图片应用的详细内容。
其它类似信息

推荐信息