Commit 5b16ae67 authored by rockyl's avatar rockyl

作用dpr

parent 2588c85c
......@@ -60,15 +60,15 @@ export function parseDom(el: HTMLElement = document.body) {
break;
}
if(!bound && childNode.getBoundingClientRect){
if (!bound && childNode.getBoundingClientRect) {
bound = childNode.getBoundingClientRect();
}
let styles = getStylesWithoutDefaults(node || childNode);
if (!isText) {
for(let skey of commonStyleKeys){
if(commonStyleKeys.indexOf(skey) < 0){
for (let skey of commonStyleKeys) {
if (commonStyleKeys.indexOf(skey) < 0) {
continue
}
......
......@@ -2,47 +2,48 @@
* 转换接口数据
*/
interface ICData {
width: number,
height: number,
nodes: INodeData[]
width: number,
height: number,
nodes: INodeData[]
}
/**
* 节点类型
*/
enum NodeType {
ANY = 0,
TEXT,
IMAGE,
CANVAS,
ANY = 0,
TEXT,
IMAGE,
CANVAS,
}
/**
* 节点数据
*/
interface INodeData {
type: NodeType,
x: number,
y: number,
width: number,
height: number,
//图片需要
src?: string,
borderRadius?: string,
img?: HTMLImageElement,//加载后挂上的
//文本需要
text?: string
color?: string,
fontSize?: string,//文本字号
fontWeight?: string,//文本粗细
wordWrap?: "break-word" | null
textAlign?: "center" | "left" | "right"
fontStyle?: "normal" | "italic" | "oblique"
type: NodeType,
x: number,
y: number,
width: number,
height: number,
//图片需要
src?: string,
borderRadius?: string,
img?: HTMLImageElement,//加载后挂上的
//文本需要
text?: string
color?: string,
fontSize?: string,//文本字号
fontWeight?: string,//文本粗细
wordWrap?: "break-word" | null
textAlign?: "center" | "left" | "right"
fontStyle?: "normal" | "italic" | "oblique"
}
export interface RenderOptions {
type?: 'canvas' | 'jpeg' | 'png',
quality?: number,
scale?: number,
type?: 'canvas' | 'jpeg' | 'png',
quality?: number,
}
/**
......@@ -53,153 +54,172 @@ export interface RenderOptions {
* @return Promise<HTMLCanvasElement | string>
*/
export async function toCanvas(data: ICData, options: RenderOptions = {}, callback?: (canvas: HTMLCanvasElement) => void): Promise<HTMLCanvasElement | string> {
const { type: exportType = 'png', quality = 0.7 } = options;
const {type: exportType = 'png', quality = 0.7} = options;
let {scale = window['devicePixelRatio'] || 1} = options;
const { nodes, width, height } = data;
let canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
//先加载完所有图片
let p: Promise<void>[] = [];
nodes.forEach((n) => {
if (n.type !== NodeType.IMAGE) return;
p.push(
new Promise((r) => {
let img = new Image();
img.crossOrigin = 'anonymous'
img.onload = () => {
n.img = img;
r()
}
img.src = n.src;
})
)
})
if (p.length) await Promise.all(p);
nodes.forEach((n) => {
switch (n.type) {
case NodeType.IMAGE:
case NodeType.CANVAS:
drawImage(n, ctx)
break
case NodeType.TEXT:
drawText(n, ctx)
break
}
})
let {nodes, width, height} = data;
width *= scale;
height *= scale;
let result: any = canvas;
switch (exportType) {
case 'jpeg':
case 'png':
result = canvas.toDataURL('image/' + exportType, quality);
break;
}
let canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
//先加载完所有图片
let p: Promise<void>[] = [];
nodes.forEach((n) => {
if (n.type !== NodeType.IMAGE) return;
p.push(
new Promise((r) => {
let img = new Image();
img.crossOrigin = 'anonymous'
img.onload = () => {
n.img = img;
r()
}
img.src = n.src;
})
)
})
if (p.length) await Promise.all(p);
nodes.forEach((n) => {
switch (n.type) {
case NodeType.IMAGE:
case NodeType.CANVAS:
drawImage(n, ctx, scale)
break
case NodeType.TEXT:
drawText(n, ctx, scale)
break
}
})
callback && callback(result)
return result
let result: any = canvas;
switch (exportType) {
case 'jpeg':
case 'png':
result = canvas.toDataURL('image/' + exportType, quality);
break;
}
callback && callback(result)
return result
}
/**
* 绘制图片
* @param data
* @param ctx
* @param scale
*/
function drawImage(data: INodeData, ctx: CanvasRenderingContext2D) {
const { x, y, img, width, height, borderRadius } = data;
if (borderRadius) {//有圆角,画遮罩,暂时只管一个
ctx.save();
let max = (width < height ? width : height) / 2;
let radius = Math.min(+borderRadius.replace("px", ""), max);
// ctx.beginPath();
// ctx.moveTo(x, y + radius);
// ctx.quadraticCurveTo(x, y, x + radius, y);
// ctx.lineTo(x + width - radius, y);
// ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
// ctx.lineTo(x + width, y + height - radius);
// ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
// ctx.lineTo(x + radius, y + height);
// ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
// ctx.lineTo(x, y + radius);
// ctx.clip();
ctx.beginPath();
ctx.moveTo(x + width - radius, y);
ctx.arcTo(x + width, y, x + width, y + radius, radius)
ctx.lineTo(x + width, y + height - radius)
ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius)
ctx.lineTo(x + radius, y + height)
ctx.arcTo(x, y + height, x, y + height - radius, radius)
ctx.lineTo(x, y + radius)
ctx.arcTo(x, y, x + radius, y, radius)
ctx.closePath();
ctx.clip();
}
ctx.drawImage(img, x, y, width, height)
if (borderRadius) ctx.restore();
function drawImage(data: INodeData, ctx: CanvasRenderingContext2D, scale: number) {
let {x, y, img, width, height, borderRadius: borderRadiusTxt} = data;
x *= scale;
y *= scale;
width *= scale;
height *= scale;
let borderRadius = parseFloat(borderRadiusTxt) * scale;
if (borderRadius) {//有圆角,画遮罩,暂时只管一个
ctx.save();
let max = (width < height ? width : height) / 2;
let radius = Math.min(borderRadius, max);
// ctx.beginPath();
// ctx.moveTo(x, y + radius);
// ctx.quadraticCurveTo(x, y, x + radius, y);
// ctx.lineTo(x + width - radius, y);
// ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
// ctx.lineTo(x + width, y + height - radius);
// ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
// ctx.lineTo(x + radius, y + height);
// ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
// ctx.lineTo(x, y + radius);
// ctx.clip();
ctx.beginPath();
ctx.moveTo(x + width - radius, y);
ctx.arcTo(x + width, y, x + width, y + radius, radius)
ctx.lineTo(x + width, y + height - radius)
ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius)
ctx.lineTo(x + radius, y + height)
ctx.arcTo(x, y + height, x, y + height - radius, radius)
ctx.lineTo(x, y + radius)
ctx.arcTo(x, y, x + radius, y, radius)
ctx.closePath();
ctx.clip();
}
ctx.drawImage(img, x, y, width, height)
if (borderRadius) ctx.restore();
}
/**
* 绘制文本,暂时没那么复杂,不用离屏玩
* @param data
* @param ctx
* @param scale
*/
function drawText(data: INodeData, ctx: CanvasRenderingContext2D) {
const {
x, y, width, height,
text,
color,
fontSize,
fontWeight,
fontStyle,
wordWrap,
textAlign
} = data;
let font = fontSize;
font += " Arial";//字体没有
//font-weight:bold;font-style:italic;
if (fontWeight) font = fontWeight + " " + font;
if (fontStyle) font = fontStyle + " " + font;
function drawText(data: INodeData, ctx: CanvasRenderingContext2D, scale: number) {
let {
x, y, width, height,
text,
color,
fontSize: fontSizeTxt,
fontWeight,
fontStyle,
wordWrap,
textAlign
} = data;
x *= scale;
y *= scale;
width *= scale;
height *= scale;
let fontSize = parseFloat(fontSizeTxt) * scale;
let font = fontSize + 'px';
font += " Arial";//字体没有
//font-weight:bold;font-style:italic;
if (fontWeight) font = fontWeight + " " + font;
if (fontStyle) font = fontStyle + " " + font;
ctx.font = font;
ctx.textBaseline = "top";
ctx.fillStyle = color;
let widthAll = ctx.measureText(text).width;
// console.log(ctx.measureText(text))
//超过宽度需要换行,且需要用到居中方式
if (wordWrap == "break-word" && widthAll > width) {
let realLines = [];
let w = ctx.measureText(text[0]).width;
let lineStr = text[0];
let wordW = 0;
let strLen = text.length;
for (let j = 1; j < strLen; j++) {
wordW = ctx.measureText(text[j]).width;
w += wordW;
if (w > width) {
realLines[realLines.length] = lineStr;
lineStr = text[j];
w = wordW;
} else {
lineStr += text[j];
}
}
//最后一行
realLines[realLines.length] = lineStr;
ctx.textAlign = textAlign || "left";
let tx = 0;
if (ctx.textAlign == "center") {
tx = width * 0.5;
} else if (ctx.textAlign == "right") {
tx = width;
}
//有待考虑.现在直接拿高度取平均算每行高度
let lineH = height / realLines.length;
realLines.forEach((r, i) => {
ctx.fillText(r, x + tx, y + i * lineH)
})
} else {
ctx.textAlign = "left"
ctx.fillText(text, x, y)
}
ctx.font = font;
ctx.textBaseline = "top";
ctx.fillStyle = color;
let widthAll = ctx.measureText(text).width;
// console.log(ctx.measureText(text))
//超过宽度需要换行,且需要用到居中方式
if (wordWrap == "break-word" && widthAll > width) {
let realLines = [];
let w = ctx.measureText(text[0]).width;
let lineStr = text[0];
let wordW = 0;
let strLen = text.length;
for (let j = 1; j < strLen; j++) {
wordW = ctx.measureText(text[j]).width;
w += wordW;
if (w > width) {
realLines[realLines.length] = lineStr;
lineStr = text[j];
w = wordW;
} else {
lineStr += text[j];
}
}
//最后一行
realLines[realLines.length] = lineStr;
ctx.textAlign = textAlign || "left";
let tx = 0;
if (ctx.textAlign == "center") {
tx = width * 0.5;
} else if (ctx.textAlign == "right") {
tx = width;
}
//有待考虑.现在直接拿高度取平均算每行高度
let lineH = height / realLines.length;
realLines.forEach((r, i) => {
ctx.fillText(r, x + tx, y + i * lineH)
})
} else {
ctx.textAlign = "left"
ctx.fillText(text, x, y)
}
}
......@@ -40,10 +40,11 @@
<img class="avatar" src="//yun.duiba.com.cn/aurora/14e3d0fa0e1ff54553a2c8c094b1caffd90f0a43.png"/>
<canvas id="canvas" style="position: absolute; left: 10px; top: 10px;"></canvas>
<p class="ppp">
a<br/>bcde<span style="background-color: rgba(0,255,0,0.5);">span</span>fghij
a<br/>bcdefghij
</p>
</div>
<!--
<span style="background-color: rgba(0,255,0,0.5);">span</span>-->
<script>
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
......
......@@ -36,6 +36,7 @@ interface INodeData {
fontStyle?: "normal" | "italic" | "oblique";
}
export interface RenderOptions {
scale?: number;
type?: 'canvas' | 'jpeg' | 'png';
quality?: number;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment