1. 程式人生 > 其它 >微信小程式之canvas畫布

微信小程式之canvas畫布

技術標籤:微信小程式小程式

一、前言

只要幹不死,就要往死幹!!!

本次帶來的是關於微信小程式之畫布的相關功能,具體詳見程式碼↓

二、圖例

功能點:顏色選擇、直線、矩形、圓形、畫筆、輸入框、線條寬度、還有特定圖示、橡皮擦 、撤銷、清空等功能

三、程式碼

本次提供展示js、wxml、wxss 程式碼示例

1、js篇

var app = getApp();
var ctx; //畫布

var startx;
var starty;
var movex;
var movey;
var stopx;
var stopy;
var tools = 'line'; // 預設選擇的工具
var canvasList = [];
var guahua = '../../../../images/guahua.png';
var tuhen = '../../../../images/tuhen.png';
var aohen = '../../../../images/aohen.png';
var polie = '../../../../images/polie.png';
var tuoqi = '../../../../images/tuoqi.png';

var oldx = '';
var oldy = '';
var color = "#000000";
Page({

  /**
   * 頁面的初始資料
   */
  data: {
    canvasWidth: '',
    canvasHeight: '336',
    lineWidth: 2,
    canvasList: [],
    isShowInput: 'true', //是否顯示輸入框 或者是否獲取焦點
    inputTop: '', //input框顯示邊距
    inputLeft: '',
    textInfo: '',
    value_input: '',
    isfocus: true,
    canvasbg: '',
    flag: "true", //遮罩層顯示
    colorone: ['#FE0000', '#00FEFF', '#0000FE', '#01FF02'],
    colortwo: ['#FF00FE', '#FEFE00', '#000000', '#FFFFFF'],
    color: '#000000',

    car_imagelist: [], //車輛照片陣列
    linshicarid: [], //臨時車輛ID
    car_order: '',

    editable: false, //編輯許可權
    statusBarHeight: '', //狀態列高度
  },

  // 選擇顏色
  select_colorone: function(e) {
    console.log(e);
    var p = e.currentTarget.dataset.p;
    this.setData({
      color: this.data.colorone[p]
    })
  },
  select_colortwo: function(e) {
    console.log(e);
    var p = e.currentTarget.dataset.p;
    this.setData({
      color: this.data.colortwo[p]
    })
  },
  color_cancle: function() {
    this.setData({
      flag: "true"
    })
    color = this.data.color;
  },
  color_sure: function() {
    this.setData({
      flag: "true",
    })
    switch (tools) {
      case 'line':
        this.line();
        break
      case 'box':
        this.box();
        break
      case 'circle':
        this.circle();
        break
      case 'pan':
        this.pan();
        break
    }
  },

  //繪圖動作函式監聽
  // 開始
  ringstart: function(e) {
    startx = e.changedTouches[0].x;
    starty = e.changedTouches[0].y;
    ctx.moveTo(startx, starty);
    // ctx.lineTo(startx, starty);
    console.log(startx, starty);
    if (tools == 'text') {
      this.setData({
        isShowInput: '',
        inputTop: starty,
        inputLeft: startx,
        value_input: '',
        isfocus: true,
      })
      console.log(this.data.isfocus);
      if (this.data.textInfo != "") {
        //繪製文字
        ctx.setFontSize(14)
        ctx.fillText(this.data.textInfo, oldx, oldy);
        ctx.draw(true, this.saveCanvasImage());
      }
    }
  },
  // 繪製中
  ringmove: function(e) {
    movex = e.changedTouches[0].x;
    movey = e.changedTouches[0].y;
    switch (tools) {
      case 'pan':
        ctx.lineTo(movex, movey);
        ctx.stroke(this.data.color);
        ctx.draw(true, this.saveCanvasImage());
        ctx.moveTo(movex, movey);
        break
      case 'rubber': //橡皮擦
        ctx.clearRect(movex - 8, movey - 8, 15, 15);
        ctx.draw(true, this.saveCanvasImage());
        break
    }

  },
  // 繪製結束
  ringchend: function(e) {
    stopx = e.changedTouches[0].x;
    stopy = e.changedTouches[0].y;
    switch (tools) {
      case 'guahua': //刮花
        this.drawImagestoCanvas(guahua);
        break
      case 'aohen': //凸痕
        this.drawImagestoCanvas(aohen);
        break
      case 'tuhen': //凹痕
        this.drawImagestoCanvas(tuhen);
        break
      case 'polie': //破裂
        this.drawImagestoCanvas(polie);
        break
      case 'tuoqi': //脫漆
        this.drawImagestoCanvas(tuoqi);
        break
      case 'rubber': //橡皮
        break

      case 'line': //畫線
        ctx.beginPath();
        ctx.moveTo(startx, starty);
        ctx.lineTo(stopx, stopy);
        ctx.stroke(this.data.color);
        ctx.draw(true, this.saveCanvasImage());
        break
      case 'box': //畫矩形
        ctx.beginPath();
        ctx.setStrokeStyle(this.data.color)
        ctx.strokeRect(startx, starty, stopx - startx, stopy - starty)
        ctx.draw(true, this.saveCanvasImage());
        break
      case 'circle': //畫圓
        ctx.beginPath();
        ctx.arc(startx, starty, stopx - startx > stopy - starty ? stopx - startx : stopy - starty, 0, 2 * Math.PI);
        ctx.stroke(this.data.color);
        ctx.draw(true, this.saveCanvasImage());
        break
    }


  },

  // 畫圖工具函式監聽
  // 右邊工具欄

  guahua: function() { //刮花
    tools = 'guahua';
    this.hiddenInput();
  },
  tuhen: function() { //凸痕
    tools = 'tuhen';
    this.hiddenInput();
  },
  aohen: function() { //凹痕
    tools = 'aohen';
    this.hiddenInput();
  },
  polie: function() { //破裂
    tools = 'polie';
    this.hiddenInput();
  },
  tuoqi: function() { //脫漆
    tools = 'tuoqi';
    this.hiddenInput();
  },
  rubber: function() { //橡皮
    tools = 'rubber';
    this.hiddenInput();
  },
  back: function(e) { // 撤銷
    this.hiddenInput();
    // canvasList.pop();
    canvasList.splice(canvasList.length - 1, 1);
    var image = canvasList.pop();
    console.log(canvasList);
    ctx.drawImage(image, 0, 0, 383, 209);
    ctx.draw(false);
  },
  cancle: function() { // 清空
    this.hiddenInput();
    ctx.restore();
    ctx.draw();
    this.drawImages();
    //清空陣列集合
    canvasList = [];
  },

  // 繪製圖片到畫布中 {右側工具中 刮花 凸痕 凹痕 破裂 脫漆}
  drawImagestoCanvas: function(imgUrl) {
    ctx.drawImage(imgUrl, startx - 10, starty - 11, 22, 22);
    ctx.draw(true, this.saveCanvasImage());
  },

  //快取繪製圖片
  saveCanvasImage: function() {
    this.setData({
      textInfo: ''
    })
    var than = this;
    wx.canvasToTempFilePath({
      canvasId: 'ringcanvas',
      success: res => {
        console.log(res.tempFilePath);
        canvasList = canvasList.concat(canvasList.push(res.tempFilePath));
        console.log('快取繪圖');
        console.log(canvasList);
      },
      fail: err => {

      }
    })
  },
  color: function() {
    //設定顏色
    this.setData({
      flag: ''
    })
  },

  line: function() { // 直線
    tools = 'line';
    this.hiddenInput();
  },
  box: function() { //矩形
    tools = 'box';
    this.hiddenInput();
  },
  circle: function() { //圓
    tools = 'circle';
    this.hiddenInput();
  },
  pan: function() { // 畫筆
    tools = 'pan';
    this.hiddenInput();
  },
  text: function() { //寫字
    tools = 'text';
  },
  minus: function() {
    this.hiddenInput(); //畫筆粗細 減
    if (this.data.lineWidth > 1) {
      this.setData({
        lineWidth: this.data.lineWidth - 1
      })
      ctx.setLineWidth(this.data.lineWidth);
    } else {

    }
  },
  add: function() { //畫筆粗細 加
    this.hiddenInput();
    this.setData({
      lineWidth: this.data.lineWidth + 1
    })
    ctx.setLineWidth(this.data.lineWidth);
  },

  hiddenInput: function() {
    this.setData({
      isShowInput: true
    })
  },

  // 獲取輸入框的值
  inputText: function(e) {
    var value = e.detail.value;
    if (value == "") {

    } else {
      this.setData({
        textInfo: value
      })
      // 儲存前一input位置的xy
      oldx = startx;
      oldy = starty;
    }
    console.log(e);
  },


  /**
   * 生命週期函式--監聽頁面載入
   */
  onLoad: function(options) {
    
    // 設定導航欄標題
    app.setNavigationtitle('環車檢查');
    // 獲取螢幕資訊
    wx.getSystemInfo({
      success: (res) => {
        console.log(res)
        var statusBarHeight = res.statusBarHeight; //狀態列高度
        this.setData({
          canvasWidth: res.screenWidth - 38,
          statusBarHeight: statusBarHeight
        })
      },
    })

    // 初始化畫布物件
    ctx = wx.createCanvasContext('ringcanvas', this);
    
  },

  drawImages: function() {
    //載入時就繪製背景圖片
    var image = '../../../../images/ringcar_bg.png';
    // ctx.drawImage(image, 0, 0, this.data.canvasWidth, 336);
    // ctx.draw();

    var manager = wx.getFileSystemManager();
    manager.readFile({
      filePath: '../../../../images/ringcar_bg.png', // 選擇圖片返回的相對路徑
      encoding: 'base64', // 編碼格式
      success: res => { // 轉碼成功的回撥
        console.log(res);
        var baseImg = 'data:image/png;base64,' + res.data;
        console.log(baseImg);
        // 後續的邏輯處理
      }
    })
  },

  /**
   * 生命週期函式--監聽頁面初次渲染完成
   */
  onReady: function() {
  },

  /**
   * 生命週期函式--監聽頁面顯示
   */
  onShow: function() {

  },

  /**
   * 生命週期函式--監聽頁面隱藏
   */
  onHide: function() {

  },

  // 網路請求函式
  request: function(url, data, type) {
    //寫自己的邏輯函式
  },
})

2、wxml篇

<view class="view_">

  <view class="canvas_container" style="margin-left:{{statusBarHeight}}px">
    <view>
      <image class="ringcar_checkcanvas" src="http://39.108.15.203:8000/AppSvc/Images/RecCheckBack01.png"></image>
    </view>
    <canvas disable-scroll="true" class="ringcar_checkcanvas" canvas-id="ringcanvas" bindtouchstart="{{editable ? 'ringstart' : ''}}" bindtouchmove="{{editable ? 'ringmove' : ''}}" bindtouchend="{{editable ? 'ringchend' : ''}}"> </canvas>


<!-- 畫布右側功能鍵 -->
    <view class="ringcar_checkright_r">
      <!-- 刮花 -->
      <view class="{{editable?'righttool_container':'editable'}}" bindtap="{{editable?'guahua':''}}" hover-class="select_color">
        <icon class="iconfont iconcircle" style="color:#0608FB"></icon>
        <text>刮花</text>
      </view>
      <view class="{{editable?'righttool_container':'editable'}}" bindtap="{{editable?'tuhen':''}}" hover-class="select_color">
        <icon class="iconfont icontriangle" style="color:#F20909"></icon>
        <text>凸痕</text>
      </view>
      <!-- 凹痕 -->
      <view class="{{editable?'righttool_container':'editable'}}" bindtap="{{editable?'aohen':''}}" hover-class="select_color">
        <icon class="iconfont iconaohen" style="color:#F20909"></icon>
        <text>凹痕</text>
      </view>
      <!-- 破裂 -->
      <view class="{{editable?'righttool_container':'editable'}}" bindtap="{{editable?'polie':''}}" hover-class="select_color">
        <icon class="iconfont iconerr" style="color:#F20909"></icon>
        <text>破裂</text>
      </view>
      <!-- 脫漆 -->
      <view class="{{editable?'righttool_container':'editable'}}" bindtap="{{editable?'tuoqi':''}}" hover-class="select_color">
        <icon class="iconfont iconforbid" style="color:#0B8E1E"></icon>
        <text>脫漆</text>
      </view>
      <view class="{{editable?'righttool_container':'editable'}}" bindtap="{{editable?'rubber':''}}" hover-class="select_color">
        <icon class="iconfont iconrubber"></icon>
        <text>橡皮</text>
      </view>
      <view class="{{editable?'righttool_container':'editable'}}" bindtap="{{editable?'back':''}}" hover-class="select_color">
        <icon class="iconfont iconrevocation"></icon>
        <text>撤銷</text>
      </view>
      <view class="{{editable?'righttool_container':'editable'}}" bindtap="{{editable?'cancle':''}}" hover-class="select_color">
        <icon class="iconfont icondelete"></icon>
        <text>清空</text>
      </view>
    </view>

<!-- 畫布底部功能鍵 -->
    <view class="ringcar_checkbottom_t">
      <view class="{{editable?'bottom_tool':'editable_tool'}}" bindtap="{{editable?'color':''}}" hover-class="select_color">
        <view style="background:red;color:#ffffff">顏色</view>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}" bindtap="{{editable?'line':''}}" hover-class="select_color">
        <icon class="iconfont iconline"></icon>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}" bindtap="{{editable?'box':''}}" hover-class="select_color">
        <icon class="iconfont iconbox"></icon>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}" bindtap="{{editable?'circle':''}}" hover-class="select_color">
        <icon class="iconfont iconcircle"></icon>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}" bindtap="{{editable?'pan':''}}" hover-class="select_color">
        <icon class="iconfont iconpan"></icon>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}" bindtap="{{editable?'text':''}}" hover-class="select_color">
        <icon class="iconfont icontext"></icon>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}">
        <view style="background:#ffffff">線條:</view>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}" bindtap="{{editable?'minus':''}}" hover-class="select_color">
        <icon class="iconfont iconminus" style="color:#0076FF"></icon>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}">
        <view type="number" value="{{lineWidth}}" bindinput="{{editable?'line_width':''}}">{{lineWidth}}</view>
      </view>
      <view class="{{editable?'bottom_tool':'editable_tool'}}" bindtap="{{editable?'add':''}}" hover-class="select_color">
        <icon class="iconfont iconadd" style="color:#0076FF"></icon>
      </view>
    </view>
  </view>
</view>



<!-- 畫布輸入框 -->
<view>
  <input hidden="{{isShowInput}}" value="{{value_input}}" focus="{{isfocus}}" class="canvas_text" style="top:{{inputTop}}px;left:{{inputLeft}}px" bindinput="inputText"></input>
</view>
<!-- 顏色選擇框 -->
<view class="zhezhao" hidden="{{flag}}">
  <view class="zhezhaoview">
    <view class="select">
      <view>選擇顏色</view>
      <view style="background:{{color}}; width:40px;higth:40px;color: rgba(255, 255, 255, 0);">1</view>
    </view>
    <view class="colorview">
      <view wx:for="{{colorone}}" bindtap="select_colorone" data-p="{{index}}" wx:key="index" class="color" style="background:{{item}}"></view>
    </view>
    <view class="colorview">
      <view wx:for="{{colortwo}}" bindtap="select_colortwo" data-p="{{index}}" wx:key="index" class="color" style="background:{{item}}"></view>
    </view>
    <view class="more">更多</view>
    <view class="right">
      <view bindtap="color_cancle">取消</view>
      <view bindtap="color_sure">設定</view>
    </view>
  </view>
</view>

3、wxss篇


page {
  background: #f8f8f8;
}

.view_{
  display: flex;
  flex-direction: row;
  margin-bottom: 40px;
}

.canvas_container{
  width: 421px;
  height: 100%;
  float: left;
}

.ringcar_checkcanvas {
  width: 383px;
  height: 209px;
  position: absolute;
}

/* 右邊工具 */

.ringcar_checkright_r {
  margin-left: 383px;
  font-size: 10px;
  color: #888;
  float: left;
  width: 38px;
  height: 264px;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
}

/* 右邊工具view */

.righttool_container {
  width: 38px;
  background: white;
  display: flex;
  height: 33px;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

icon{
  font-size:8px;
}
.righttool_container text{
  font-size:8px;
}

/* 畫布下面工具 */

.ringcar_checkbottom_t {
  width: 381px;
  position: absolute;
  margin-top: 209px;
  font-size: 12px;
  text-align: center;
  line-height: 53px;
  height: 53px;
  border: 1px #f8f8f8 solid;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
}

.bottom_tool {
  width: 10%;
  background: white;
}

.ringcar_checkbottom_t input {
  background: white;
  width: 26px;
  height: 30px;
  color: rgba(136, 136, 136, 1);
  font-size: 14px;
  font-family: Arial;
  border: 1px solid rgba(187, 187, 187, 1);
}

.canvas_text {
  position: fixed;
  border: 1px #888 dashed;
  height: auto;
  width: 200px;
}

.right_container{
  width: auto;
  height: 100%;
  float: left;
}

/* 底部item條目 */

.ringcar_checkbottom_list {
  /* margin-bottom: 50px; */
}

.testitem {
  width: 100%;
  font-size: 12px;
  color: #888;
  margin-bottom: 1px;
  background: white;
  height: 30px;
}

.testitem view {
  float: left;
  line-height: 30px;
  margin-left: 4px;
}

.iconright{
  float: right;
}

/* 選中顏色樣式 */

.select_color {
  background: #ddd;
}

/* 彈出遮罩層 */

.zhezhao {
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0px;
  background: rgba(0, 0, 0, 0.4);
  overflow: hidden;
}

.zhezhaoview {
  margin: 10px;
  background: white;
  border-radius: 5px;
  height: 80%;
  width: (100% - 20px);
  justify-content: center;
  align-items: center;
}

.select {
  height: 30px;
  line-height: 30px;
  margin-bottom: 5px;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
  padding-top: 2px;
}

.colorview {
  text-align: center;
  display: flex;
  height: 40px;
  flex-direction: row;
  align-items: center;
  justify-content: space-around;
  width: 100%;
  margin-top: 10px;
}

.more {
  border: 1px #ddd solid;
  width: 98%;
  text-align: center;
  font-size: 14px;
  height: 40px;
  margin-top: 10rpx;
  margin-left: 10rpx;
  line-height: 40px;
}

.color {
  float: left;
  border: 1px #ccc solid;
  height: 40px;
  width: 23%;
}

.right {
  color: red;
  margin-top: 20px;
  font-size: 12px;
  float: right;
  width: 50%;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
}

.car_imagecontainer {
  float: left;
  position: relative;
}

.car_image {
  width: 60px;
  height: 60px;
}

#deleteerr {
  width: 12px;
  height: 12px;
  right: 2px;
  top: 2px;
  border: 1px black solid;
  font-size: 12px;
  color: red;
  position: absolute;
}

.add_image {
  float: left;
  text-align: center;
  font-size: 22px;
  width: 60px;
  height: 60px;
}

/* 許可權狀態樣式 底色*/

.editable {
  background: #f5f5f5;
  color: #aaa;
  width: 38px;
  background: white;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.editable_tool {
  width: 10%;
  background: #f5f5f5;
  color: #aaa;
}

爾等勿噴!謝謝