微信小程序之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;
}

尔等勿喷!谢谢

  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值