Last active
July 23, 2019 02:57
-
-
Save mutoe/dea1bc18609c1164a30887d3d3f5a7d0 to your computer and use it in GitHub Desktop.
canvas 工具类 (可绘制圆角图片、含有缩放模式的图片绘制)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Canvas 助手方法 | |
*/ | |
export class CanvasUtil { | |
constructor (ctx, canvasWidth, canvasHeight) { | |
this.ctx = ctx | |
this.canvasWidth = canvasWidth | |
this.canvasHeight = canvasHeight | |
return this | |
} | |
/** 绘制圆角裁切区域 */ | |
clipRadius ( | |
/** 绘制区域左上角 x 坐标 */ | |
x, | |
/** 绘制区域左上角 y 坐标 */ | |
y, | |
/** 绘制区域宽 */ | |
width, | |
/** 绘制区域高 */ | |
h, | |
/** 圆角半径 */ | |
radius, | |
/** 在圆角裁切区域内绘制的回调方法 */ | |
callback) { | |
this.ctx.save() | |
this.ctx.beginPath() | |
this.ctx.moveTo(x + radius, y) | |
this.ctx.lineTo(x + width - radius, y) | |
this.ctx.arcTo(x + width, y, x + width, y + radius, radius) | |
this.ctx.lineTo(x + width, y + h - radius) | |
this.ctx.arcTo(x + width, y + h, x + width - radius, y + h, radius) | |
this.ctx.lineTo(x + radius, y + h) | |
this.ctx.arcTo(x, y + h, x, y + h - radius, radius) | |
this.ctx.lineTo(x, y + radius) | |
this.ctx.arcTo(x, y, x + radius, y, radius) | |
this.ctx.closePath() | |
this.ctx.clip() | |
callback() | |
this.ctx.restore() | |
} | |
/** | |
* 绘制图片 | |
* | |
* 可自动按比例缩放图片 | |
* | |
* @param imagePath 图片路径 | |
* @param imageWidth 图片原始宽度 | |
* @param imageHeight 图片原始高度 | |
* @param dx 绘制区域左上角 x 坐标 (相对于 canvas) | |
* @param dy 绘制区域左上角 y 坐标 (相对于 canvas) | |
* @param dw 绘制区域宽度 | |
* @param dh 绘制区域高度 | |
* @param [mode=cover] 填充模式 | |
* - `cover`: 短边优先 (默认) | |
* - `contain`: 长边优先 | |
* - `fill`: 铺满 | |
* @param [align=center] 对齐方式 (只在 `cover` 和 `contain` 模式下有效) | |
* - `center`: 居中 | |
* - `start`: 左/上 | |
* - `end`: 右/下 | |
*/ | |
drawImage (imagePath, imageWidth, imageHeight, dx, dy, dw, dh, mode = 'cover', align = 'center') { | |
/** 裁切区域左上角 x 坐标 */ | |
let sx = 0 | |
/** 裁切区域左上角 y 坐标 */ | |
let sy = 0 | |
/** 裁切区域的宽 */ | |
let sw = imageWidth | |
/** 裁切区域的高 */ | |
let sh = imageHeight | |
/** 原始图片宽高比 */ | |
const imageRatio = imageWidth / imageHeight | |
/** 绘制区域宽高比 */ | |
const drawRatio = dw / dh | |
// 拉伸铺满模式 | |
if (mode === 'fill') { | |
this.ctx.drawImage(imagePath, sx, sy, sw, sh, dx, dy, dw, dh) | |
} | |
// 覆盖模式 | |
else if (mode === 'cover') { | |
if (imageRatio > drawRatio) { | |
const originSWidth = sw | |
sw = sh * drawRatio | |
if (align === 'center') { | |
sx -= (sw - originSWidth) / 2 | |
} else if (align === 'end') { | |
sx -= sw - originSWidth | |
} | |
} else { | |
const originSHeight = sh | |
sh = sw / drawRatio | |
if (align === 'center') { | |
sy -= (sh - originSHeight) / 2 | |
} else if (align === 'end') { | |
sy -= sh - originSHeight | |
} | |
} | |
this.ctx.drawImage(imagePath, sx, sy, sw, sh, dx, dy, dw, dh) | |
} | |
// 包含模式 | |
else if (mode === 'contain') { | |
if (imageRatio > drawRatio) { | |
const originDHeight = dh | |
dh = dw / imageRatio | |
if (align === 'center') { | |
dy += (originDHeight - dh) / 2 | |
} else if (align === 'end') { | |
dy += originDHeight - dh | |
} | |
} else { | |
const originDWidth = dw | |
dw = dh * imageRatio | |
if (align === 'center') { | |
dx += (originDWidth - dw) / 2 | |
} else if (align === 'end') { | |
dx += originDWidth - dw | |
} | |
} | |
this.ctx.drawImage(imagePath, sx, sy, sw, sh, dx, dy, dw, dh) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Canvas 助手方法 | |
*/ | |
export class CanvasUtil { | |
/** 原生 Canvas 上下文对象 */ | |
public ctx: wx.CanvasContext | |
public canvasWidth: number | |
public canvasHeight: number | |
public constructor(ctx: wx.CanvasContext, canvasWidth: number, canvasHeight: number) { | |
this.ctx = ctx | |
this.canvasWidth = canvasWidth | |
this.canvasHeight = canvasHeight | |
return this | |
} | |
/** 绘制圆角裁切区域 */ | |
public clipRadius( | |
/** 绘制区域左上角 x 坐标 */ | |
x: number, | |
/** 绘制区域左上角 y 坐标 */ | |
y: number, | |
/** 绘制区域宽 */ | |
width: number, | |
/** 绘制区域高 */ | |
h: number, | |
/** 圆角半径 */ | |
radius: number, | |
/** 在圆角裁切区域内绘制的回调方法 */ | |
callback: () => void, | |
) { | |
this.ctx.save() | |
this.ctx.beginPath() | |
this.ctx.moveTo(x + radius, y) | |
this.ctx.lineTo(x + width - radius, y) | |
this.ctx.arcTo(x + width, y, x + width, y + radius, radius) | |
this.ctx.lineTo(x + width, y + h - radius) | |
this.ctx.arcTo(x + width, y + h, x + width - radius, y + h, radius) | |
this.ctx.lineTo(x + radius, y + h) | |
this.ctx.arcTo(x, y + h, x, y + h - radius, radius) | |
this.ctx.lineTo(x, y + radius) | |
this.ctx.arcTo(x, y, x + radius, y, radius) | |
this.ctx.closePath() | |
this.ctx.clip() | |
callback() | |
this.ctx.restore() | |
} | |
/** | |
* 绘制图片 | |
* | |
* 可自动按比例缩放图片 | |
* | |
* @param imagePath 图片路径 | |
* @param imageWidth 图片原始宽度 | |
* @param imageHeight 图片原始高度 | |
* @param dx 绘制区域左上角 x 坐标 (相对于 canvas) | |
* @param dy 绘制区域左上角 y 坐标 (相对于 canvas) | |
* @param dw 绘制区域宽度 | |
* @param dh 绘制区域高度 | |
* @param [mode=cover] 填充模式 | |
* - `cover`: 短边优先 (默认) | |
* - `contain`: 长边优先 | |
* - `fill`: 铺满 | |
* @param [align=center] 对齐方式 (只在 `cover` 和 `contain` 模式下有效) | |
* - `center`: 居中 | |
* - `start`: 左/上 | |
* - `end`: 右/下 | |
*/ | |
public drawImage( | |
imagePath: string, | |
imageWidth: number, | |
imageHeight: number, | |
dx: number, | |
dy: number, | |
dw: number, | |
dh: number, | |
mode: 'cover' | 'contain' | 'fill' = 'cover', | |
align: 'start' | 'center' | 'end' = 'center', | |
) { | |
/** 裁切区域左上角 x 坐标 */ | |
let sx = 0 | |
/** 裁切区域左上角 y 坐标 */ | |
let sy = 0 | |
/** 裁切区域的宽 */ | |
let sw = imageWidth | |
/** 裁切区域的高 */ | |
let sh = imageHeight | |
/** 原始图片宽高比 */ | |
const imageRatio = imageWidth / imageHeight | |
/** 绘制区域宽高比 */ | |
const drawRatio = dw / dh | |
// 拉伸铺满模式 | |
if (mode === 'fill') { | |
this.ctx.drawImage(imagePath, sx, sy, sw, sh, dx, dy, dw, dh) | |
} | |
// 覆盖模式 | |
else if (mode === 'cover') { | |
if (imageRatio > drawRatio) { | |
const originSWidth = sw | |
sw = sh * drawRatio | |
if (align === 'center') { | |
sx -= (sw - originSWidth) / 2 | |
} else if (align === 'end') { | |
sx -= sw - originSWidth | |
} | |
} else { | |
const originSHeight = sh | |
sh = sw / drawRatio | |
if (align === 'center') { | |
sy -= (sh - originSHeight) / 2 | |
} else if (align === 'end') { | |
sy -= sh - originSHeight | |
} | |
} | |
this.ctx.drawImage(imagePath, sx, sy, sw, sh, dx, dy, dw, dh) | |
} | |
// 包含模式 | |
else if (mode === 'contain') { | |
if (imageRatio > drawRatio) { | |
const originDHeight = dh | |
dh = dw / imageRatio | |
if (align === 'center') { | |
dy += (originDHeight - dh) / 2 | |
} else if (align === 'end') { | |
dy += originDHeight - dh | |
} | |
} else { | |
const originDWidth = dw | |
dw = dh * imageRatio | |
if (align === 'center') { | |
dx += (originDWidth - dw) / 2 | |
} else if (align === 'end') { | |
dx += originDWidth - dw | |
} | |
} | |
this.ctx.drawImage(imagePath, sx, sy, sw, sh, dx, dy, dw, dh) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment