Coder Social home page Coder Social logo

kuckboy1994 / mp_canvas_drawer Goto Github PK

View Code? Open in Web Editor NEW
1.7K 34.0 267.0 249 KB

:rocket: 微信小程序上canvas绘制图片助手,一个json就制作分享朋友圈图片

License: MIT License

JavaScript 100.00%
mp canvas drawer wxapp mpvue wepy xiaochengxu

mp_canvas_drawer's Introduction

canvas drawer

新增 mpvue_canvas_drawer。之后同步更新。

新增由simmzl开发移植的wepy_canvas_drawer。之后同步更新。

做微信小程序中最好用的 canvas 绘图组件之一。

当前环境下,大家都非常需要分享到朋友圈这个功能,但是实现起来各有心酸(坑比较多),所以才有了如下的 canvas 绘图工具。

具有如下特性:

  • 简单易用 —— 一个 json 搞定绘制图片
  • 功能全 —— 满足 90% 的使用场景
    • 绘制文本(换行、超出内容省略号、中划线、下划线、文本加粗)
    • 绘制图片
    • 绘制矩形
    • 保存图片
    • 多图绘制
    • ...
  • 代码量小

体验

git clone https://github.com/kuckboy1994/mp_canvas_drawer

想在手机上使用配置自己的 appid 即可。

编译模式中已经为你配置好比较常用的两种模式:

  • 普通绘制,绘制单张分享图。
  • 多图绘制,连续绘制分享图

演示

左侧是 canvasdrawer 绘制的,右侧是UI给的图

使用

  • git clone https://github.com/kuckboy1994/mp_canvas_drawer 到本地

  • components 中的 canvasdrawer 拷贝到自己项目下。

  • 在使用页面注册组件

    {
      "usingComponents": {
        "canvasdrawer": "/components/canvasdrawer/canvasdrawer"
      }
    }
  • 在页面 **.wxml 文件中加入如下代码

    <canvasdrawer painting="{{painting}}" bind:getImage="eventGetImage"/>

    painting 是需要传入的 jsongetImage 方法是绘图完成之后的回调函数,在 event.detail 中返回绘制完成的图片地址。

  • 当前栗子中的 painting 简单展示一下。详细配置请看 API

    painting(点击展开)
    {
      width: 375,
      height: 555,
      views: [
        {
          type: 'image',
          url: 'https://hybrid.xiaoying.tv/miniprogram/viva-ad/1/1531103986231.jpeg',
          top: 0,
          left: 0,
          width: 375,
          height: 555
        },
        {
          type: 'image',
          url: 'https://wx.qlogo.cn/mmopen/vi_32/DYAIOgq83epJEPdPqQVgv6D8bojGT4DrGXuEC4Oe0GXs5sMsN4GGpCegTUsBgL9SPJkN9UqC1s0iakjQpwd4h4A/132',
          top: 27.5,
          left: 29,
          width: 55,
          height: 55
        },
        {
          type: 'image',
          url: 'https://hybrid.xiaoying.tv/miniprogram/viva-ad/1/1531401349117.jpeg',
          top: 27.5,
          left: 29,
          width: 55,
          height: 55
        },
        {
          type: 'text',
          content: '您的好友【kuckboy】',
          fontSize: 16,
          color: '#402D16',
          textAlign: 'left',
          top: 33,
          left: 96,
          bolder: true
        },
        {
          type: 'text',
          content: '发现一件好货,邀请你一起0元免费拿!',
          fontSize: 15,
          color: '#563D20',
          textAlign: 'left',
          top: 59.5,
          left: 96
        },
        {
          type: 'image',
          url: 'https://hybrid.xiaoying.tv/miniprogram/viva-ad/1/1531385366950.jpeg',
          top: 136,
          left: 42.5,
          width: 290,
          height: 186
        },
        {
          type: 'image',
          url: 'https://hybrid.xiaoying.tv/miniprogram/viva-ad/1/1531385433625.jpeg',
          top: 443,
          left: 85,
          width: 68,
          height: 68
        },
        {
          type: 'text',
          content: '正品MAC魅可口红礼盒生日唇膏小辣椒Chili西柚情人',
          fontSize: 16,
          lineHeight: 21,
          color: '#383549',
          textAlign: 'left',
          top: 336,
          left: 44,
          width: 287,
          MaxLineNumber: 2,
          breakWord: true,
          bolder: true
        },
        {
          type: 'text',
          content: '¥0.00',
          fontSize: 19,
          color: '#E62004',
          textAlign: 'left',
          top: 387,
          left: 44.5,
          bolder: true
        },
        {
          type: 'text',
          content: '原价:¥138.00',
          fontSize: 13,
          color: '#7E7E8B',
          textAlign: 'left',
          top: 391,
          left: 110,
          textDecoration: 'line-through'
        },
        {
          type: 'text',
          content: '长按识别图中二维码帮我砍个价呗~',
          fontSize: 14,
          color: '#383549',
          textAlign: 'left',
          top: 460,
          left: 165.5,
          lineHeight: 20,
          MaxLineNumber: 2,
          breakWord: true,
          width: 125
        }
      ]
    }

API

对象结构一览
{
  width: 375,
  height: 555,
  views: [
    {
      type: 'image',
      url: 'url',
      top: 0,
      left: 0,
      width: 375,
      height: 555
    },
    {
      type: 'text',
      content: 'content',
      fontSize: 16,
      color: '#402D16',
      textAlign: 'left',
      top: 33,
      left: 96,
      bolder: true
    },
    {
      type: 'rect',
      background: 'color',
      top: 0,
      left: 0,
      width: 375,
      height: 555
    }
  ]
}

数据对象的第一层需要三个参数: widthheightmodeviews。配置中所有的数字都是没有单位的。这就意味着 canvas 绘制的是一个比例图。具体显示的大小直接把返回的图片路径放置到 image 标签中即可。

mode 可选值有 same, 默认值为空,常规下尽量不要使用。如要使用请看 Q&A的第1点。

当前可以绘制3种类型的配置: imagetextrect。配置的属性基本上使用的都是 css 的驼峰名称,还是比较好理解的。

image(图片)

属性 含义 默认值 可选值
url 绘制的图片地址,可以是本地图片,如:/images/1.jpeg
top 左上角距离画板顶部的距离
left 左上角距离画板左侧的距离
width 要画多宽 0
height 要画多高 0

text(文本)

属性 含义 默认值 可选值
content 绘制文本 ''(空字符串)
color 颜色 black
fontSize 字体大小 16
textAlign 文字对齐方式 left center、right
lineHeight 行高,只有在多行文本中才有用 20
top 文本左上角距离画板顶部的距离 0
left 文本左上角距离画板左侧的距离 0
breakWord 是否需要换行 false true
MaxLineNumber 最大行数,只有设置 breakWord: true ,当前属性才有效,超出行数内容的显示为... 2
width MaxLineNumber 属性配套使用,width 就是达到换行的宽度
bolder 是否加粗 false true
textDecoration 显示中划线、下划线效果 none underline(下划线)、line-through(中划线)

rect (矩形,线条)

属性 含义 默认值 可选值
background 背景颜色 black
top 左上角距离画板顶部的距离
left 左上角距离画板左侧的距离
width 要画多宽 0
height 要画多高 0

Q&A

  1. 最佳实践

    绘制操作的时候最好 锁住屏幕 ,例如在点击绘制的时候

    wx.showLoading({
      title: '绘制分享图片中',
      mask: true
    })

    绘制完成之后

    wx.hideLoading()

    具体可以参考项目下的 /pages/multiple

  2. [mpvue] 由于 canvasdrawer 不主动呈现绘制内容,而是交给调用者去使用 image 来展示,所以在mpvue更新数据就会render整个组件的,之后 canvasdrawer 又会重新被渲染,导致无限循环,所以默认情况下我把代码改为,传入的 painting 和之前的一样的话,组件就不渲染了。只有出现差异的内容才会更新(触发回调),这种个人认为还是可以接受的。 增加顶层参数 mode, mode: 'same' 为可以绘制同样的内容。在 mpvue 模式下勿用

  3. 二维码和小程序码如何绘制?

    • 二维码和小程序码可以通过调用微信官方的接口产生,需要后端配合。
    • 然后走 type: image 类型进行绘制即可。
  4. 绘制流程相关

    • views 数组中的顺序代表绘画的先后顺序,会有覆盖的现象。请各位使用者注意。
  5. 如何实现圆形头像?

    • 由于完成一些效果,例如: 文字下划线 等。必须要使用微信小程序 rect 相关的接口,和 clip 接口感觉相处的不好(存在bug)。可以查看 微信小程序社区的帖子
    • so,提供一种解决方式:使用一张中间镂空的图片盖在头像上。
  6. canvas drawer 组件为什么不直接显示canvas画板和其内容呢?

    • 考虑到大部分场景,我们都是用来把图片保存到本地,或用以展示。
    • 保存到本地,返回临时文件给调用者一定是最佳的解决方式。
    • 展示,转化成图片之后,就可以使用 image 基础组件的所有显示模式了,还能设置宽高。

更新计划

  • 图片缓存机制 - 加快相同图片绘制的速度
  • 增加 measureText 方法对于低版本的提示
  • 安卓下文本绘制稳定性修复
  • 增加圆角属性 borderRadiusborder 支持
  • 错误异常回调支持
  • 预缓存模式
  • 优化 measureText 测量模式
  • mpvue 版本小程序

TIPS

如果有什么疑问,欢迎 issues。 如果觉得不错,能不能送我小 ✨ ✨ ,让我有更多的动力。

mp_canvas_drawer's People

Contributors

kuckboy1994 avatar qizf7 avatar simmzl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mp_canvas_drawer's Issues

想画圆形图的童鞋们进来看看。

先从canvasdrawer.wpy文件中找到画图的这个方法drawImage。然后直接替换下面的代码就可以。
drawImage(params) { this.ctx.save(); const { url, top = 0, left = 0, width = 0, height = 0, borderRadius = 0 } = params; if(borderRadius){ let d = borderRadius * 2; let cx = left + borderRadius; let cy = top + borderRadius; this.ctx.beginPath(); this.ctx.arc(cx, cy, borderRadius, 0, 2 * Math.PI); this.ctx.fill(); this.ctx.clip(); this.ctx.drawImage(url, left, top, d, d); }else{ this.ctx.drawImage(url, left, top, width, height); } this.ctx.restore(); }
borderRadius 是圆的半径,image类型的json里加这个属性的时候你画出来的是圆形图。

下面是画圆角矩形,rect类型的json里加一个radius(圆角半径)属性就可以画圆角矩形。
drawRect(params) { this.ctx.save(); const { background, top = 0, left = 0, width = 0, height = 0, radius = 0 } = params; this.ctx.setFillStyle(background); if(radius){ // 开始绘制 this.ctx.beginPath(); // 左上角 this.ctx.arc(left + radius, top + radius, radius, Math.PI, Math.PI * 1.5); // border-top this.ctx.moveTo(left + radius, top); this.ctx.lineTo(left + width - radius, top); this.ctx.lineTo(left + width, top + radius); // 右上角 this.ctx.arc(left + width - radius, top + radius, radius, Math.PI * 1.5, Math.PI * 2); // border-right this.ctx.lineTo(left + width, top + height - radius); this.ctx.lineTo(left + width - radius, top + height); // 右下角 this.ctx.arc(left + width - radius, top + height - radius, radius, 0, Math.PI * 0.5); // border-bottom this.ctx.lineTo(left + radius, top + height); this.ctx.lineTo(left, top + height - radius); // 左下角 this.ctx.arc(left + radius, top + height - radius, radius, Math.PI * 0.5, Math.PI); // border-left this.ctx.lineTo(left, top + radius); this.ctx.lineTo(left + radius, top); // 这里是使用 fill 还是 stroke都可以,二选一即可,但是需要与上面对应 this.ctx.fill(); this.ctx.closePath(); }else{ this.ctx.fillRect(left, top, width, height); } this.ctx.restore(); }

多图重叠不显示

你好,我绘制两张图片,一张是大背景,一张是二维码,理论上我第二次绘制二维码的时候是覆盖在第一张上面的,为什么不显示,我自己手写canvas的时候是可以的,但是你的组件却不显示???

type:'text' , 文本的对齐方式失效???

{ type: 'text', content: 'this is text', fontSize: 30, color: '#402D16', textAlign: 'center', top: 270, right: 0 },

我设置文案居中或者居右的时候没有效果,只有居左的时候可以显示

添加圆角头像的支持

` drawImage(params) {
const { url, top = 0, left = 0, width = 0, height = 0, circleRadius = 0, color = '#eeeef0' } = params
this.ctx.save()
if (circleRadius) {
this.ctx.beginPath()
this.ctx.arc(left, top, circleRadius, 0, 2 * Math.PI);
this.ctx.setStrokeStyle(color)
this.ctx.stroke(); // 进行绘制
this.ctx.clip();
this.ctx.drawImage(url, left - circleRadius, top - circleRadius, width, height)
} else {
this.ctx.drawImage(url, left, top, width, height)
}

        this.ctx.restore(); //恢复之前保存的绘图上下文 恢复之前保存的绘图问下文即状态 还可以继续绘制
    }`

canvas

我用canvas画出了海报,然后固定定位在屏幕中间,这个disable-scroll属性也加了,父元素也设置了overflow-y:hidden; 但是这个海报还是能上下滚动,求解

引入到mpvue里边使用!

这个可以引入到mpvue里边使用吗?如果不可以的话可以改一下吗?让我们广大的mpvue使用者为你点赞

在PC和真机调试模式可以,但是真机不行

PC完美,真机调试很慢(真的非常慢,iPhone se),但是能出来,但是真机出不来
wxml代码
<block wx:if="{{showShareImage}}"> <image src="{{shareImage}}" style="height: {{windowHeight}}px;top: {{scrollTop}}px;" class="share-image"></image> </block> <block wx:if="{{showSaveBtn}}"> <button class="saveImg" style="top: {{scrollTop+windowHeight-50}}px;" bindtap="eventSave">保存图片到相册</button> </block> <canvasdrawer painting="{{painting}}" bind:getImage="eventGetImage"/>

js代码
eventDraw () { wx.showLoading({ title: '绘制分享图片中', mask: true }) this.setData({ showShareImage:true, showSaveBtn:true, painting: { width: 375, height: 555, clear: true, views: [ { type: 'image', url: 'http://retail.26460000.com/share.jpeg', top: 0, left: 0, width: 375, height: 555 }, { type: 'image', url: '/image/sys/redlogo.png', top: 27.5, left: 35, width: 120, height: 60 }, { type: 'text', content: '大兴二手车', fontSize: 16, color: '#402D16', textAlign: 'left', top: 33, left: 160, bolder: true }, { type: 'text', content: '您值得信赖的二手车专家', fontSize: 15, color: '#563D20', textAlign: 'left', top: 59.5, left: 160 }, { type: 'image', url: this.data.car.releaseRetail.mainPicPath, top: 136, left: 42.5, width: 290, height: 186 }, { type: 'image', url: '/image/sys/8cm.jpg', top: 435, left: 50, width: 100, height: 90 }, { type: 'text', content: this.data.car.releaseRetail.spOneSentenceAd +" "+ this.data.car.releaseRetail.modelName, fontSize: 16, lineHeight: 21, color: '#383549', textAlign: 'left', top: 336, left: 44, width: 287, MaxLineNumber: 2, breakWord: true, bolder: true }, { type: 'text', content: '¥'+this.data.car.releaseRetail.internetPrice+"万", fontSize: 19, color: '#E62004', textAlign: 'left', top: 387, left: 44.5, bolder: true }, { type: 'text', content: '新车指导价:¥'+this.data.car.releaseRetail.newCarPrice+"万", fontSize: 13, color: '#7E7E8B', textAlign: 'left', top: 391, left: 140, textDecoration: 'line-through' }, { type: 'text', content: '长按识别图中二维码', fontSize: 14, color: '#383549', textAlign: 'left', top: 460, left: 165.5, lineHeight: 20, MaxLineNumber: 2, breakWord: true, width: 125 } , { type: 'text', content: '海量优质二手车', fontSize: 14, color: '#383549', textAlign: 'left', top: 480, left: 165.5, lineHeight: 20, MaxLineNumber: 2, breakWord: true, width: 125 } ] } }) }, eventSave () { var that = this; wx.saveImageToPhotosAlbum({ filePath: this.data.shareImage, success (res) { wx.showToast({ title: '保存图片成功', icon: 'success', duration: 2000 }) that.setData({ showShareImage: false, showSaveBtn:false }) } }) }, eventGetImage (event) { console.log(event) wx.hideLoading() const { tempFilePath, errMsg } = event.detail if (errMsg === 'canvasdrawer:ok') { this.setData({ shareImage: tempFilePath, showSaveBtn:true }) } },

关于换行

首先,你这个组件很棒!然后在一些使用场景里,是有对内容进行换行,但不作内容省略的(不管有多少字都继续换行),感觉可以出个配置参数做不省略处理。

错误

你好,我点击绘制之后,就一直显示绘制分享图片中 然后没有图片出来,是怎么回事啊,谢谢

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.