search
HomeWeChat AppletMini Program DevelopmentUse the small program canvas to write a simple picture application

Small program development tutorialThe column introduces the use of canvas to write a picture

Use the small program canvas to write a simple picture application

Recommendation (free): Mini program development tutorial

##Application display

Screenshot

Use the small program canvas to write a simple picture application

Requirements

Since it is a small application, I hope that the final product has

applicable scenarios And it is a valuable

source of demand

inspiration 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


Users need to upload a picture
  • 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 program

Using 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 store
Canvas 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 image

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'
                  })
                }
              })
            }
          }
        })
      }
    }
  })
}

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!

Statement
This article is reproduced at:segmentfault. If there is any infringement, please contact admin@php.cn delete

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

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

Hot Article

Hot Tools

MantisBT

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

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

SublimeText3 Chinese version

Chinese version, very easy to use

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

Atom editor mac version download

Atom editor mac version download

The most popular open source editor