关于前端:uniapp-绘制海报的各种工具

16次阅读

共计 8656 个字符,预计需要花费 22 分钟才能阅读完成。

在日常 uniapp 和小程序开发,每当工作须要绘制一个海报,都让我很头疼,我须要将我以前的代码(downloadFile 异步封装,ctx 绘制办法 ….)复制过去,而后在一个个引入,又或者找不到了,又去百度(而后这漫长的一天将这么节约了,所以为了缩小引入这些芜杂的工具我做了一个专门用于绘制海报的一个工具库,这样就能够缩小我的工作量啦(hhh 又能够摸鱼划水了。上面是插件库的介绍,大家能够看看,目前性能都曾经全副欠缺了

绘制海报工具简述

  • 创立绘制海报 canvas 矩形办法,内置了图片绘制,圆角矩形绘制,换行字体绘制等办法。
  • 靠近原生开发体验,上手快,只需思考业务逻辑,而不必思考其余问题。
  • 领有良好的语法架构,不会在绘制 uni/wx 矩形时陷入回调天堂。
  • 反对原生小程序,与 uniapp 多端利用。当是环境为原生小程序时,主动切换为性能更好的 type2d 绘制形式。
  • 将简单的逻辑组合为简略的办法,扩展性强,可应用 use|useCtx 引入扩大。
  • 反对 typescript,反对vue3 模板,具体应用参考 useDrawPoster。

api 文档:u-draw-poster

插件市场:dcloud/u-draw-poster

npm 装置插件

npm i --save-dev u-draw-poster

开启对该插件的 uni 条件编译(重要)

// vue.config.js
module.exports = {transpileDependencies: ['u-draw-poster'],
};

1. 创立海报绘制工具

<!-- #ifdef MP-WEIXIN -->
<canvas id="canvas" type="2d" style="width:100rpx; height:100rpx" />
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<canvas canvas-id="canvas" id="canvas" style="width:100rpx; height:100rpx" />
<!-- #endif -->
// 留神:如果应用 HBuilder 引入, 须要引入 '@/js_sdk/u-draw-poster'
import DrawPoster from 'u-draw-poster'
async onReady() {// 传入选择器, 初始化绘制工具(留神, 不须要传入 #符号) 当微信小程序时, 将主动启用 type2d 绘制
 const dp = await DrawPoster.build("canvas")   
}

2. 设置画布尺寸

// 设置长高为 100px 的矩形宽高
dp.canvas.width = 100
dp.canvas.height = 100

3. 绘制任意内容

// 绘制背景与文字
dp.draw((ctx) => {
    ctx.fillStyle = "#F4F4F4";
    ctx.fillRect(0, 0, dp.canvas.width, dp.canvas.height);
    ctx.textBaseline = "top";
    ctx.textAlign = "start";
    ctx.fillStyle = "white";
    ctx.font = `bold ${22}px sans-serif`;
    ctx.fillText('周先生', dp.canvas.width/2, 38.5);
})
// 绘制图片内容
dp.draw(async (ctx) => {//.......})

值得注意的是, draw办法会主动的执行ctx.save/ctx.restore, 不须要人为操纵绘画栈.

dp.draw((ctx) => {/* ... */})
// 相当于
ctx.save()
/* ... */
ctx.restore()

4. 进行绘制

dp.draw并不会马上绘制,只是将该工作增加到了工作栈,须要应用 dp.awaitCreate 函数进行绘制,该函数在绘制结束后将弹出所有工作。
dp.awaitCreate在非 2d 绘画中,执行绘画工作结束后,将主动执行 ctx.draw 办法,并在 draw 绘画才算异步完结。

dp.draw((ctx) => {/* ... */})
dp.draw(async (ctx) => {/* ... */})
// 因为每个工作都有可能会有异步的绘制工作, 所以得须要应用 await 期待绘制
const result = await dp.awaitCreate();
// 绘制胜利将返回每个工作的绘制情况组成的数组
console.log("draw 绘制情况:", result); // draw 绘制情况: [true]

5. 生成图片本地地址

如须要保留为图片时,能够应用 dp.createImgUrl 进行创立图片本地地址,在由wxuniapi 进行保留。

dp.draw(async (ctx) => {/* ... */})
const result = await dp.awaitCreate();
const posterImgUrl = await dp.createImagePath();
console.log("draw 绘制情况:", result); // [true]
console.log("绘制生成本地地址:", posterImgUrl); // ...tmp...

你也能够不应用 dp.awaitCreate 办法,当调用 dp.createImagePath 时会自动检测工作列表,如果有则执行绘制工作后在创立地址。

dp.draw(async (ctx) => {/* ... */})
// 跳过 drawPoster.awaitCreate 间接生成地址
const posterImgUrl = await dp.createImagePath();
console.log("绘制生成本地地址:", posterImgUrl);

绘制扩大 API

drawPoster在创立时,会主动的向 ctx(画笔) 增加 / 笼罩扩大办法,以便构建海报矩形。

dp.draw(async (ctx) => {// ctx.drawImage | ctx.drawRoundImage | ctx.fillWarpText | ....})

绘制图片(ctx.drawImage)

ctx.drawImage(url, x, y, w, h)

drawPoster绘制图片与原生绘制不雷同,ctx.drawImage外部曾经内置了 downloadFile,只须要传入本地 / 网络地址即可。反对2d非 2d绘制,绘制形式统一。须要 await 期待绘制。

留神:当绘制环境为 H5 时,uniapp 应用本地图片绘画时不要用尺寸较大的图片,不然会在创立图片时生成失败。

dp.draw(async (ctx)=>{
    const url = "/static/logo.png"
    // const url = "https://...."
    await ctx.drawImage(url, 88, 174.94, 198.98, 36);
})
参数 形容
url 网络图片地址,或本地 /static 中图片门路。
x,y 图片的左上角的坐标。
width,height 图片的大小。

换行字体(ctx.fillWarpText)

ctx.fillWarpText(options)

传入配置对象,绘制换行字体,以下为可配置项。

interface FillWarpTextOpts {
  // 绘制字符串, 必传项
  text: string;
  // 绘制最长高度, 默认 100px
  maxWidth?: number;
  // 绘制行高, 默认取以后字体的默认宽度
  lineHeight?: number;
  // 绘制行数量, 默认限度为 2 层
  layer?: number;
  // 绘制 x 轴, 默认 0
  x?: number;
  // 绘制 y 轴, 默认 0
  y?: number;
  // 设置换行字符, 默认为空, 如设置, maxWidth|layer 将会生效
  splitText?: string;
  // 是否不马上进行绘制
  notFillText?: boolean;
}
// 当 `notFillText` 为 `true` 时,则不进行绘制,该函数将返回一个绘制信息队列
// 用于代表每行字体所对应的绘制信息, 以下是返回的构造信息,你能够用于计算该
// 换行字体的宽度,也你能够应用 array.forEach 与 ctx.fillText 进行绘制。[{ text: string, y: number, x: number}
  // ....
]

圆角矩形(ctx.fillRoundRect)

ctx.fillWarpText(x, y, w, h, r)

dp.draw(async (ctx)=>{
   // 设置矩形色彩
   ctx.fillStyle = "#fff";
   // 进行绘制
   ctx.fillRoundRect(15, 179, 345, 365.5, 10);
})
参数 形容
x,y 矩形的左上角的坐标。
width,height 矩形的大小。
r 矩形的弧度半径。

圆角矩形边框(ctx.strokeRoundRect)

ctx.strokeRoundRect(x, y, w, h, r)

参数 形容
x,y 矩形的左上角的坐标。
width,height 矩形的大小。
r 矩形的弧度半径。

圆角图片(ctx.drawRoundImage)

ctx.drawRoundImage(url, x, y, w, h, r)

dp.draw(async (ctx) => {
  const url = "static/logo.png"
  // const url = "https://...."
  await ctx.drawRoundImage(url, 0, 0, 100, 100, 50);
});
参数 形容
url 网络图片地址,或本地 /static 中图片门路。
x,y 图片的左上角的坐标。
width,height 图片的大小。
r 图片的弧度半径。

绘制二维码(ctx.drawQrCode)

生成二维码扩大,源码应用了 uQRCode 并改变了一下,该文件比拟大,所以作为扩大插件应用,应用时得先引入插件。

// 留神:如果应用 HBuilder 引入, 须要引入 '@/js_sdk/u-draw-poster'
import DrawPoster from 'u-draw-poster'
import drawQrCode from 'u-draw-poster/dist/extends/draw-qr-code'
// 引入绘制二维码插件
DrawPoster.useCtx(drawQrCode)

async onReady() {const dp = await DrawPoster.build("canvas")
 dp.canvas.width = 200; dp.canvas.height = 200
 dp.draw(ctx=>{
   ctx.drawQrCode({x: (dp.canvas.width / 2) - 50,
    y: (dp.canvas.height / 2) - 50,
    text: "http://www.baidu.com",
    size: 100,
  });
 })
}
参数 类型 必填 阐明
x number 程度方向偏移长度
y number 垂直方向偏移长度
text String 二维码内容
size Number 二维码尺寸大小
margin Number 边距,二维码理论尺寸会依据所设边距值进行缩放调整(默认:0
backgroundColor String 背景色,若设置为通明背景,fileType 需设置为 'png',而后设置背景色为 'rgba(255,255,255,0)' 即可(默认:'#ffffff'
foregroundColor String 前景色(默认:'#000000'
errorCorrectLevel Number 纠错等级,蕴含 errorCorrectLevel.LerrorCorrectLevel.MerrorCorrectLevel.QerrorCorrectLevel.H 四个级别,L: 最大 7% 的谬误可能被纠正;M: 最大 15% 的谬误可能被纠正;Q: 最大 25% 的谬误可能被纠正;H: 最大 30% 的谬误可能被纠正。

全局实例 API

绘画构建(DrawPoster.build)

DrawPoster.build(string|object)

初始化构建绘制工具,传入查问字符串与配置对象,当配置字符串时,则间接查问该字符串的 canvas,当配置对象时,object.selector 则为必选项,以下是 options 的配置项,须要留神的是,返回值为Promise,返回绘制构建对象dp

/** DrawPoster.build 构建配置 */
interface DrawPosterBuildOpts {// 查问字符串(必须), 留神不要写错对应 canvas id, 不须要传入 #符号
    selector: string;
    // 选取组件范畴
    componentThis?: any;
    // 类型为 2d 绘制, 默认开启, 在微信小程序的时候动静加载
    type2d?: boolean;
    // 是否在绘制的过程中, 显示加载框, 默认敞开
    loading?: boolean,
    // 当存在绘制图片时, 期待绘画结束的工夫(毫秒),仅在 App 中失效
    drawImageTime?: 100,
    // 加载提醒文字
    loadingText?: '绘制海报中...',
    // 创立图片加载提醒文字
    createText?: '生成图片中...'
}

多绘画构建(DrawPoster.buildAll)

DrawPoster.buildAll(Array<string|object>)

构建多个绘画工具,传入 build 函数中参数 string | options 形成的数组,返回多个绘制工具组成的对象。key 为 canvasId,value 为构建对象。

挂载全局扩大(DrawPoster.use)

DrawPoster.use(object)

传入挂载配置对象,增加全局扩大办法,个别可用于海报绘制模板的封装,在不同页面有一样的海报模板时能够无效的缩小代码量,应用形式如下。

一、在任意地位增加扩大(倡议放在 main.js 中执行)

import DrawPoster from 'u-draw-poster'
// 全局增加绘制集体海报的扩大实现
DrawPoster.use({
  name: "createMyCardImagePath",
  // dp 为以后实例, 其余参数为自定义传入参数
  handle: async (dp, opts) => {
    // .. 自定义构建内容..
    return await dp.createImagePath()}
})

二、页面中应用自定义扩大

import DrawPoster from 'u-draw-poster'
async onReady() {const dp = await DrawPoster.build("canvas")
 dp.canvas.width = 100; dp.canvas.height = 100
 const posterImg = await dp.createMyCardImagePath({/*...*/})
}

挂载绘制扩大(DrawPoster.useCtx)

DrawPoster.useCtx(object)

传入挂载配置对象,增加全局绘制扩大办法,用于自定义绘制办法的定义,应用形式如下。

一、在任意地位增加扩大(倡议放在 main.js 中执行)

// 全局增加绘制二维码的绘画扩大实现
DrawPoster.useCtx({
  name: "drawQrCode",
  // canvas(绘制节点), ctx(绘制画笔), 其余参数为自定义传入参数
  handle: async (canvas, ctx, url, x, y, w, h) => {// .. 自定义绘制内容..},
});

二、绘制中应用自定义扩大

dp.draw(ctx=> {
  const url = 'http://www.baidu.com'
  await ctx.drawQrCode(url, 0, 0, 50, 50)
 })

绘制节点(dp.canvas)

dp.canvas | dp.canvas.width | dp.canvas.height | ...

dp.canvas为全局的绘制根节点,在微信小程序中领有独享 API。在其余端将作为全局宽高容器应用。当dp.createImagePath 未传入参数时,默认应用 dp.canvas.width | dp.canvas.height 创立图片,以下是 dp.canvas 对象中存在的 api 与属性。

interface Canvas {
  width: number;
  height: number;
  // 残余参数为微信小程序独享 API,只有微信小程序才领有的 API
  // 具体参考微信小程序文档:https://developers.weixin.qq.com/miniprogram/dev/api/canvas/Canvas.html
}

创立绘制(dp.draw)

dp.draw(async callback(ctx))

绘制器, 接管执行器函数, 增加到绘制容器中,可改装为异步函数解决图片绘制,也能够为同步函数。

全局画笔(dp.ctx)

dp.ctx

全局绘制画笔,非凡状况能够应用,举荐只应用 dp.draw 函数进行绘制。

期待绘制(dp.awaitCreate)

dp.awaitCreate()

异步绘制绘制器堆栈,胜利后清空绘制器容器,返回胜利堆栈情况的数组(boolean[])。

进行绘画(dp.stop)

dp.stop()

进行以后绘画栈,调用后将进行 dp.awaitCreate |dp.createImagePath 的执行。

创立图片(dp.createImagePath)

dp.createImagePath(options)

创立以后 canvas 绘制后的本地图片地址,如绘制器堆栈未清空时,会主动调用 dp.awaitCreate() 清空堆栈。createImagePath 会依据 canvas.widthcanvas.height 进行创立图片。如果你想自定义参数,awaitCreate 办法能够承受一个配置对象,返回图片地址,以下为可配置项。

interface CreateImagePathOptions {
  x?: number;
  y?: number;
  width?: number;
  height?: number;
  destWidth?: number;
  destHeight?: number;
}

应用倡议

canvas 在海报生成中请当做一个生成工具来对待,它的作用仅是绘制出海报。应把生成失去的资源保留并应用,显示用 image 图片组件,起因是不便操作,例如调整大小,或是 H5 端长按保留或辨认,所以 canvas 应将它放在看不见的中央。不能用 display:none;overflow:hidden; 暗藏,否则生成空白。这里举荐 canvas 的暗藏款式代码,该阐明为 uQRCode 提供的阐明,同样 u-draw-poster 也实用

.canvas-hide {
    /* 1 */
    position: fixed;
    right: 100vw;
    bottom: 100vh;
    /* 2 */
    z-index: -9999;
    /* 3 */
    opacity: 0;
}

常见问题

微信小程序手机浏览空白

微信小程序绘制如果有图片绘制,手机浏览须要在后盾增加 downloadFile 域名,并须要重启开发者工具。

微信小程序无奈真机调试

https://developers.weixin.qq….

H5 端图片裁剪异样

H5 端绘制两个以上的 ctx.drawRoundImage 圆角图片时,创立的本地 base64 显示异样,倡议当环境是 h5 时,将圆角图片限度为一个,或者 uni 动静编译展现 img 标签。

绘制结束后没有成果

留神 DrawPoster.build 无奈检测你所抉择 canvasId 的是否正确,所以肯定要确保与 canvas-idhtml中的 canvas 雷同,在小程序端,因为会主动切换为type2d,必须得加上动静编译。

<!-- #ifdef MP-WEIXIN -->
<canvas id="canvas" type="2d" style="width: 300px; height: 300px" />
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<canvas canvas-id="canvas" id="canvas" style="width: 300px; height: 300px" />
<!-- #endif -->

绘制多个图片加载慢

如果感觉多个图片绘制 await 加载慢,能够应用 Promise.all 将一部分不须要解决图层笼罩的图片进行同步绘制。

dp.draw(async (ctx) => {
  // // 用户头像
  await ctx.drawRoundImage(headImgUrl, 39, 790, 90, 90, 100);
  await Promise.all([ctx.drawImage('/static/logo1.png', 20, 20, 35, 35),
    ctx.drawImage('/static/tp.png', 19, 86, 612, 459),
    ctx.drawImage('/static/bw.png', 188, 559, 274, 50),
    // // 用户二维码
    ctx.drawImage(codeImgUrl, 518, 780, 92, 92),
  ]);
});

须要留神的是:ctx.drawRoundImage不能够放在 Promise.all 当中,因为 ctx.drawRoundImage 外部会调用 ctx.clip 办法,在 Promise.all 中会与其余图片绘制产生抵触。从而导致圆角生效。

我的博客:Mr.Mao’blog

联系方式:951416545@qq.com

正文完
 0