| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620 |
- import { SPaintEngine } from "./SPaintEngine";
- import {
- SBrushType,
- SFont,
- SGradientStop,
- SLine,
- SLinearGradient,
- SLineCapStyle,
- SPaintEngineType,
- SPoint,
- SRadialGradient,
- SRect,
- STextAlign,
- STextBaseLine,
- STextDirection
- } from "..";
- import { SPath2D } from "../SPath2D";
- /**
- * 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;
- } // Get type
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // 构造函数
- /**
- * 构造函数
- *
- * @param canvas canvas对象
- */
- constructor(canvas: CanvasRenderingContext2D) {
- super();
- this._canvas = canvas;
- this._canvas.imageSmoothingEnabled = true;
- // this._canvas.imageSmoothingQuality;
- } // Constructor()
- // =================================================================================================================
- // 绘制图形
- /**
- * 设置裁剪路径
- *
- * @param path 裁剪路径
- */
- setClip(path: Path2D): void {
- this.setMatrix();
- // this._canvas.stroke(path);
- this._canvas.fill(path);
- this._canvas.clip();
- } // Function setClip()
- /**
- * 清空矩形区域
- *
- * @param rect 矩形
- */
- clearRect(rect: SRect): void {
- this.setMatrix();
- this._canvas.clearRect(rect.x, rect.y, rect.width, rect.height);
- } // Function clearRect()
- /**
- * 绘制空心矩形
- *
- * @param rect 矩形
- */
- drawRect(rect: SRect): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- this._canvas.fillRect(rect.x, rect.y, rect.width, rect.height);
- this._canvas.strokeRect(rect.x, rect.y, rect.width, rect.height);
- } // Function drawRect()
- /**
- * 绘制圆形
- *
- * @param cx 圆心X坐标
- * @param cy 圆心X坐标
- * @param r 圆半径
- */
- drawCircle(cx: number, cy: number, r: number): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- this._canvas.beginPath();
- this._canvas.arc(cx, cy, r, 0, 2 * Math.PI, true);
- this._canvas.fill();
- this._canvas.stroke();
- } // Function drawCircle()
- /**
- * 绘制椭圆
- *
- * @param cx 圆点X坐标
- * @param cy 圆点Y坐标
- * @param rx 水平半径
- * @param ry 垂直半径
- */
- drawEllipse(cx: number, cy: number, rx: number, ry: number): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- this._canvas.beginPath();
- this._canvas.ellipse(cx, cy, rx, ry, 0.5, 0, 2 * Math.PI, true);
- } // Function drawEllipse()
- /**
- * 绘制椭圆弧
- *
- * @param x 椭圆所在矩形X坐标
- * @param y 椭圆所在矩形Y坐标
- * @param width 椭圆所在矩形宽度
- * @param height 椭圆所在矩形高度
- * @param startAngle 开始角度(单位弧度)
- * @param endAngle 结束角度(单位弧度)
- */
- drawArc(
- x: number,
- y: number,
- width: number,
- height: number,
- startAngle: number,
- endAngle: number
- ): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- let p = SPath2D.arc(x, y, width, height, startAngle, endAngle);
- let path = new Path2D(
- SPath2D.arc(x, y, width, height, startAngle, endAngle)
- );
- this._canvas.stroke(path);
- } // Function drawArc()
- /**
- * 绘制椭圆弦弧
- *
- * @param x 椭圆所在矩形X坐标
- * @param y 椭圆所在矩形Y坐标
- * @param width 椭圆所在矩形宽度
- * @param height 椭圆所在矩形高度
- * @param startAngle 开始角度(单位弧度)
- * @param endAngle 结束角度(单位弧度)
- */
- drawChord(
- x: number,
- y: number,
- width: number,
- height: number,
- startAngle: number,
- endAngle: number
- ): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- let path = new Path2D(
- SPath2D.chord(x, y, width, height, startAngle, endAngle)
- );
- this._canvas.fill(path);
- this._canvas.stroke(path);
- } // Function drawChord()
- /**
- * 绘制椭圆饼
- *
- * @param x 椭圆所在矩形X坐标
- * @param y 椭圆所在矩形Y坐标
- * @param width 椭圆所在矩形宽度
- * @param height 椭圆所在矩形高度
- * @param startAngle 开始角度(单位弧度)
- * @param endAngle 结束角度(单位弧度)
- */
- drawPie(
- x: number,
- y: number,
- width: number,
- height: number,
- startAngle: number,
- endAngle: number
- ): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- let path = new Path2D(
- SPath2D.pie(x, y, width, height, startAngle, endAngle)
- );
- this._canvas.fill(path);
- this._canvas.stroke(path);
- } // Function drawPie()
- /**
- * 绘制线段
- *
- * @param line 线段
- */
- drawLine(line: SLine): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- this._canvas.beginPath();
- this._canvas.moveTo(line.x1, line.y1);
- this._canvas.lineTo(line.x2, line.y2);
- this._canvas.stroke();
- } // Function drawLine()
- /**
- * 绘制折线
- *
- * @param points 折线折点
- */
- drawPolyline(points: SPoint[]): void {
- // 折线至少要有2个节点
- if (points.length < 2) {
- return;
- }
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- 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();
- } // Function drawPolyline()
- /**
- * 绘制多边形
- *
- * @param points 多边形顶点
- */
- drawPolygon(points: SPoint[]): void {
- // 多边形至少要有3个节点
- if (points.length < 3) {
- return;
- }
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- 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();
- } // Function drawPolygon()
- /**
- * 绘制路径
- *
- * @param path 路径
- */
- drawPath(path: SPath2D): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setComposite();
- this.setShadow();
- this._canvas.fill(path._path);
- this._canvas.stroke(path._path);
- } // Function drawPath()
- /**
- * 绘制文本
- *
- * @param text 文本内容
- * @param x X坐标
- * @param y Y坐标
- * @param maxWidth 最大宽度
- */
- drawText(text: string, x: number, y: number, maxWidth?: number): void {
- this.setMatrix();
- this.setPen();
- this.setBrush();
- this.setFont();
- this.setComposite();
- this.setShadow();
- if (maxWidth == undefined) {
- this._canvas.fillText(text, x, y);
- } else {
- this._canvas.fillText(text, x, y, maxWidth);
- }
- } // Function drawText()
- /**
- * 绘制图片
- *
- * @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.setMatrix();
- 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);
- }
- } // Function drawImage()
- /**
- * 预测量文本宽度
- *
- * @param text 预测的文本
- * @return 文本长度像素
- * */
- textWidth(text: string): number {
- return this._canvas.measureText(text).width;
- } // Function textWidth()
- // /**
- // * 绘制带导角空心矩形
- // *
- // * @param x X坐标
- // * @param y Y坐标
- // * @param w 宽度
- // * @param h 高度
- // * @param r 导角半径
- // */
- // drawRoundedRect(x: number, y: number, w: number, h: number, r: number): void {
- // this.canvas.beginPath();
- // this.canvas.moveTo(x, y + r);
- // this.canvas.lineTo(x, y + h - r);
- // this.canvas.quadraticCurveTo(x, y + h, x + r, y + h);
- // this.canvas.lineTo(x + w - r,y + h);
- // this.canvas.quadraticCurveTo(x + w, y + h, x + w, y + h - r);
- // this.canvas.lineTo(x + w, y + r);
- // this.canvas.quadraticCurveTo(x + w, y, x + w - r, y);
- // this.canvas.lineTo(x + r, y);
- // this.canvas.quadraticCurveTo(x, y, x,y + r);
- // this.canvas.fill();
- // this.canvas.stroke();
- // } // Function drawRoundedRect()
- /**
- * 设置字体
- *
- * @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);
- } // Function changeFont()
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // 私有函数
- /**
- * 设置画笔
- */
- private setPen(): void {
- //this._canvas.strokeStyle = this.state.pen.color.value;
- 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);
- } // Function setPen()
- /**
- * 线段端点风格
- *
- * @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";
- }
- } // Set lineCapStyle
- /**
- * 设置画刷
- */
- private setBrush(): void {
- // this._canvas.fillStyle = this.state.brush.color.value;
- 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
- );
- }
- // @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;
- }
- }
- } // Function setBrush()
- /**
- * 设置融合
- */
- private setComposite(): void {
- this._canvas.globalCompositeOperation =
- SCanvasPaintEngine.gcoList[this.state._composite];
- } // Function setComposite()
- /**
- * 设置阴影
- */
- 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;
- }
- } // Function setShadow()
- /**
- * 设置字体
- */
- 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);
- } // Function setFont()
- /**
- * 文本对齐选项
- *
- * @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";
- }
- } // Function setTextAlign()
- /**
- * 设置文本基线对齐选项
- *
- * @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";
- }
- } // Set textBaseLine()
- /**
- * 设置文本方向选项
- *
- * @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";
- }
- } // Set textDirection
- /**
- * 设置变型矩阵
- */
- 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
- );
- } // Function setMatrix()
- } // class SPaintEngine
|