123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665 |
- /*
- * *********************************************************************************************************************
- *
- * !!
- * .F88X
- * X8888Y
- * .}888888N;
- * i888888N; .:! .I$WI:
- * R888888I .'N88~ i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
- * .R888888I .;N8888~ .X8' "8I.!,/8" !%NY8`"8I8~~8>,88I
- * +888888N; .8888888Y "&&8Y.}8,
- * ./888888N; .R888888Y .'}~ .>}'.`+> i}! "i' +/' .'i~ !11,.:">, .~]! .i}i
- * ~888888%: .I888888l .]88~`1/iY88Ii+1'.R$8$8]"888888888> Y8$ W8E X8E W8888'188Il}Y88$*
- * 18888888 E8888881 .]W%8$`R8X'&8%++N8i,8N%N8+l8%` .}8N:.R$RE%N88N%N$K$R 188,FE$8%~Y88I
- * .E888888I .i8888888' .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
- * 8888888I .,N888888~ ~88i"8W,!N8*.I88.}888%F,i$88"F88" 888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
- * i888888N' I888Y ]88;/EX*IFKFK88X K8R .l8W 88Y ~88}'88E&%8W.X8N``]88!.$8K .:W8I
- * .i888888N; I8Y .&8$ .X88! i881.:%888>I88 ;88] +88+.';;;;:.Y88X 18N.,88l .+88/
- * .:R888888I
- * .&888888I Copyright (c) 2009-2020. 博锐尚格科技股份有限公司
- * ~8888'
- * .!88~ All rights reserved.
- *
- * *********************************************************************************************************************
- */
- import { SPaintEngine } from "./SPaintEngine";
- import {
- SBrushType,
- SFont,
- SGradientStop,
- SLine,
- SLinearGradient,
- SLineCapStyle,
- SPaintEngineType,
- SPoint,
- SRadialGradient,
- SRect,
- STextAlign,
- STextBaseLine,
- STextDirection
- } from "..";
- import { SPath } from "../SPath";
- /**
- * Canvas 绘制引擎基类
- *
- * @author 庞利祥 <sybotan@126.com>
- */
- export class SCanvasPaintEngine extends SPaintEngine {
- /** 画布对象 */
- private readonly _canvas: CanvasRenderingContext2D;
- /** 融合类型 */
- static gcoList = [
- "copy",
- "destination-atop",
- "destination-in",
- "destination-out",
- "destination-over",
- "lighter",
- "source-atop",
- "source-in",
- "source-out",
- "source-over",
- "xor"
- ];
- /**
- * 绘制引擎类型
- *
- * @return 返回 Canvas 绘制引擎类型
- */
- get type(): SPaintEngineType {
- return SPaintEngineType.Canvas;
- }
- /**
- * 构造函数
- *
- * @param canvas canvas对象
- */
- constructor(canvas: CanvasRenderingContext2D) {
- super();
- this._canvas = canvas;
- this._canvas.imageSmoothingEnabled = true;
- }
- /**
- * 清空矩形区域
- *
- * @param rect 矩形
- */
- clearRect(rect: SRect): void {
- this.setMatrix();
- this._canvas.clearRect(rect.x, rect.y, rect.width, rect.height);
- }
- /**
- * 绘制矩形
- *
- * @param rect 矩形
- */
- drawRect(rect: SRect): void {
- this.init((): void => {
- this._canvas.beginPath();
- this._canvas.rect(rect.x, rect.y, rect.width, rect.height);
- this._canvas.stroke();
- this._canvas.fill();
- });
- }
- /**
- * 绘制圆形
- *
- * @param cx 圆心 x 坐标
- * @param cy 圆心 y 坐标
- * @param r 圆半径
- */
- drawCircle(cx: number, cy: number, r: number): void {
- this.init((): void => {
- this._canvas.beginPath();
- this._canvas.arc(cx, cy, r, 0, 2 * Math.PI, true);
- this._canvas.fill();
- this._canvas.stroke();
- });
- }
- /**
- * 绘制椭圆
- *
- * @param cx 圆点 X 坐标
- * @param cy 圆点 Y 坐标
- * @param rx 水平半径
- * @param ry 垂直半径
- */
- drawEllipse(cx: number, cy: number, rx: number, ry: number): void {
- this.init((): void => {
- this._canvas.beginPath();
- this._canvas.ellipse(cx, cy, rx, ry, 0, 0, 2 * Math.PI, true);
- this._canvas.fill();
- this._canvas.stroke();
- });
- }
- /**
- * 绘制线段
- *
- * @param line 线段
- */
- drawLine(line: SLine): void {
- this.init((): void => {
- this._canvas.beginPath();
- this._canvas.moveTo(line.x1, line.y1);
- this._canvas.lineTo(line.x2, line.y2);
- this._canvas.stroke();
- });
- }
- /**
- * 绘制折线
- *
- * @param points 折线折点
- */
- drawPolyline(points: SPoint[]): void {
- // 折线至少要有2个节点
- if (points.length < 2) {
- return;
- }
- this.init((): void => {
- this._canvas.beginPath();
- this._canvas.moveTo(points[0].x, points[0].y);
- // 遍历折线折点数组,绘制折线
- for (let p of points) {
- this._canvas.lineTo(p.x, p.y);
- }
- this._canvas.stroke();
- });
- }
- /**
- * 绘制多边形
- *
- * @param points 多边形顶点
- */
- drawPolygon(points: SPoint[]): void {
- // 多边形至少要有3个节点
- if (points.length < 3) {
- return;
- }
- this.init((): void => {
- this._canvas.beginPath();
- this._canvas.moveTo(points[0].x, points[0].y);
- // 遍历顶点数组,绘制折线
- for (let p of points) {
- this._canvas.lineTo(p.x, p.y);
- }
- this._canvas.closePath();
- this._canvas.fill();
- this._canvas.stroke();
- });
- }
- /**
- * 绘制路径
- *
- * @param path 路径
- */
- drawPath(path: SPath): void {
- this.init((): void => {
- this.drawWay(path);
- });
- }
- /**
- * 绘制文本
- *
- * @param text 文本内容
- * @param x X 坐标
- * @param y Y 坐标
- * @param maxWidth 最大宽度
- */
- drawText(text: string, x: number, y: number, maxWidth?: number): void {
- this.init((): void => {
- this.setFont();
- // 不传最大宽度时,绘制时不限制最大宽度
- if (maxWidth == undefined) {
- this._canvas.strokeText(text, x, y);
- this._canvas.fillText(text, x, y);
- } else { // 绘制时限制最大宽度
- this._canvas.strokeText(text, x, y, maxWidth);
- this._canvas.fillText(text, x, y, maxWidth);
- }
- });
- }
- /**
- * 绘制图片
- *
- * @param img 图片
- * @param x X 坐标
- * @param y Y 坐标
- * @param width 宽度
- * @param height 高度
- */
- drawImage(
- img: CanvasImageSource,
- x: number,
- y: number,
- width?: number,
- height?: number
- ): void {
- this.init((): void => {
- try {
- // 不传宽度时,绘制图片不限制宽高
- if (width == undefined) {
- this._canvas.drawImage(img, x, y);
- } else { // 绘制时限制图片宽高
- this._canvas.drawImage(img, x, y, width, height as number);
- }
- } catch (e) { // 捕获 获取图片异常
- console.log(e);
- }
- });
- }
- /**
- * 预测量文本宽度
- *
- * @param text 预测的文本
- * @return 文本长度像素
- */
- textWidth(text: string): number {
- return this._canvas.measureText(text).width;
- }
- /**
- * 绘制二次贝塞尔曲线
- *
- * @param cp1x 控制点 X 坐标
- * @param cp1y 控制点 Y 坐标
- * @param x 结束点 X 坐标
- * @param y 结束点 Y 坐标
- */
- quadraticCurveTo(cp1x: number, cp1y: number, x: number, y: number): void {
- this._canvas.quadraticCurveTo(cp1x, cp1y, x, y);
- }
- /**
- * 绘制三次贝塞尔曲线
- *
- * @param cp1x 起始点控制点 X 坐标
- * @param cp1y 起始点控制点 Y 坐标
- * @param cp2x 结束点控制点 X 坐标
- * @param cp2y 结束点控制点 Y 坐标
- * @param x 结束点X坐标
- * @param y 结束点Y坐标
- */
- bezierCurveTo(
- cp1x: number,
- cp1y: number,
- cp2x: number,
- cp2y: number,
- x: number,
- y: number
- ): void {
- this._canvas.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
- }
- /**
- * 绘制带导角空心矩形
- *
- * @param rect 矩形
- * @param r 导角半径
- */
- drawRoundRect(rect: SRect, r: number): void {
- this.init((): void => {
- this._canvas.beginPath();
- this._canvas.moveTo(rect.x, rect.y + r);
- this._canvas.lineTo(rect.x, rect.bottom - r);
- this._canvas.quadraticCurveTo(
- rect.x,
- rect.bottom,
- rect.x + r,
- rect.bottom
- );
- this._canvas.lineTo(rect.right - r, rect.bottom);
- this._canvas.quadraticCurveTo(
- rect.right,
- rect.bottom,
- rect.right,
- rect.bottom - r
- );
- this._canvas.lineTo(rect.right, rect.y + r);
- this._canvas.quadraticCurveTo(
- rect.right,
- rect.y,
- rect.right - r,
- rect.y
- );
- this._canvas.lineTo(rect.x + r, rect.y);
- this._canvas.quadraticCurveTo(rect.x, rect.y, rect.x, rect.y + r);
- this._canvas.fill();
- this._canvas.stroke();
- });
- }
- /**
- * 设置字体
- *
- * @param font 字体
- */
- changeFont(font: SFont): void {
- this._canvas.font = `${font.size}px ${font.name}`;
- this.setTextAlign(font.textAlign);
- this.setBaseLine(font.textBaseLine);
- this.setTextDirection(font.textDirection);
- }
- /**
- * 设置整体绘制状态
- *
- * @param fn 绘制图形的具体函数
- */
- private init(fn: Function): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- this.setClip();
- fn();
- }
- /**
- * 设置画笔
- */
- private setPen(): void {
- this._canvas.strokeStyle = `rgba(${this.state.pen.color.red}, ${
- this.state.pen.color.green
- }, ${this.state.pen.color.blue}, ${this.state.pen.color.alpha /
- 255.0})`;
- this._canvas.lineWidth = this.state.pen.lineWidth;
- this._canvas.miterLimit = this.state.pen.miterLimit;
- // 设定了画笔的虚线样式
- if (this.state.pen.lineDash != null) {
- this._canvas.setLineDash(this.state.pen.lineDash);
- this._canvas.lineDashOffset = this.state.pen.dashOffset;
- } else { // 没有设定画笔的虚线样式
- this._canvas.setLineDash([]);
- this._canvas.lineDashOffset = 0;
- }
- this.setLineCapStyle(this.state.pen.lineCapStyle);
- }
- /**
- * 线段端点风格
- *
- * @param style 风格
- */
- private setLineCapStyle(style: SLineCapStyle): void {
- // 没有设定风格
- if (style == undefined) {
- return;
- }
- // 圆头
- if (style == SLineCapStyle.Round) {
- this._canvas.lineCap = "round";
- } else if (style == SLineCapStyle.Square) { // 方头
- this._canvas.lineCap = "square";
- } else { // 平头
- this._canvas.lineCap = "butt";
- }
- }
- /**
- * 设置画刷
- */
- private setBrush(): void {
- // 实心画刷
- if (this.state.brush.type == SBrushType.Color) {
- this._canvas.fillStyle = `rgba(${this.state.brush.color.red}, ${
- this.state.brush.color.green
- }, ${this.state.brush.color.blue}, ${this.state.brush.color.alpha /
- 255.0})`;
- } else if (this.state.brush.type == SBrushType.Gradient) { // 渐变画刷
- let gradient = this.state.brush.gradient,
- drawGradient: CanvasGradient;
- // 线性渐变画刷
- if (gradient instanceof SLinearGradient) {
- drawGradient = this._canvas.createLinearGradient(
- gradient.x1,
- gradient.y1,
- gradient.x2,
- gradient.y2
- );
- } else if (gradient instanceof SRadialGradient) { // 径向渐变画刷
- drawGradient = this._canvas.createRadialGradient(
- gradient.x1,
- gradient.y1,
- gradient.r1,
- gradient.x2,
- gradient.y2,
- gradient.r2
- );
- }
- // TODO:建龙补充
- // @ts-ignore
- if (gradient && drawGradient) {
- gradient.stopList.forEach((t: SGradientStop): void => {
- drawGradient.addColorStop(
- t.pos,
- `rgba(${t.color.red},${t.color.green},${
- t.color.blue
- },${t.color.alpha / 255.0})`
- );
- });
- this._canvas.fillStyle = drawGradient;
- }
- }
- }
- /**
- * 设置融合
- */
- private setComposite(): void {
- this._canvas.globalCompositeOperation =
- SCanvasPaintEngine.gcoList[this.state._composite];
- }
- /**
- * 设置阴影
- */
- private setShadow(): void {
- // 存在阴影扩散距离和阴影颜色
- if (this.state.shadow.shadowBlur > 0 && this.state.shadow.shadowColor) {
- this._canvas.shadowBlur = this.state.shadow.shadowBlur;
- this._canvas.shadowColor = `rgba(${
- this.state.shadow.shadowColor.red
- },${this.state.shadow.shadowColor.green}, ${
- this.state.shadow.shadowColor.blue
- }, ${this.state.shadow.shadowColor.alpha / 255.0})`;
- this._canvas.shadowOffsetX = this.state.shadow.shadowOffsetX;
- this._canvas.shadowOffsetY = this.state.shadow.shadowOffsetY;
- } else { // 否则
- this._canvas.shadowBlur = 0;
- this._canvas.shadowColor = "";
- this._canvas.shadowOffsetX = 0;
- this._canvas.shadowOffsetY = 0;
- }
- }
- /**
- * 设置字体
- */
- private setFont(): void {
- this._canvas.font = `${this.state.font.size}px ${this.state.font.name}`;
- this.setTextAlign(this.state.font.textAlign);
- this.setBaseLine(this.state.font.textBaseLine);
- this.setTextDirection(this.state.font.textDirection);
- }
- /**
- * 文本对齐选项
- *
- * @param value 对齐方式
- */
- private setTextAlign(value: STextAlign): void {
- // 不设置对齐方式时
- if (value == undefined) {
- return;
- }
- // 文本在指定的位置开始
- if (value === STextAlign.Start) {
- this._canvas.textAlign = "start";
- } else if (value === STextAlign.End) { // 文本在指定的位置结束
- this._canvas.textAlign = "end";
- } else if (value === STextAlign.Left) { // 左对齐
- this._canvas.textAlign = "left";
- } else if (value === STextAlign.Center) { // 文本的中心被放置在指定的位置
- this._canvas.textAlign = "center";
- } else { // 右对齐
- this._canvas.textAlign = "right";
- }
- }
- /**
- * 设置文本基线对齐选项
- *
- * @param value 对齐方式
- */
- private setBaseLine(value: STextBaseLine): void {
- if (value == undefined) {
- return;
- }
- if (value == STextBaseLine.Alphabetic) {
- this._canvas.textBaseline = "alphabetic";
- } else if (value == STextBaseLine.Top) {
- this._canvas.textBaseline = "top";
- } else if (value == STextBaseLine.Hanging) {
- this._canvas.textBaseline = "hanging";
- } else if (value == STextBaseLine.Middle) {
- this._canvas.textBaseline = "middle";
- } else if (value == STextBaseLine.Ideographic) {
- this._canvas.textBaseline = "ideographic";
- } else {
- this._canvas.textBaseline = "bottom";
- }
- }
- /**
- * 设置文本方向选项
- *
- * @param value 文本方向
- */
- private setTextDirection(value: STextDirection): void {
- if (value == undefined) {
- return;
- }
- if (value == STextDirection.Inherit) {
- this._canvas.direction = "inherit";
- } else if (value == STextDirection.LTR) {
- this._canvas.direction = "ltr";
- } else {
- this._canvas.direction = "rtl";
- }
- }
- /**
- * 设置变型矩阵
- */
- private setMatrix(): void {
- this._canvas.setTransform(
- this.state.matrix.a,
- this.state.matrix.b,
- this.state.matrix.c,
- this.state.matrix.d,
- this.state.matrix.e,
- this.state.matrix.f
- );
- }
- /**
- * 设置裁剪路径
- *
- */
- setClip(): void {
- if (this.state.clip) {
- this.drawWay(this.state.clip);
- this._canvas.clip();
- }
- }
- /**
- * 绘制路径
- *
- */
- private drawWay(path: SPath): void {
- this._canvas.beginPath();
- path.cmdList.forEach((cmd): void => {
- if (cmd.command == "L") {
- this._canvas.lineTo(cmd.args[0], cmd.args[1]);
- } else if (cmd.command == "M") {
- this._canvas.moveTo(cmd.args[0], cmd.args[1]);
- } else if (cmd.command == "Z") {
- this._canvas.closePath();
- } else if (cmd.command == "Q") {
- this._canvas.quadraticCurveTo(
- cmd.args[0],
- cmd.args[1],
- cmd.args[2],
- cmd.args[3]
- );
- } else if (cmd.command == "T") {
- // @ts-ignore
- this._canvas.bezierCurveTo(
- cmd.args[0],
- cmd.args[1],
- cmd.args[2],
- cmd.args[3],
- cmd.args[4]
- );
- } else if (cmd.command == "Ellipse") {
- this._canvas.ellipse(
- cmd.args[0],
- cmd.args[1],
- cmd.args[2],
- cmd.args[3],
- 0,
- 0,
- Math.PI * 2
- );
- } else if (cmd.command == "Arc") {
- this._canvas.arc(
- cmd.args[0],
- cmd.args[1],
- cmd.args[2],
- cmd.args[3],
- cmd.args[4],
- cmd.args[5] == 1
- );
- } else if (cmd.command == "ArcTo") {
- this._canvas.arcTo(
- cmd.args[0],
- cmd.args[1],
- cmd.args[2],
- cmd.args[3],
- cmd.args[4]
- );
- }
- });
- this._canvas.fill();
- this._canvas.stroke();
- }
- }
|