Giter Club home page Giter Club logo

u-draw's Introduction

  • 创建绘制海报canvas矩形方法,内置了图片绘制,圆角矩形绘制,换行字体绘制等方法。

  • 接近原生开发体验,上手快,只需考虑业务逻辑,而不用考虑其他问题。

  • 拥有良好的语法架构,不会在绘制uni/wx矩形时陷入回调地狱。

  • 支持原生小程序,与uniapp多端应用。当是环境为原生小程序时,自动切换为性能更好的type2d绘制方式。

  • 将复杂的逻辑组合为简单的方法,扩展性强,可使用 use|useCtx 引入扩展。

  • 支持typescript,支持vue3模板,具体使用参考 useDraw

  • API 文档:u-draw

  • 插件市场:dcloud/u-draw

⚙️ Install

pnpm add u-draw --dev
# Or Yarn
yarn add u-draw --dev

📖 Usage

template

<!-- #ifdef MP-WEIXIN -->
<canvas id="canvas" type="2d" style="width:100px; height:100px" />
<!-- #endif -->
<!-- #ifndef MP-WEIXIN -->
<canvas canvas-id="canvas" id="canvas" style="width:100px; height:100px" />
<!-- #endif -->
<script setup>
// 注意:如果使用 HBuilder 引入, 需要引入 '../js_sdk'
import { useDraw } from "u-draw"

const { draw, render, create } = useDraw('canvas')
</script>
Vue 2
import { createDraw } from 'u-draw'

export default {
  async onReady() {
    // 传入选择器, 初始化绘制工具(注意, 不需要传入#符号) 当微信小程序时, 将自动启用type2d绘制
    const dp = await createDraw('canvas', {
      width: 100,
      height: 100
    })
  }
}

content

const { draw, render, create, canvas } = useDraw('canvas')
// 绘制背景与文字
draw((ctx) => {
  ctx.fillStyle = '#F4F4F4'
  ctx.fillRect(0, 0, canvas.width, canvas.height)
  ctx.textBaseline = 'top'
  ctx.textAlign = 'start'
  ctx.fillStyle = 'white'
  ctx.font = `bold ${22}px sans-serif`
  ctx.fillText('周先生', canvas.width / 2, 38.5)
})
// 绘制图片内容
draw(async (ctx) => {
  // 拥有异步等待的图片绘制,支持 local、url 等图片类型
  await ctx.drawImage(/* ... */)
})

值得注意的是, draw方法会自动的执行 ctx.save/ctx.restore, 不需要人为操纵绘画栈。

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

render

draw 并不会马上绘制,只是将该任务添加到了任务栈,需要使用 dp.render 函数进行绘制,该函数在绘制完毕后将弹出所有任务。

render 在非 2d 绘画中,执行绘画任务完毕后,将自动执行 ctx.draw 方法,并在 draw 绘画才算异步结束。

draw((ctx) => { /* ... */ })
draw(async (ctx) => { /* ... */ })
// 由于每个任务都有可能会有异步的绘制任务, 所以得需要使用await等待绘制
const result = await render()
// 绘制成功将返回每个任务的绘制状况组成的数组
console.log('draw绘制状况:', result) // draw绘制状况: [ { api: 'drawImage', params: [/* ... */], status: 'success'} ]

当全部同步绘制时,将会出现绘制时间保持不一致的情况。这样就会导致一个问题,绘制图层覆盖导致显示未达到预期效果,之所以设计为异步等待,也是为了绘制图层能保持一致顺序。

image

如需要保存为图片时,可以使用 create 进行创建图片本地地址,在由 wxuniapi 进行保存。

draw(async (ctx) => { /* ... */ })
const result = await render()
const posterImgUrl = await create()
console.log('draw绘制状况:', result)
console.log('绘制生成本地地址:', posterImgUrl) // ...tmp...

你也可以不使用 render 方法,当调用 create 时会自动检测任务列表,如果有则执行绘制任务后在创建地址。

draw(async (ctx) => { /* ... */ })
// 跳过drawPoster.render直接生成地址
const posterImgUrl = await create()
console.log('绘制生成本地地址:', posterImgUrl)

Animation

4.x 版本支持 renderAnimation,支持渲染动画、小程序、H5 默认使用 requestAnimationFrame 渲染:

const { draw, renderAnimation, create, canvas } = useDrawCanvas('canvas')

const w = ref(100)
const h = ref(100)

draw((ctx) => {
  ctx.roundRect(0, 0, w.value, h.value)
})

// 绘制图片内容(在 Animation 中可能存在图片绘制过慢的问题)
draw(async (ctx) => {
  await ctx.drawImage(/* ... */)
})

const stop = renderAnimation(() => {
  width.value--
  if (width.value === 0)
    stop()
})

function onCreate() {
  // 等待 renderAnimation 结束后执行
  const url = await create()
}

u-draw's People

Contributors

hairyf avatar renovate[bot] 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

Watchers

 avatar  avatar

u-draw's Issues

我运行示例项目的第三个demo,报错 "TypeError: Cannot set property 'width' of undefined"

    const dp = createDrawPoster({
      selector: 'canvas',
    })
    dp.mount()
    console.log(dp.canvas) // undefined
    dp.canvas.width = 300
    dp.canvas.height = 300

    dp.draw((ctx) => {
      ctx.fillStyle = '#F4F4F4'
      ctx.fillRect(0, 0, 300, 300)
    })
    // 测试本地/网络地址
    const url = '/static/tabbar/wode.jpg' /* 网络图片 */
    // 测试案例一:绘制图片(矩形)
    dp.draw(async (ctx) => {
      await ctx.drawImage(url, 0, 150, 150, 150)
      await ctx.drawImage(url, 150, 150, 150, 150)
    })
    // 测试案例二:绘制图片(圆角)
    dp.draw(async (ctx) => {
      await ctx.drawRoundImage(url, 0, 0, 150, 150, 100)
      await ctx.drawRoundImage(url, 150, 0, 150, 150, 100)
    })
    // 创建本地地址
    this.imgUrl = await dp.create()
    console.log('创建地址:', { url: this.imgUrl })
  },
}

vite4.3.x uni-app 运行报错

错误信息:[vite]: Rollup failed to resolve import "@uni-helper/uni-env" from "xxx/preset-uni-vue3/node_modules/u-draw/helpers/params.js".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
build.rollupOptions.external

"devDependencies": {
"u-draw": "^4.0.2",
"vite": "^4.3.9"
}

微信小程序ios createImagePath方法没有返回

iphone7、ios12、u-draw-poste1.1.5版本
执行createImagePath方法没有返回
源码中的resolve执行了
image
解决方案:将源码编译为es5就可以了
但是理论应该是对es6语法支持的才对

H5启用摇树优化会报错!!

具体错误如下

API createCanvasContext is not yet implemented

Uncaught (in promise) Error: DrawPoster Error: Use DrawPoster.build(string | ops) to build drawPoster instance objects
at new t (pages-PartnerIntroduction-PartnerIntroduction.741c228b.js:1)
at pages-PartnerIntroduction-PartnerIntroduction.741c228b.js:1
at w (chunk-vendors.be2999e0.js:1)
at Generator._invoke (chunk-vendors.be2999e0.js:1)
at Generator.forEach.t. [as next] (chunk-vendors.be
20210408093840
2999e0.js:1)
at r (chunk-vendors.be2999e0.js:1)
at s (chunk-vendors.be2999e0.js:1)

微信小程序中绘制不出图片

#组件方式引用 在h5 app中都能绘制图片但是在 微信小程序绘制不出图片 的解决方法

image

配置项传入componentThis:this

Failed to set 'font' on 'CanvasContext': invalid format.

[system] Failed to set 'font' on 'CanvasContext': invalid format.
console.log(ctx.font)
好象多了很多空格
normal           bold           22px           sans-serif            at node_modules/u-draw-poster/dist/extends/draw-painter/index.js:35

这样就可以了

ctx.font = [
            `${drawInfo.fontStyle || 'normal'}`,
            `${drawInfo.fontWeight || 'normal'}`,
            `${drawInfo.fontSize || 30}`,
            `${drawInfo.fontFamily || 'serial'}`
          ].join(' ');

苹果端真机调试场景下报错

v1.1.36,直接用你的demo,在开发工具中点“真机调试”然后,扫码测试,
但体验版或发布版又不会报下面错

Unhandled promise rejection TypeError: n.Canvas is not a constructor at t.value (eval at n.call.document (runtime.js?devtools_ignore=true:1), :2:2224602) at t.value (eval at n.call.document (runtime.js?devtools_ignore=true:1), :2:1866342) at A (eval at n.call.document (runtime.js?devtools_ignore=true:1), :2:1866508) at t.value (eval at n.call.document (runtime.js?devtools_ignore=true:1), :2:1866619) at eval (eval at n.call.document (runtime.js?devtoolsignore=true:1), :2:2559099) at new (eval at n.call.document (runtime.js?devtools_ignore=true:1), :2:67394) at ac (eval at n.call.document (runtime.js?devtools_ignore=true:1), :2:2559061) at eval (eval at n.call.document (runtime.js?devtools_ignore=true:1), :2:2560523) at Array.forEach () at n (eval at n.call.document (runtime.js?devtools_ignore=true:1), :2:2560501)

table无法使用await dp.create() ?

你好,我想使用table模块生成一个餐饮小票,最终生成图片。
我从https://ext.dcloud.net.cn/plugin?id=3237 中下载了示例项目。
demo中的table.vue,我看到使用setTimeout包裹dp.create()方法。
image

我尝试将setTimeout替换成文档中的await dp.create(),但是这样基本上就无法预览到生成的canvas了。问题如下这个视频展示:

Screenrecorder-2022-07-05-17-19-44-933.mp4

目前参考demo的代码,暂时使用了setTimeout方法解决。

使用 uni-app的APP端,一直在绘制海报中...

遇到问题是在项目两个页面使用海报生成,商品详情可以成功生成海报,采购详情一直弹窗 在绘制海报中...
插件版本 2.1.0-bate.1
代码:
const dp = await useDrawPoster("canvas", {
debug: true,
loading: true
});
dp.canvas.width = 300;
dp.canvas.height = 250;
dp.draw(async (ctx)=>{
// 设置矩形颜色
ctx.fillStyle = "#fff";
// 进行绘制
ctx.fillRoundRect(0, 0, 300, 405, 0);
});
dp.draw(async (ctx)=>{
const url = "/static/empty/goods-fail.png";
await ctx.drawImage(url, 0, 0, 280, 280);
});
this.imgPath = await dp.createImagePath();

希望大佬们看到后可以帮我解决问题,非常感谢。

探讨:关于小程序绘制模糊的最优解决方法。

关于小程序绘制并生成图片后模糊的解决方法,目前最好的解决方法是当绘制一个600*400的海报,则放大一倍尺寸为1200*800,但这种方法使得每次定义尺寸或者偏移值时,都得计算一遍(num*2)

例如:

    dp.canvas.width = 300 * 2;
    dp.canvas.height = 300 * 2;
    dp.draw((ctx) => {
      ctx.fillStyle = "#fff";
      ctx.fillRect(0, 0, 300 * 2, 300 * 2);
    });

又或者:

    const st2 = (size) => size * 2;
    dp.canvas.width = st2(300);
    dp.canvas.height = st2(300);
    dp.draw((ctx) => {
      ctx.fillStyle = "#fff";
      ctx.fillRect(0, 0, st2(300) st2(300);
    });

在我看来,无论是哪种方法,都使工作量大量的增加,目前有个想法,就是使用Object.defineProperty和来new Proxy动态的修改内容。

例如:

    dp.canvas.width = 300; // dp.canvas.width = 600
    dp.canvas.height = 300;  // dp.canvas.width = 600
    dp.draw((ctx) => {
      ctx.fillStyle = "#fff";
      ctx.fillRect(0, 0, 300, 300);  // ctx.fillRect(0, 0, 600, 600)
    });

但这无疑会增加影响先有api的稳定性,并且在一些特定场景就会出现不合理的情况。

    dp.canvas.width = 300; // dp.canvas.width = 600
    dp.canvas.height = 300;  // dp.canvas.width = 600
    dp.draw((ctx) => {
      ctx.fillStyle = "#fff";
      ctx.fillRect(0, 0, dp.canvas.width, dp.canvas.height);  // ctx.fillRect(0, 0, 1200, 1200)
    });

在此,如何更好的解决图片模糊的问题?

feat: 4.x 具有响应式处理的 useDrawPoster,以及是否抛弃使用 vue2

<!-- 不在提供自动切换 type 2d,用户选择,默认 2d -->
<canvas id="canvas" type="2d" style="width:100px; height:100px" />
import { useDrawPoster } from "use-draw-poster"
// feat: 不在需要 await 等待获取 ctx、canvas 元素
const { draw, render, create, canvas } = useDrawPoster('canvas', {
  type: '2d'
})

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

// 绘制图片内容
draw(async (ctx) => {
  // 拥有异步等待的图片绘制,支持 local、url 等图片类型
  await ctx.drawImage(/* ... */)
})

// 渲染内容
await render()

// 创建图片、可直接跳过 render()、会自动检测绘画栈
const posterImgUrl = await create()

4.x 添加 DrawCavnas 组件(待定)

<template>
  <Canvas id="canvas" width="..." height="..." />
</template>

<script setup>
import { Cavnas, useDrawCanvas  } from "uni-canvas"
const { draw, render, create, canvas } = useDrawCanvas("canvas")
</script>

renderAnimation:

const { draw, renderAnimation, create, canvas } = useDrawCanvas('canvas')

const w = ref(100)
const h= ref(100)

draw((ctx)=> {
  ctx.roundRect(0, 0, w.value, h.value)
})

// 绘制图片内容(在 Animation 中可能存在图片绘制过慢的问题)
draw(async (ctx) => {
  await ctx.drawImage(/* ... */)
})

const stop = renderAnimation(() => {
  width.value--
  if (width.value === 0) {
    stop()
  }
})

// 等待 renderAnimation 结束后执行
await create()

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Rate-Limited

These updates are currently rate-limited. Click on a checkbox below to force their creation now.

  • fix(deps): update dependency archiver to v5.3.2 (archiver, @types/archiver)
  • chore(deps): update dependency @dcloudio/types to v3.4.8
  • chore(deps): update dependency @types/node to v18.19.33
  • chore(deps): update dependency eslint to v8.57.0
  • chore(deps): update dependency miniprogram-api-typings to v3.12.2
  • chore(deps): update dependency eslint to v9
  • fix(deps): update dependency archiver to v7
  • fix(deps): update dependency execa to v9
  • fix(deps): update dependency fs-extra to v11 (fs-extra, @types/fs-extra)
  • fix(deps): update dependency rimraf to v5
  • fix(deps): update dependency slash to v5
  • 🔐 Create all rate-limited PRs at once 🔐

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

npm
package.json
  • archiver ^5.3.1
  • consola ^2.15.3
  • esno ^0.16.3
  • execa ^5.1.1
  • fs-extra ^10.1.0
  • rimraf ^3.0.2
  • slash 3.0.0
  • @antfu/eslint-config ^0.38.4
  • @dcloudio/types ^3.2.11
  • @types/archiver ^5.3.2
  • @types/fs-extra ^9.0.13
  • @types/node ^18.15.11
  • eslint ^8.38.0
  • miniprogram-api-typings ^3.9.1
  • typescript ^4.9.5
  • vitepress 1.0.0-alpha.46
packages/uni-draw/package.json
  • @uni-helper/uni-env ^0.0.2
packages/uni-vue3-vite/package.json

  • Check this box to trigger a request for Renovate to run again on this repository

feat:新的创建方式

<draw-canvas ref="canvas" />
import { useDrawPoster } from 'u-draw-poster'
import DrawCanvas from 'u-draw-poster/component'
const dp = useDrawPoster('canvas')

可能的问题:

  • 要不要放弃支持 vue2
  • 要不要传入 this

hideLoading 关闭时机问题

draw-poster.js 文件里 awaitCreate 函数,createImagePath函数
注意:里面有 2个 resolve(tips);

// 当前绘制为 context 绘制
return await new Promise((resolve) => {
this.ctx.draw(true, () => { // 这个执行时间 可能 会晚于 下面setTimeout,因为每个手机的绘制能力不一
resolve(tips);
this.loading && gbl.hideLoading();
});
// 当环境是app时,ctx.draw 回调不触发, 手动定时器触发
// 没有 执行完 this.ctx.draw 就 resolve(tips); 会导致 this.loading && gbl.showLoading(‘生成图片中...’); 被过早关闭
if (PLATFORM === "app-plus") {
const time = this.ctx.existDrawImage ? this.drawImageTime : 0;
this.ctx.existDrawImage = false;
setTimeout(() => {
resolve(tips);
this.loading && gbl.hideLoading();
}, time);
}
});

2.2.1 版本 vite+vue3 问题汇总

问题1:微信小程序平台 使用vite+vue3 上无法正常使用 提示
image

问题2:H5端dp.createImagePath()方法返回值不是最终绘制的图像,缺少最后绘制的图片元素(已经使用await语法 并没什么用)

问题3: H5端 ctx.drawRoundImage 可以绘制图片但是不能画圆 ,drawImageFit绘制无效果

报bug

感谢您的插件。
2.5.1版本有dp.createImagePath 这个方法不存在。
降级到2.2.1就ok了

HBuilderX 3.1.0 alpha以上会出现 canvas截取不完整

问题描述,及官方回答:
问题反馈地址https://ask.dcloud.net.cn/question/111225
获取canvas的大小,不要用其他元素的大小来替代。另外x、y、width、height、destWidth、destHeight均可缺省。

可以可以下载 HBuilderX 3.1.0 alpha,运行 绘制海拔就可以重现问题

解决方案:
draw-poster.js

const options = Object.assign({ x: 0, y: 0, width: canvas.width, height: canvas.height, destWidth: canvas.width * 2, destHeight: canvas.height * 2 }, baseOptions);

 // 改成
const options = Object.assign({}, baseOptions);

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.