新增绘制海报组件
This commit is contained in:
78
uni_modules/sakura-canvas/changelog.md
Normal file
78
uni_modules/sakura-canvas/changelog.md
Normal file
@@ -0,0 +1,78 @@
|
||||
## 1.0.33(2021-09-16)
|
||||
修改当绘制文字为空字符串时报x: undefined的问题
|
||||
## 1.0.32(2021-08-10)
|
||||
修改一些绘制问题
|
||||
## 1.0.31(2021-08-05)
|
||||
修改小程序绘制文字时字体加粗影响后面字体的问题
|
||||
## 1.0.30(2021-08-05)
|
||||
外框设置圆角
|
||||
## 1.0.29(2021-08-05)
|
||||
[修改] 安卓上面图片不显示的问题
|
||||
## 1.0.28(2021-08-05)
|
||||
[修改] 安卓上面图片不显示的问题
|
||||
## 1.0.27(2021-08-05)
|
||||
[修改] 安卓上面图片不显示的问题
|
||||
## 1.0.26(2021-07-27)
|
||||
紧急,忘记改方法名称了。
|
||||
## 1.0.25(2021-07-27)
|
||||
[修改] 绘制文字时,callBack ex值的不准缺席
|
||||
[修改] 绘制图片时,当图片为空时一直停留在绘制状态中的问题
|
||||
## 1.0.24(2021-07-22)
|
||||
修改 绘制透明背景的png图片时背景成黑色
|
||||
## 1.0.23(2021-07-22)
|
||||
修改 绘制透明背景的png图片时背景成黑色
|
||||
## 1.0.22(2021-07-22)
|
||||
...
|
||||
## 1.0.21(2021-07-21)
|
||||
...
|
||||
## 1.0.20(2021-07-21)
|
||||
绘制文字添加 lastWidth 属性,用于限制行数的时候,最后一行的宽度
|
||||
绘制矩形,绘制图片添加 borderType属性,用于设置圆角方向
|
||||
## 1.0.19(2021-07-21)
|
||||
绘制文字添加 lastWidth 属性,用于限制行数的时候,最后一行的宽度
|
||||
绘制矩形,绘制图片添加 borderType属性,用于设置圆角方向
|
||||
## 1.0.18(2021-07-10)
|
||||
修复绘制文字传入的内容是Number类型时的错误
|
||||
## 1.0.17(2021-07-01)
|
||||
完善文档
|
||||
## 1.0.16(2021-07-01)
|
||||
添加示例项目
|
||||
## 1.0.15(2021-07-01)
|
||||
添加callBack
|
||||
## 1.0.14(2021-07-01)
|
||||
紧急修复因为疏忽导致的问题
|
||||
修改文档参数
|
||||
## 1.0.13(2021-06-30)
|
||||
修改一些很蠢的问题
|
||||
文字添加首行缩进功能
|
||||
添加绘制海报示例
|
||||
## 1.0.12(2021-06-30)
|
||||
绘制文字添加\n实现自定义换行
|
||||
## 1.0.11(2021-06-29)
|
||||
添加绘制二维码功能
|
||||
添加矩形,圆形,三角形绘制边框功能
|
||||
## 1.0.10(2021-06-28)
|
||||
添加 三角形定点朝向
|
||||
## 1.0.09(2021-06-27)
|
||||
添加图片设置透明度
|
||||
## 1.0.08(2021-06-26)
|
||||
添加实例项目
|
||||
## 1.0.07(2021-06-26)
|
||||
添加使用文档
|
||||
## 1.0.06(2021-06-25)
|
||||
1、添加图片压缩
|
||||
2、添加绘制三角形
|
||||
3、添加绘制三角形图片
|
||||
4、添加图片旋转,矩形旋转。三角形旋转
|
||||
## 1.0.05(2021-06-18)
|
||||
添加图片mode模式
|
||||
## 1.0.04(2021-06-16)
|
||||
[优化] 绘制canvas的的速度
|
||||
## 1.0.03(2021-06-15)
|
||||
使用class重新书写绘制canvas
|
||||
## 1.0.02(2021-06-08)
|
||||
无
|
||||
## 1.0.01(2021-06-08)
|
||||
无
|
||||
## 1.0.0(2021-06-08)
|
||||
无
|
||||
1597
uni_modules/sakura-canvas/js_sdk/draw.js
Normal file
1597
uni_modules/sakura-canvas/js_sdk/draw.js
Normal file
File diff suppressed because it is too large
Load Diff
147
uni_modules/sakura-canvas/js_sdk/image-tools.js
Normal file
147
uni_modules/sakura-canvas/js_sdk/image-tools.js
Normal file
@@ -0,0 +1,147 @@
|
||||
function getLocalFilePath(path) {
|
||||
if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('file://') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('/storage/emulated/0/') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('/') === 0) {
|
||||
var localFilePath = plus.io.convertAbsoluteFileSystem(path)
|
||||
if (localFilePath !== path) {
|
||||
return localFilePath
|
||||
} else {
|
||||
path = path.substr(1)
|
||||
}
|
||||
}
|
||||
return '_www/' + path
|
||||
}
|
||||
|
||||
export function pathToBase64(path) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof window === 'object' && 'document' in window) {
|
||||
if (typeof FileReader === 'function') {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open('GET', path, true)
|
||||
xhr.responseType = 'blob'
|
||||
xhr.onload = function() {
|
||||
if (this.status === 200) {
|
||||
let fileReader = new FileReader()
|
||||
fileReader.onload = function(e) {
|
||||
resolve(e.target.result)
|
||||
}
|
||||
fileReader.onerror = reject
|
||||
fileReader.readAsDataURL(this.response)
|
||||
}
|
||||
}
|
||||
xhr.onerror = reject
|
||||
xhr.send()
|
||||
return
|
||||
}
|
||||
var canvas = document.createElement('canvas')
|
||||
var c2x = canvas.getContext('2d')
|
||||
var img = new Image
|
||||
img.onload = function() {
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
c2x.drawImage(img, 0, 0)
|
||||
resolve(canvas.toDataURL())
|
||||
canvas.height = canvas.width = 0
|
||||
}
|
||||
img.onerror = reject
|
||||
img.src = path
|
||||
return
|
||||
}
|
||||
if (typeof plus === 'object') {
|
||||
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
|
||||
entry.file(function(file) {
|
||||
var fileReader = new plus.io.FileReader()
|
||||
fileReader.onload = function(data) {
|
||||
resolve(data.target.result)
|
||||
}
|
||||
fileReader.onerror = function(error) {
|
||||
reject(error)
|
||||
}
|
||||
fileReader.readAsDataURL(file)
|
||||
}, function(error) {
|
||||
reject(error)
|
||||
})
|
||||
}, function(error) {
|
||||
reject(error)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
|
||||
wx.getFileSystemManager().readFile({
|
||||
filePath: path,
|
||||
encoding: 'base64',
|
||||
success: function(res) {
|
||||
resolve('data:image/png;base64,' + res.data)
|
||||
},
|
||||
fail: function(error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
reject(new Error('not support'))
|
||||
})
|
||||
}
|
||||
|
||||
export function base64ToPath(base64) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof window === 'object' && 'document' in window) {
|
||||
base64 = base64.split(',')
|
||||
var type = base64[0].match(/:(.*?);/)[1]
|
||||
var str = atob(base64[1])
|
||||
var n = str.length
|
||||
var array = new Uint8Array(n)
|
||||
while (n--) {
|
||||
array[n] = str.charCodeAt(n)
|
||||
}
|
||||
return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], { type: type })))
|
||||
}
|
||||
var extName = base64.match(/data\:\S+\/(\S+);/)
|
||||
if (extName) {
|
||||
extName = extName[1]
|
||||
} else {
|
||||
reject(new Error('base64 error'))
|
||||
}
|
||||
var fileName = Date.now() + '.' + extName
|
||||
if (typeof plus === 'object') {
|
||||
var bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||
bitmap.loadBase64Data(base64, function() {
|
||||
var filePath = '_doc/uniapp_temp/' + fileName
|
||||
bitmap.save(filePath, {}, function() {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
}, function(error) {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
}, function(error) {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
|
||||
var filePath = wx.env.USER_DATA_PATH + '/' + fileName
|
||||
wx.getFileSystemManager().writeFile({
|
||||
filePath: filePath,
|
||||
data: base64.replace(/^data:\S+\/\S+;base64,/, ''),
|
||||
encoding: 'base64',
|
||||
success: function() {
|
||||
resolve(filePath)
|
||||
},
|
||||
fail: function(error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
reject(new Error('not support'))
|
||||
})
|
||||
}
|
||||
1088
uni_modules/sakura-canvas/js_sdk/qrcode.js
Normal file
1088
uni_modules/sakura-canvas/js_sdk/qrcode.js
Normal file
File diff suppressed because it is too large
Load Diff
345
uni_modules/sakura-canvas/js_sdk/util.js
Normal file
345
uni_modules/sakura-canvas/js_sdk/util.js
Normal file
@@ -0,0 +1,345 @@
|
||||
// 路径转base64
|
||||
import { base64ToPath } from './image-tools'
|
||||
/**
|
||||
* base64转本地路径
|
||||
* @param { String } path 路径
|
||||
* @returns
|
||||
*/
|
||||
export function base64ToPathFn(path) {
|
||||
let reg =
|
||||
/^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i
|
||||
if (!reg.test(path)) {
|
||||
return Promise.resolve(path)
|
||||
}
|
||||
return base64ToPath(path)
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件资源到本地,客户端直接发起一个 HTTP GET 请求,返回文件的本地临时路径
|
||||
* @param { String } url 资源路径
|
||||
* @param { Object } options 回调
|
||||
* @returns
|
||||
*/
|
||||
export function downloadFile(url, options = {
|
||||
onProgressUpdate: () => {}
|
||||
}) {
|
||||
return new Promise(resolve => {
|
||||
try {
|
||||
let download = uni.downloadFile({
|
||||
url,
|
||||
header: options.header || {},
|
||||
success(res) {
|
||||
return resolve({
|
||||
success: true,
|
||||
data: res
|
||||
})
|
||||
},
|
||||
fail() {
|
||||
return resolve({
|
||||
success: false,
|
||||
message: `下载资源${url}失败`
|
||||
})
|
||||
}
|
||||
})
|
||||
// 下载进度回调
|
||||
download.onProgressUpdate(data => {
|
||||
options.onProgressUpdate(data)
|
||||
})
|
||||
} catch(e) {
|
||||
return resolve({
|
||||
success: false,
|
||||
msg: `下载资源${url}失败`
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载提示框
|
||||
* @param { String } title 提示内容
|
||||
* @param { Boolean } mask 是否显示透明蒙层
|
||||
*/
|
||||
export function showLoading(title, mask = true) {
|
||||
uni.showLoading({
|
||||
title,
|
||||
mask
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭加载提示框
|
||||
*/
|
||||
export function hideLoading() {
|
||||
uni.hideLoading()
|
||||
}
|
||||
|
||||
/**
|
||||
* 不需要确认提示框
|
||||
* @param { String } title 提示内容
|
||||
* @param { Object } options 参数
|
||||
* @param { Stirng } options.icon 提示图片
|
||||
* @param { String || Number } options.duration 时效
|
||||
*/
|
||||
export function showToast(title, options = {}) {
|
||||
uni.showToast({
|
||||
title,
|
||||
icon: options.icon || "none",
|
||||
duration: options.duration || 1500,
|
||||
mask: options.mask || false
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存图片到系统相册。
|
||||
* @param { String } filePath 图片文件路径,可以是临时文件路径也可以是永久文件路径,不支持网络图片路径
|
||||
* @returns
|
||||
*/
|
||||
export function saveImageToPhotosAlbum(filePath) {
|
||||
return new Promise(resolve => {
|
||||
showLoading('保存中...')
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath,
|
||||
success(res) {
|
||||
hideLoading()
|
||||
resolve({
|
||||
success: true,
|
||||
data: res.file
|
||||
})
|
||||
},
|
||||
fail(err) {
|
||||
hideLoading()
|
||||
resolve({
|
||||
success: false,
|
||||
message: err
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算文字长度
|
||||
* @param { CanvasText } Context canvas对象
|
||||
* @param { String } text 文本
|
||||
* @param { String } size 长度
|
||||
* @returns
|
||||
*/
|
||||
export function countTextLength(Context, text, size) {
|
||||
let textLength = 0
|
||||
try {
|
||||
textLength = Context.measureText(text)
|
||||
} catch(e) {
|
||||
textLength = {}
|
||||
}
|
||||
textLength = textLength && textLength.width ? textLength.width : 0
|
||||
if (textLength == 0) {
|
||||
for (let i of text) {
|
||||
textLength += Context.measureText(text)
|
||||
}
|
||||
textLength * size
|
||||
}
|
||||
return textLength
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 压缩图片 H5不支持
|
||||
* @param { Object } params
|
||||
* @param { String } params.src 图片路径,图片的路径,可以是相对路径、临时文件路径、存储文件路径
|
||||
* @param { String } params.quality 压缩质量,范围0~100,数值越小,质量越低,压缩率越高(仅对jpg有效)
|
||||
* @param { String } params.width 缩放图片的宽度,支持像素值(如"100px")、百分比(如"50%")、自动计算(如"auto",即根据height与源图高的缩放比例计算,若未设置height则使用源图高度)
|
||||
* @param { String } params.height 缩放图片的高度,支持像素值(如"100px")、百分比(如"50%")、自动计算(如"auto",即根据height与源图高的缩放比例计算,若未设置height则使用源图高度)
|
||||
* @returns
|
||||
*/
|
||||
export function compressImage(params = {}) {
|
||||
return new Promise(resolve => {
|
||||
uni.compressImage({
|
||||
src: params.src || '',
|
||||
quality: params.quality || 80,
|
||||
width: params.width || 'auto',
|
||||
height: params.height || 'auto',
|
||||
success: res => {
|
||||
resolve({
|
||||
success: true,
|
||||
src: res.tempFilePath
|
||||
})
|
||||
},
|
||||
fail: res => {
|
||||
resolve({
|
||||
success: false,
|
||||
message: '压缩图片失败'
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取图片信息
|
||||
* @param { String } src 图片地址
|
||||
*/
|
||||
export function getImageInfo(src){
|
||||
return new Promise(resolve =>{
|
||||
uni.getImageInfo({
|
||||
src,
|
||||
success: res => {
|
||||
let { path } = res
|
||||
// #ifdef H5
|
||||
let index = path.lastIndexOf('.', path.length)
|
||||
let type = ''
|
||||
if (index != -1) {
|
||||
type = path.substring(index + 1, path.length)
|
||||
} else {
|
||||
type = 'png'
|
||||
}
|
||||
res.type = type
|
||||
// #endif
|
||||
resolve({
|
||||
success: true,
|
||||
...res
|
||||
})
|
||||
},
|
||||
fail: e => {
|
||||
resolve({
|
||||
success: false,
|
||||
msg: e
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取使用模式的图片信息
|
||||
* @param { String | Number } oWidth 原图宽度
|
||||
* @param { String | Number } oHeight 原图高度
|
||||
* @param { String | Number } x x轴位置
|
||||
* @param { String | Number } y y轴位置
|
||||
* @param { String | Number } width 宽度
|
||||
* @param { String | Number } height 高度
|
||||
* @param { String } mode 模式
|
||||
* aspectFit 保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。
|
||||
* aspectFill 保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。
|
||||
* widthFix 宽度不变,高度自动变化,保持原图宽高比不变
|
||||
* heightFix 高度不变,宽度自动变化,保持原图宽高比不变
|
||||
*/
|
||||
export function getModeImage(oWidth, oHeight, x, y, width, height, mode) {
|
||||
if (mode == 'aspectFit') {
|
||||
return getAspectFitModelInfo(oWidth, oHeight, x, y, width, height)
|
||||
}
|
||||
|
||||
if (mode == 'aspectFill') {
|
||||
return getAspectFillModelInfo(oWidth, oHeight, x, y, width, height)
|
||||
}
|
||||
|
||||
if (mode == 'widthFix') {
|
||||
return getWidthFixModelInfo(oWidth, oHeight, x, y, width, height)
|
||||
}
|
||||
|
||||
if (mode == 'heightFix') {
|
||||
return getHeightFixModelInfo(oWidth, oHeight, x, y, width, height)
|
||||
}
|
||||
|
||||
if (mode == 'default') {
|
||||
return {
|
||||
dw: width,
|
||||
dh: height,
|
||||
dx: x,
|
||||
dy: y
|
||||
}
|
||||
}
|
||||
return getAspectFillModelInfo(oWidth, oHeight, x, y, width, height)
|
||||
}
|
||||
|
||||
|
||||
// aspectFit 保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。
|
||||
function getAspectFitModelInfo(oWidth, oHeight, x, y, width, height) {
|
||||
let aspect = oHeight / oWidth
|
||||
let sw = width
|
||||
let sh = aspect * sw
|
||||
if (aspect > 1) {
|
||||
aspect = oWidth / oHeight
|
||||
sh = height
|
||||
sw = aspect * sh
|
||||
}
|
||||
return {
|
||||
sw,
|
||||
sh,
|
||||
sx: x,
|
||||
sy: y,
|
||||
dw: oWidth,
|
||||
dh: oHeight,
|
||||
dx: 0,
|
||||
dy: 0
|
||||
}
|
||||
}
|
||||
|
||||
// 保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。
|
||||
function getAspectFillModelInfo(oWidth, oHeight, x, y, width, height) {
|
||||
// 高比宽大 宽是短边
|
||||
let aspect = oHeight / oWidth
|
||||
let sw = width
|
||||
let sh = aspect * sw
|
||||
let dx = 0
|
||||
let dy = (sh - height) / 2
|
||||
if (aspect < 1) {
|
||||
// 高比宽小 高是短边
|
||||
aspect = oWidth / oHeight
|
||||
sh = height
|
||||
sw = aspect * sh
|
||||
dy = 0
|
||||
dx = (sw - width) / 2
|
||||
}
|
||||
return {
|
||||
sw,
|
||||
sh,
|
||||
sx: x,
|
||||
sy: y,
|
||||
dw: oWidth,
|
||||
dh: oHeight,
|
||||
dx,
|
||||
dy
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 宽度不变,高度自动变化,保持原图宽高比不变
|
||||
function getWidthFixModelInfo(oWidth, oHeight, x, y, width, height) {
|
||||
let aspect = oHeight / oWidth
|
||||
let sw = width
|
||||
let sh = sw * aspect
|
||||
let dx = 0
|
||||
let dy = 0
|
||||
return {
|
||||
sw,
|
||||
sh,
|
||||
sx: x,
|
||||
sy: y,
|
||||
dw: oWidth,
|
||||
dh: oHeight,
|
||||
dx,
|
||||
dy
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 高度不变,宽度自动变化,保持原图宽高比不变
|
||||
function getHeightFixModelInfo(oWidth, oHeight, x, y, width, height) {
|
||||
let aspect = oWidth / oHeight
|
||||
let sh = height
|
||||
let sw = sh * aspect
|
||||
let dx = 0
|
||||
let dy = 0
|
||||
return {
|
||||
sw,
|
||||
sh,
|
||||
sx: x,
|
||||
sy: y,
|
||||
dw: oWidth,
|
||||
dh: oHeight,
|
||||
dx,
|
||||
dy
|
||||
}
|
||||
}
|
||||
83
uni_modules/sakura-canvas/package.json
Normal file
83
uni_modules/sakura-canvas/package.json
Normal file
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "sakura-canvas",
|
||||
"displayName": "canvas绘制海报(分享图) ",
|
||||
"version": "1.0.33",
|
||||
"description": "支持JSON格式绘制海报。内置拥有许多的封装方法,便于你更快绘制",
|
||||
"keywords": [
|
||||
"uni_modules",
|
||||
"canvas",
|
||||
"绘制海报",
|
||||
"分享图"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"JS SDK",
|
||||
"通用 SDK"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "n"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "y",
|
||||
"QQ": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
478
uni_modules/sakura-canvas/readme.md
Normal file
478
uni_modules/sakura-canvas/readme.md
Normal file
@@ -0,0 +1,478 @@
|
||||
# sakura-canvas(海报生成器)
|
||||
|
||||
|
||||
|
||||
# 用前需知:
|
||||
|
||||
## 1、小程序绘制时,记得配置图片的域名为安全域名(白名单)
|
||||
|
||||
## 2、兼容性。目前只测试过APP(不包括NVUE页面), 微信小程序, H5, 字节跳动小程序。其他小程序未测。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 引入
|
||||
|
||||
```javascript
|
||||
import Draw from '@/uni_modules/sakura-canvas/js_sdk/draw'
|
||||
```
|
||||
|
||||
|
||||
|
||||
# 使用教程
|
||||
|
||||
|
||||
|
||||
## 初始化
|
||||
|
||||
```javascript
|
||||
let draw = new Draw({
|
||||
width: 375, // canvas(海报)的宽度 必填
|
||||
height: 500, // canvas(海报)的高度 必填
|
||||
canvasId: 'myCanvas', // canvasId 必填
|
||||
_this: this, // 传入this实例 必填
|
||||
background: {
|
||||
type: 'color', // 背景样式 color: 纯色 image: 图片
|
||||
color: '#fffff',
|
||||
// color: 参数详看绘制矩形的参数
|
||||
// image: 详看绘制图片时的参数
|
||||
}, // 背景 默认纯白,
|
||||
drawDelayTime: 200, // 绘制海报时的延迟时间(单位毫秒),默认200,
|
||||
delayTime: 200, // 导出图片时的延迟时间(单位毫秒),默认200,
|
||||
fileType: 'png', // 导出图片的类型, 默认png 可选jpg, png
|
||||
quality: 1, // 导出图片的质量, 默认1 值范围0~1, 大于一都为1处理
|
||||
drawTipsText: '绘制中...', // 绘制时的加载提示, 默认绘制中...
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Draw类内置方法大纲
|
||||
|
||||
|
||||
|
||||
# 非Json方式绘制
|
||||
|
||||
## 绘制文本-text
|
||||
|
||||
# !!!注意绘制文本添加使用\n实现自定义换行
|
||||
|
||||
```javascript
|
||||
// 绘制文字
|
||||
draw.drawText({
|
||||
x: 0, // x轴方向 默认 0
|
||||
y: 0, // y轴方向 默认 0
|
||||
w: 100, // 文字宽度 默认整个画布的宽度 - x轴的距离
|
||||
text: '你好\n世界', // 文字内容
|
||||
textIndent: 0, // 文字首行缩进 默认0 注意在设置了windowAlign或者textAlign的时候会失去作用
|
||||
font: {
|
||||
size: 12, // 文字大小 默认12
|
||||
family: '微软雅黑', // 文字字体 默认sans-serif
|
||||
style: 'normal', // 文字样式 默认 normal 可选: italic: 斜体 oblique: 倾斜体
|
||||
weight: 'normal' // 文字粗体 默认 normal 可传递 bold: 粗体 数字
|
||||
},
|
||||
line: {
|
||||
num: -1, // 限制文字行数,默认 -1: 不限制 限制行数,多出部分会变成...
|
||||
height: 16, // 行高默认16
|
||||
style: 'none', // 样式 默认none: 不需要 可选 underline: 下划线, lineThrough 删除线
|
||||
type: 'solid', // 线类型 当使用样式时线的类型 默认: solid 实线 可选: dashed 虚线
|
||||
width: 1, // 线宽度 默认1
|
||||
},
|
||||
color: '#000000', // 文字颜色 默认#000000 在不考虑字节跳动小程序的前提下可简写(#000)
|
||||
alpha: 1, // 透明度 默认1 取值范围 0~1
|
||||
isFill: true, // 是否是填充字体, false: 线性字体
|
||||
windowAlign: 'none', // 文字在窗口(整个画布的宽度)对齐的方式 默认: none 可选 居中: center 右边: right
|
||||
textAlign: 'none', // 文字水平对齐的方式 默认: none 可选 居中: center 右边: right
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 绘制矩形-rect
|
||||
|
||||
```javascript
|
||||
// 绘制矩形
|
||||
draw.drawRect({
|
||||
x: 0, // x轴方向 默认 0
|
||||
y: 0, // y轴方向 默认 0
|
||||
w: 100, // 宽度 必填
|
||||
h: 100, // 高度 必填
|
||||
r: 0, // 矩形圆角大小 默认: 0
|
||||
color: '#000000', // 颜色 默认#000000 在不考虑字节跳动小程序的前提下可简写(#000)
|
||||
alpha: 1, // 透明度 默认1 取值范围 0~1
|
||||
isFill: true, // 是否是填充矩形, false: 线性矩形
|
||||
lineWidth: 1, // 当矩形为线性时,矩形的边框宽度
|
||||
windowAlign: 'none', // 矩形在窗口(整个画布的宽度)对齐的方式 默认: none 可选 居中: center 右边: right
|
||||
// 旋转
|
||||
rotate: {
|
||||
deg: 0, // 旋转角度
|
||||
type: 'middle', // 旋转的中心点 默认: middle: 矩形正中心
|
||||
// topLeft: 中心点在上左 topMiddle 中心点在上中 topRight 中心点在上右
|
||||
// middleLeft: 中心点在中左 bottomMiddle 中心点在正中间 middleRight 中心点在中右
|
||||
// bottomLeft: 中心点在下左 bottomMiddle 中心点在下中 middleRight 中心点在下右
|
||||
},
|
||||
borderWidth: 0, // 边框大小 默认0 (类型为填充矩形时生效)
|
||||
borderColor: '#ffffff', // 边框颜色 默认无颜色 (类型为填充矩形时生效)
|
||||
// 圆角的方向
|
||||
// 值类型为数组, 添加不同的圆角方向设置哪里是圆角哪里不是圆角
|
||||
// 参数可选值 tr: 上右; tl: 上左; bl:左下; br: 左右; default: 全圆角
|
||||
borderType: ['tr', 'tl'] // 默认全圆角['default']
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 绘制圆-arc
|
||||
|
||||
```javascript
|
||||
// 绘制圆
|
||||
draw.drawArc({
|
||||
x: 0, // x轴方向 默认 0
|
||||
y: 0, // y轴方向 默认 0
|
||||
r: 100, // 圆半径 必填
|
||||
s: 0, // 画圆的起始角度
|
||||
e: Math.PI * 2, // 画圆的终止角度
|
||||
d: false, // 指定弧度的方向是逆时针还是顺时针。默认是false,即顺时针。
|
||||
color: '#000000', // 颜色 默认#000000 在不考虑字节跳动小程序的前提下可简写(#000)
|
||||
alpha: 1, // 透明度 默认1 取值范围 0~1
|
||||
isFill: true, // 是否是填充圆, false: 线性圆
|
||||
lineWidth: 1, // 当圆为线性时,圆的边框宽度
|
||||
windowAlign: 'none', // 圆在窗口(整个画布的宽度)对齐的方式 默认: none 可选 居中: center 右边: right
|
||||
borderWidth: 0, // 边框大小 默认0 (类型为填充圆时生效)
|
||||
borderColor: '#ffffff' // 边框颜色 默认无颜色 (类型为填充圆时生效)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 绘制三角形-triangle
|
||||
|
||||
```javascript
|
||||
// 绘制三角形
|
||||
draw.drawTriangle({
|
||||
x: 0, // x轴方向 默认 0
|
||||
y: 0, // y轴方向 默认 0
|
||||
w: 100, // 宽度 必填
|
||||
h: 100, // 高度 必填
|
||||
r: 0, // 矩形圆角大小 默认: 0
|
||||
color: '#000000', // 颜色 默认#000000 在不考虑字节跳动小程序的前提下可简写(#000)
|
||||
alpha: 1, // 透明度 默认1 取值范围 0~1
|
||||
isFill: true, // 是否是填充三角形, false: 线性三角形
|
||||
lineWidth: 1, // 当三角形为线性时,三角形的边框宽度
|
||||
drawType: 'isosceles', // 绘制的三角形类型 默认 isosceles: 等腰三角形 right: 直角三角形 custom: 自定义自定义时,x, y, 宽, 高都不需要传递。需要传递绘制点的坐标类型是数组(coordinate)
|
||||
// 三角形定点朝向 top, left, right, bottom (只在等腰三角形和直角三角形里生效,自定义绘制不生效)
|
||||
direction: params.direction || 'top',
|
||||
coordinate: [], // 当绘制类别是自定义的时候需要传递的参数[[x1, y1], [x2, y2], [x3, y3]]
|
||||
windowAlign: 'none', // 三角形在窗口(整个画布的宽度)对齐的方式 默认: none 可选 居中: center 右边: right (并且三角形类型不能为自定义)
|
||||
// 旋转
|
||||
rotate: {
|
||||
deg: 0, // 旋转角度
|
||||
type: 'middle', // 旋转的中心点 默认: middle: 三角形正中心
|
||||
// top: 上 left: 左 right: 右 middle: 中心
|
||||
},
|
||||
borderWidth: 0, // 边框大小 默认0 (类型为填充三角形时生效)
|
||||
borderColor: '#ffffff' // 边框颜色 默认无颜色 (类型为填充三角形时生效)
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 绘制线条-line
|
||||
|
||||
```javascript
|
||||
// 绘制线条
|
||||
draw.drawLine({
|
||||
x: 0, // x轴方向 默认 0
|
||||
y: 0, // y轴方向 默认 0
|
||||
w: 100, // 宽度 默认整个画布的宽度 - x轴的距离
|
||||
color: '#000000', // 颜色 默认#000000 在不考虑字节跳动小程序的前提下可简写(#000)
|
||||
alpha: 1, // 透明度 默认1 取值范围 0~1
|
||||
lineType: 'solid', // 线条类型 默认 solid: 实线 可选 dashed: 虚线
|
||||
pattern: [5, 5], // 当线条类型为虚线是生效,具体详看CanvasContext.setLineDash文档
|
||||
offset: 5, // 虚线偏移量 默认: 5
|
||||
lineWidth: 1, // 线条高度
|
||||
lineCap: 'butt', // 线条端点样式 默认 butt 可选 round, square
|
||||
windowAlign: 'none', // 线条在窗口(整个画布的宽度)对齐的方式 默认: none 可选 居中: center 右边: right
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 绘制图片-image
|
||||
|
||||
```javascript
|
||||
// 绘制图片
|
||||
await draw.drawImage({
|
||||
x: 0, // x轴方向 默认 0
|
||||
y: 0, // y轴方向 默认 0
|
||||
w: 100, // 图片宽度 必填
|
||||
h: 100, // 图片高度 必填
|
||||
r: 0, // 当图片样式为矩形时, 圆角的大小
|
||||
alpha: 1, // 透明度 默认1 取值范围 0~1
|
||||
src: '/static/logo.png', // 图片资源路径 必填 网络路径(小程序中需要配置白名单),本地路径, base64(使用base64格式绘制速度会稍微慢点,在IOS端显著。)
|
||||
mode: 'aspectFill', // 图片模式 默认 aspectFill 可选 aspectFit, widthFix, heightFix
|
||||
drawType: 'default', // 图片样式 default: 默认 rect: 矩形, arc: 圆形 triangle: 三角形
|
||||
triangle: {
|
||||
type: 'isosceles', // 三角形的类型 right: 直角三角形 isosceles: 等腰三角形 custom: 自定义三角形(不支持旋转)
|
||||
coordinate: [], // 自定义时传递, [[x1, y1], [x2, y2], [x3, y3]],
|
||||
triangle: 'top', // 三角形顶点朝向
|
||||
}, // 绘制三角形时传递
|
||||
borderWidth: 0, // 图片边框大小
|
||||
borderColor: '#ffffff', // 图片边框颜色
|
||||
// 图片圆角的方向
|
||||
// 值类型为数组, 添加不同的圆角方向设置哪里是圆角哪里不是圆角
|
||||
// 参数可选值 tr: 上右; tl: 上左; bl:左下; br: 左右; default: 全圆角
|
||||
borderType: ['tr', 'tl'], // 默认全圆角['default']
|
||||
windowAlign: 'none', // 图片在窗口(整个画布的宽度)对齐的方式 默认: none 可选 居中: center 右边: right
|
||||
quality: 80, // 压缩图片的质量 默认 80 值范围0~100
|
||||
rotate: {}, // 旋转 具体可看绘制矩形和绘制三角形中的属性值
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 绘制二维码
|
||||
|
||||
```javascript
|
||||
// 绘制二维码
|
||||
draw.drawQrCode({
|
||||
x: 0, // x轴方向 默认 0
|
||||
y: 0, // y轴方向 默认 0
|
||||
size: 100, // 二维码的大小 默认100
|
||||
text: '', // 二维码内容 默认''
|
||||
background: '#000000', // 二维码背景色 默认#00000
|
||||
foreground: '#ffffff', // 二维码前景色 默认#fffff
|
||||
pdground: '#ffffff', // 二维码角标色 默认 #fffff
|
||||
lv: 3, // 容错级别(一般不需要调它) 默认值是3
|
||||
windowAlign: 'none', // 二维码在窗口(整个画布的宽度)对齐的方式 默认: none 可选 居中: center 右边: right
|
||||
// 二维码中间的图片 可选
|
||||
image: {
|
||||
src: '/static/logo.png', //网络路径(小程序中需要配置白名单),本地路径, base64(使用base64格式绘制速度会稍微慢点,在IOS端显著。)
|
||||
size: 30, // 图片大小 默认 30
|
||||
r: 0, // 图片圆角 默认 0
|
||||
borderWidth: 0, // 图片边框大小 默认0
|
||||
borderColor: '#ffffff' // 图片边框颜色 默认无颜色
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 自定义绘制-custom
|
||||
|
||||
### 具体详看Context文档 [点我跳转](https://uniapp.dcloud.io/api/canvas/CanvasContext)
|
||||
|
||||
```javascript
|
||||
// 自定义绘制
|
||||
draw.Context.fillText('你好', 0, 200)
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 将通过以上方法绘制的内容绘制到画板上
|
||||
|
||||
```javascript
|
||||
// complete 是否导出图片,默认 true会绘制图片并返回图片路径 false时需要自行调用uni.canvasToTempFilePath()方法导出图片
|
||||
await draw.canvasDraw(complete)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Json方式绘制内容(推荐使用Json方式绘制)
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
// bgObj: 背景大小含有背景宽高
|
||||
// ctxObj: 画布大小含有画布宽高
|
||||
// res接收参数格式
|
||||
// res.success: 是否成功 true: 成功 false: 失败
|
||||
// res.message: 成功或者失败时的信息
|
||||
// res.data: 成功时绘制的图片路径
|
||||
let res = await draw.createdSharePoster(({ bgObj, ctxObj }) => {
|
||||
let data = [
|
||||
// 绘制文字
|
||||
{
|
||||
name: '', // 用于在callBack中寻找
|
||||
type: 'text',
|
||||
// callBack: 用于知道上一次绘制的内容具体的数据
|
||||
// before: 上一次绘制的内容的数据,当你绘制的内容处于第一个则是一个空对象
|
||||
// all: 所有绘制内容的数据
|
||||
callBack: (before, all) => {
|
||||
let { sx, sy, ex, ey, w, h } = before
|
||||
// sx: 上一次绘制内容开始的x轴位置
|
||||
// sy: 上一次绘制内容开始的y轴位置
|
||||
// ex: 上一次绘制内容结束的x轴位置
|
||||
// ey: 上一次绘制内容结束的y轴位置
|
||||
// w: 上一次绘制内容的宽度
|
||||
// h: 上一次绘制内容的高度
|
||||
// callBack 返回的对象会覆盖原属性
|
||||
return {
|
||||
x: sx,
|
||||
y: sy
|
||||
}
|
||||
}
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawText 方法的参数
|
||||
},
|
||||
// 绘制矩形
|
||||
{
|
||||
type: 'rect',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawRect 方法的参数
|
||||
},
|
||||
// 绘制圆
|
||||
{
|
||||
type: 'arc',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawArc 方法的参数
|
||||
},
|
||||
// 绘制三角形
|
||||
{
|
||||
type: 'triangle',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawTriangle 方法的参数
|
||||
},
|
||||
// 绘制线条
|
||||
{
|
||||
type: 'line',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawLine 方法的参数
|
||||
},
|
||||
// 绘制图片
|
||||
{
|
||||
type: 'image',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawImage 方法的参数
|
||||
},
|
||||
// 绘制二维码
|
||||
{
|
||||
type: 'qrcode',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawQrCode 方法的参数
|
||||
},
|
||||
// 自定义绘制
|
||||
{
|
||||
type: 'custom',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// Context: 调用原生方法绘制
|
||||
// _this: 调用draw类的内置方法绘制
|
||||
setDarw(Context, _this) {
|
||||
// 原生方法绘制
|
||||
Context.fillText('你好', 0, 200)
|
||||
// 使用draw类内置方法绘制
|
||||
_this.drawText({
|
||||
x: 0,
|
||||
y: 0,
|
||||
text: '你好, 世界'
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
return data
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# 绘制时,需要提前绘制一部分内容,然后后面等数据有了在绘制一部分内容的需求
|
||||
|
||||
|
||||
|
||||
```javascript
|
||||
// 初始化
|
||||
let draw = new Draw({
|
||||
width: 375, // canvas(海报)的宽度,
|
||||
height: 500, // canvas(海报)的高度,
|
||||
canvasId: 'myCanvas', // canvasId 必填
|
||||
_this: this, // 传入this实例 必填
|
||||
drawDelayTime: 200, // 绘制海报时的延迟时间(单位毫秒),默认200,
|
||||
delayTime: 200, // 导出图片时的延迟时间(单位毫秒),默认200,
|
||||
fileType: 'png', // 导出图片的类型, 默认png 可选jpg, png
|
||||
quality: 1, // 导出图片的质量, 默认1 值范围0~1, 大于一都为1处理
|
||||
drawTipsText: '绘制中...', // 绘制时的加载提示, 默认绘制中...
|
||||
})
|
||||
// 预绘制需要自行调用绘制背景
|
||||
await draw.preDrawBackground()
|
||||
// draw.preDraw(drawArray), complete)
|
||||
// 参数
|
||||
// drawArray: 参数如下
|
||||
// complete: 是否绘制完成,绘制完成会自行导出图片 默认false
|
||||
// 返回值
|
||||
// res接收参数格式
|
||||
// res.success: 是否成功 true: 成功 false: 失败
|
||||
// res.message: 成功或者失败时的信息
|
||||
// res.data: 成功时绘制的图片路径
|
||||
let res = await draw.preDraw(({ bgObj, ctxObj }) => {
|
||||
let data = [
|
||||
// 绘制文字
|
||||
{
|
||||
type: 'text',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawText 方法的参数
|
||||
},
|
||||
// 绘制矩形
|
||||
{
|
||||
type: 'rect',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawRect 方法的参数
|
||||
},
|
||||
// 绘制圆
|
||||
{
|
||||
type: 'arc',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawArc 方法的参数
|
||||
},
|
||||
// 绘制三角形
|
||||
{
|
||||
type: 'triangle',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawTriangle 方法的参数
|
||||
},
|
||||
// 绘制线条
|
||||
{
|
||||
type: 'line',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawLine 方法的参数
|
||||
},
|
||||
// 绘制图片
|
||||
{
|
||||
type: 'image',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawImage 方法的参数
|
||||
},
|
||||
// 绘制二维码
|
||||
{
|
||||
type: 'qrcode',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// 参数详看draw.drawQrCode 方法的参数
|
||||
},
|
||||
// 自定义绘制
|
||||
{
|
||||
type: 'custom',
|
||||
zIndex: 0, // 绘制顺序 越小越先绘制
|
||||
// Context: 调用原生方法绘制
|
||||
// _this: 调用draw类的内置方法绘制
|
||||
setDarw(Context, _this) {
|
||||
// 原生方法绘制
|
||||
Context.fillText('你好', 0, 200)
|
||||
// 使用draw类内置方法绘制
|
||||
_this.drawText({
|
||||
x: 0,
|
||||
y: 0,
|
||||
text: '你好, 世界'
|
||||
})
|
||||
}
|
||||
}
|
||||
]
|
||||
return data
|
||||
})
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user