首页 > 其他分享 >Canvas 封装

Canvas 封装

时间:2024-03-12 10:55:34浏览次数:27  
标签:Canvas 封装 option number let canvas ._ public

Canvas 封装

记录一个Canvas封装,这个是给小程序用的,html可以直接用html2canvas,且不说小程序有没有对应的东西,小程序这原生的东西对于第三方框架都不一定有用,毕竟小程序就是一坨,用不了带document的东西,啥新特性都没有,还一堆bug不修

这里使用的是Taro vue3 typescript,用别的框架把Taro相关的东西改掉就行
直接搞一个工具类出来

export class Canvas2DHelper
{

}

创建离屏Canvas

离屏Canvas在小程序里面跟正常的Canvas的api基本一致,但是在html里面区别蛮大的,我这里是给小程序用的,自己注意

/**
 * 创建离屏canvas
 * @param width 宽
 * @param height 高
 * @returns 
 */
public static CreateOffscreenCanvas(width: number = 0, height: number = 0): Taro.OffscreenCanvas
{
    let canvas: Taro.OffscreenCanvas = Taro.createOffscreenCanvas({
        type: "2d",
    });

    return canvas;
}

保存和读取

基本操作,首先要保存初始化之后的状态,之后每次操作结束后先读取再保存

/**
 * 保存canvas
 * @param canvas 
 */
public static SaveCanvas(canvas: Canvas): void
{
    let canvasContext = canvas.getContext("2d");
    //保存状态
    canvasContext.save();
}

/**
 * 恢复canvas
 * @param canvas 
 */
public static ReloadCanvas(canvas: Canvas): void
{
    let canvasContext = canvas.getContext("2d");
    //恢复状态
    canvasContext.restore();
}

设置像素比

我觉得这个算是比较没用的,似乎并不能让像素对上,更糊了,而且之后的操作都要除以2,怪麻烦的,不如嗯写就完事了

/**
 * 设置canvas像素
 * @param canvas 
 * @param devicePixelRatio 设备像素比
 * @param deviceWidth 设备宽
 * @param deviceHeight 设备高
 */
public static SetPixelRatio(canvas: Canvas, devicePixelRatio: number, deviceWidth: number, deviceHeight: number): void
{
    let canvasContext = canvas.getContext("2d");
    canvas.height = deviceHeight * devicePixelRatio;
    canvas.width = deviceWidth * devicePixelRatio;
    canvasContext.scale(devicePixelRatio, devicePixelRatio);
}

绘制矩形

绘制矩形还是很简单的,不过为了规范和方便,先整一个Option类出来
我这里单纯绘制图形是没有颜色的,只是闭合路径,方便后续操作

export class CreateRectangleOptionModel
{

    private _canvas: Canvas = null;
    /**
     * 画布
     */
    public get Canvas(): Canvas
    {
        return this._canvas;
    }
    public set Canvas(v: Canvas)
    {
        this._canvas = v;
    }


    private _width: number = 0;
    /**
     * 宽度
     */
    public get Width(): number
    {
        return this._width;
    }
    public set Width(v: number)
    {
        this._width = v;
    }


    private _height: number = 0;
    /**
     * 高度
     */
    public get Height(): number
    {
        return this._height;
    }
    public set Height(v: number)
    {
        this._height = v;
    }

    private _x: number = 0;
    /**
     * 起始坐标x
     */
    public get X(): number
    {
        return this._x;
    }
    public set X(v: number)
    {
        this._x = v;
    }


    private _y: number = 0;
    /**
     * 起始坐标Y
     */
    public get Y(): number
    {
        return this._y;
    }
    public set Y(v: number)
    {
        this._y = v;
    }


    constructor()
    {
        this.Canvas = null;
        this.Width = 0;
        this.Height = 0;
        this.X = 0;
        this.Y = 0;
    }
}

再把这个类作为参数传进来

/**
 * 绘制矩形
 * @param option 
 */
public static CreateRectangle(option: CreateRectangleOptionModel): void
{
    let canvas = option.Canvas;
    let width = option.Width;
    let height = option.Height;
    let x = option.X;
    let y = option.Y;

    let canvasContext = canvas.getContext("2d");

    //选择背景色
    canvasContext.fillStyle = backgroundColor;
    //绘制矩形
    canvasContext.fillRect(x, y, width, height);
}

绘制矩形并描边

这里再来一个配置类,其实大部分属性跟矩形的配置是一样的,可以用继承

export class CreateRectangleStrokeColorOptionModel extends CreateRectangleOptionModel
{
    private _strokeColor: string = "#000000";
    /**
     * 描边颜色
     */
    public get StrokeColor(): string
    {
        return this._strokeColor;
    }
    public set StrokeColor(v: string)
    {
        this._strokeColor = v;
    }


    private _lineWidth: number = 1;
    /**
     * 描边宽度
     */
    public get LineWidth(): number
    {
        return this._lineWidth;
    }
    public set LineWidth(v: number)
    {
        this._lineWidth = v;
    }


    constructor()
    {
        super();
        this.StrokeColor = "#000000";
        this.LineWidth = 1;
    }
}

对应的函数

/**
 * 绘制矩形,描边
 * @param option 
 */
public static CreateRectangleStrokeColor(option: CreateRectangleStrokeColorOptionModel): void
{
    let canvas = option.Canvas;
    let width = option.Width;
    let height = option.Height;
    let x = option.X;
    let y = option.Y;
    let color = option.StrokeColor;
    let lineWidth = option.LineWidth;

    let createRectangleOptionModel = new CreateRectangleOptionModel();
    createRectangleOptionModel.Canvas = canvas;
    createRectangleOptionModel.Width = width;
    createRectangleOptionModel.Height = height;
    createRectangleOptionModel.X = x;
    createRectangleOptionModel.Y = y;

    //绘制矩形
    Canvas2DHelper.CreateRectangle(createRectangleOptionModel);

    let canvasContext = canvas.getContext("2d");

    //描边宽度
    canvasContext.lineWidth = lineWidth;
    //选择描边颜色
    canvasContext.strokeStyle = color;
    //描边
    canvasContext.stroke();
}

绘制矩形并填充颜色

export class CreateRectangleFillBackgroundColorOptionModel extends CreateCircleOptionModel
{
    private _backgroundColor: string;
    /**
     * 背景颜色
     */
    public get BackgroundColor(): string
    {
        return this._backgroundColor;
    }
    public set BackgroundColor(v: string)
    {
        this._backgroundColor = v;
    }


    constructor()
    {
        super();
        this.BackgroundColor = "#000000";
    }
}
/**
 * 绘制矩形填充背景色
 * @param option 
 */
public static CreateRectangleBackgroundColor(option: CreateRectangleFillBackgroundColorOptionModel): void
{
    let canvas = option.Canvas;
    let width = option.Width;
    let height = option.Height;
    let x = option.X;
    let y = option.Y;
    let backgroundColor = option.BackgroundColor;

    let canvasContext = canvas.getContext("2d");

    //选择背景色
    canvasContext.fillStyle = backgroundColor;
    //绘制矩形
    canvasContext.fillRect(x, y, width, height);
    //填充背景色
    canvasContext.fill();
}

绘制圆形

export class CreateCircleOptionModel
{

    private _canvas: Canvas = null;
    /**
     * 画布
     */
    public get Canvas(): Canvas
    {
        return this._canvas;
    }
    public set Canvas(v: Canvas)
    {
        this._canvas = v;
    }

    private _x: number = 0;
    /**
     * 圆心坐标x
     */
    public get X(): number
    {
        return this._x;
    }
    public set X(v: number)
    {
        this._x = v;
    }

    private _y: number = 0;
    /**
     * 圆心坐标Y
     */
    public get Y(): number
    {
        return this._y;
    }
    public set Y(v: number)
    {
        this._y = v;
    }

    private _radius: number = 0;
    /**
     * 半径
     */
    public get Radius(): number
    {
        return this._radius;
    }
    public set Radius(v: number)
    {
        this._radius = v;
    }


    constructor()
    {
        this.Canvas = null;
        this.X = 0;
        this.Y = 0;
        this.Radius = 0;
    }
}
/**
 * 绘制圆形
 * @param option 
 */
public static CreateCircle(option: CreateCircleOptionModel): void
{
    let canvas = option.Canvas;
    let x = option.X;
    let y = option.Y;
    let radius = option.Radius;

    let canvasContext = canvas.getContext("2d");

    //开始路径
    canvasContext.beginPath();

    //绘制圆形
    canvasContext.arc(x, y, radius, 0, 2 * Math.PI);

    //关闭路径
    canvasContext.closePath();
}

绘制圆形并描边

export class CreateCircleStrokeColorOptionModel extends CreateCircleOptionModel
{

    private _strokeColor: string = "#000000";
    /**
     * 描边颜色
     */
    public get StrokeColor(): string
    {
        return this._strokeColor;
    }
    public set StrokeColor(v: string)
    {
        this._strokeColor = v;
    }

    private _lineWidth: number = 1;
    /**
     * 描边宽度
     */
    public get LineWidth(): number
    {
        return this._lineWidth;
    }
    public set LineWidth(v: number)
    {
        this._lineWidth = v;
    }


    constructor()
    {
        super();
        this.StrokeColor = "#000000";
        this.LineWidth = 1;
    }
}
/**
 * 绘制圆形,描边
 * @param option 
 */
public static CreateCircleStrokeColor(option: CreateCircleStrokeColorOptionModel): void
{
    let canvas = option.Canvas;
    let x = option.X;
    let y = option.Y;
    let radius = option.Radius;
    let color = option.StrokeColor;
    let lineWidth = option.LineWidth;

    let createCircleOptionModel = new CreateCircleOptionModel();
    createCircleOptionModel.Canvas = canvas;
    createCircleOptionModel.X = x;
    createCircleOptionModel.Y = y;
    createCircleOptionModel.Radius = radius;

    //绘制圆形
    Canvas2DHelper.CreateCircle(createCircleOptionModel);

    let canvasContext = canvas.getContext("2d");

    //描边宽度
    canvasContext.lineWidth = lineWidth;
    //选择描边颜色
    canvasContext.strokeStyle = color;
    //描边
    canvasContext.stroke();
}

绘制圆形并填充颜色

export class CreateCircleFillBackgroundColorOptionModel extends CreateCircleOptionModel
{
    private _backgroundColor: string = "#000000";
    /**
     * 描边颜色
     */
    public get BackgroundColor(): string
    {
        return this._backgroundColor;
    }
    public set BackgroundColor(v: string)
    {
        this._backgroundColor = v;
    }

    constructor()
    {
        super();
        this.BackgroundColor = "#000000";
    }
}
/**
 * 绘制圆形,填充颜色
 * @param option 
 */
public static CreateCircleFillBackgroundColor(option: CreateCircleFillBackgroundColorOptionModel)
{
    let canvas = option.Canvas;
    let x = option.X;
    let y = option.Y;
    let radius = option.Radius;
    let backgroundColor = option.BackgroundColor;

    let createCircleOptionModel = new CreateCircleOptionModel();
    createCircleOptionModel.Canvas = canvas;
    createCircleOptionModel.X = x;
    createCircleOptionModel.Y = y;
    createCircleOptionModel.Radius = radius;

    //绘制圆形
    Canvas2DHelper.CreateCircle(createCircleOptionModel);

    let canvasContext = canvas.getContext("2d");

    //选择背景色
    canvasContext.fillStyle = backgroundColor;
    //填充背景色
    canvasContext.fill();
}

绘制圆角矩形

export class CreateRoundRectangleOptionModel
{

    private _canvas: Canvas = null;
    /**
     * 画布
     */
    public get Canvas(): Canvas
    {
        return this._canvas;
    }
    public set Canvas(v: Canvas)
    {
        this._canvas = v;
    }


    private _width: number = 0;
    /**
     * 宽度
     */
    public get Width(): number
    {
        return this._width;
    }
    public set Width(v: number)
    {
        this._width = v;
    }


    private _height: number = 0;
    /**
     * 高度
     */
    public get Height(): number
    {
        return this._height;
    }
    public set Height(v: number)
    {
        this._height = v;
    }

    private _x: number = 0;
    /**
     * 起始坐标x
     */
    public get X(): number
    {
        return this._x;
    }
    public set X(v: number)
    {
        this._x = v;
    }


    private _y: number = 0;
    /**
     * 起始坐标Y
     */
    public get Y(): number
    {
        return this._y;
    }
    public set Y(v: number)
    {
        this._y = v;
    }

    private _radius: number = 0;
    /**
     * 圆角半径
     */
    public get Radius(): number
    {
        return this._radius;
    }
    public set Radius(v: number)
    {
        this._radius = v;
    }

    constructor()
    {
        this.Canvas = null;
        this.Width = 0;
        this.Height = 0;
        this.X = 0;
        this.Y = 0;
        this.Radius = 0;
    }

}
/**
 * 绘制圆角矩形
 * @param option 
 */
public static CreateRoundRectangle(option: CreateRoundRectangleOptionModel): void
{
    let canvas = option.Canvas;
    let width = option.Width;
    let height = option.Height;
    let x = option.X;
    let y = option.Y;
    let radius = option.Radius;

    let canvasContext = canvas.getContext("2d");

    //开始路径
    canvasContext.beginPath();
    //左上角的右上点
    canvasContext.moveTo(x + radius, y);
    //右上角圆角
    canvasContext.arcTo(x + width, y, x + width, y + height, radius);
    //右下角圆角
    canvasContext.arcTo(x + width, y + height, x, y + height, radius);
    //左下角圆角
    canvasContext.arcTo(x, y + height, x, y, radius);
    //左上角圆角
    canvasContext.arcTo(x, y, x + width, y, radius);
    //合并路径
    canvasContext.closePath();
}

绘制圆角矩形并描边

export class CreateRoundRectangleStrokeColorOptionModel extends CreateRoundRectangleOptionModel
{
    private _strokeColor: string = "#000000";
    /**
     * 描边颜色
     */
    public get StrokeColor(): string
    {
        return this._strokeColor;
    }
    public set StrokeColor(v: string)
    {
        this._strokeColor = v;
    }

    private _lineWidth: number = 1;
    /**
     * 描边宽度
     */
    public get LineWidth(): number
    {
        return this._lineWidth;
    }
    public set LineWidth(v: number)
    {
        this._lineWidth = v;
    }

    constructor()
    {
        super();
        this.StrokeColor = "#000000";
        this.LineWidth = 1;
    }

}
/**
 * 绘制圆角矩形,描边
 * @param option 
 */
public static CreateRoundRectangleStrokeColor(option: CreateRoundRectangleStrokeColorOptionModel): void
{
    let canvas = option.Canvas;
    let width = option.Width;
    let height = option.Height;
    let x = option.X;
    let y = option.Y;
    let radius = option.Radius;
    let color = option.StrokeColor;
    let lineWidth = option.LineWidth;

    let createRoundRectangleOptionModel = new CreateRoundRectangleOptionModel();
    createRoundRectangleOptionModel.Canvas = canvas;
    createRoundRectangleOptionModel.Width = width;
    createRoundRectangleOptionModel.Height = height;
    createRoundRectangleOptionModel.X = x;
    createRoundRectangleOptionModel.Y = y;
    createRoundRectangleOptionModel.Radius = radius;

    //绘制矩形
    Canvas2DHelper.CreateRoundRectangle(createRoundRectangleOptionModel);

    let canvasContext = canvas.getContext("2d");

    //描边宽度
    canvasContext.lineWidth = lineWidth;
    //选择描边颜色
    canvasContext.strokeStyle = color;
    //描边
    canvasContext.stroke();
}

绘制圆角矩形并填充颜色

export class CreateRoundRectangleFillBackgroundColorOptionModel extends CreateRoundRectangleOptionModel
{
    private _backgroundColor: string;
    /**
     * 背景颜色
     */
    public get BackgroundColor(): string
    {
        return this._backgroundColor;
    }
    public set BackgroundColor(v: string)
    {
        this._backgroundColor = v;
    }


    constructor()
    {
        super();
        this.BackgroundColor = "#000000";
    }

}
/**
 * 绘制圆角矩形,填充颜色
 * @param option 
 */
public static CreateRoundRectangleFillBackgroundColor(option: CreateRoundRectangleFillBackgroundColorOptionModel): void
{
    let canvas = option.Canvas;
    let width = option.Width;
    let height = option.Height;
    let x = option.X;
    let y = option.Y;
    let radius = option.Radius;
    let backgroundColor = option.BackgroundColor;

    let createRoundRectangleOptionModel = new CreateRoundRectangleOptionModel();
    createRoundRectangleOptionModel.Canvas = canvas;
    createRoundRectangleOptionModel.Width = width;
    createRoundRectangleOptionModel.Height = height;
    createRoundRectangleOptionModel.X = x;
    createRoundRectangleOptionModel.Y = y;
    createRoundRectangleOptionModel.Radius = radius;

    //绘制矩形
    Canvas2DHelper.CreateRoundRectangle(createRoundRectangleOptionModel);

    let canvasContext = canvas.getContext("2d");

    //选择背景色
    canvasContext.fillStyle = backgroundColor;
    //填充背景色
    canvasContext.fill();
}

绘制文字

绘制文字是比较麻烦的,因为有换行和省略号的问题
我这里是没有配置字体的,要配置字体就自己稍微改改

export class CreateTextOptionModel
{

    private _canvas: Canvas = null;
    /**
     * 画布
     */
    public get Canvas(): Canvas
    {
        return this._canvas;
    }
    public set Canvas(v: Canvas)
    {
        this._canvas = v;
    }


    private _text: string = "";
    /**
     * 文本
     */
    public get Text(): string
    {
        return this._text;
    }
    public set Text(v: string)
    {
        this._text = v;
    }


    private _fontSize: number = 14;
    /**
     * 字体大小
     */
    public get FontSize(): number
    {
        return this._fontSize;
    }
    public set FontSize(v: number)
    {
        this._fontSize = v;
    }


    private _fontColor: string = "#000000";
    /**
     * 字体颜色
     */
    public get FontColor(): string
    {
        return this._fontColor;
    }
    public set FontColor(v: string)
    {
        this._fontColor = v;
    }


    private _isLineBreak: boolean = false;
    /**
     * 是否换行
     */
    public get IsLineBreak(): boolean
    {
        return this._isLineBreak;
    }
    public set IsLineBreak(v: boolean)
    {
        this._isLineBreak = v;
    }


    private _isOVerflowEllipsis: boolean = false;
    /**
     * 超出是否用省略号
     */
    public get IsOverflowEllipsis(): boolean
    {
        return this._isOVerflowEllipsis;
    }
    public set IsOverflowEllipsis(v: boolean)
    {
        this._isOVerflowEllipsis = v;
    }


    private _lineCount: number = 1;
    /**
     * 行数
     */
    public get LineCount(): number
    {
        return this._lineCount;
    }
    public set LineCount(v: number)
    {
        this._lineCount = v;
    }


    private _lineWidth: number = 100;
    /**
     * 行宽
     */
    public get LineWidth(): number
    {
        return this._lineWidth;
    }
    public set LineWidth(v: number)
    {
        this._lineWidth = v;
    }


    private _lineHeight: number = 21;
    /**
     * 行高
     */
    public get LineHeight(): number
    {
        return this._lineHeight;
    }
    public set LineHeight(v: number)
    {
        this._lineHeight = v;
    }

    private _x: number = 0;
    /**
     * 基线坐标x
     */
    public get X(): number
    {
        return this._x;
    }
    public set X(v: number)
    {
        this._x = v;
    }


    private _y: number = 0;
    /**
     * 基线坐标Y
     */
    public get Y(): number
    {
        return this._y;
    }
    public set Y(v: number)
    {
        this._y = v;
    }

    constructor()
    {
        this.Canvas = null;
        this.Text = "";
        this.FontSize = 14;
        this.FontColor = "#000000";
        this.IsLineBreak = false;
        this.IsOverflowEllipsis = false;
        this.LineCount = 1;
        this.LineWidth = 100;
        this.LineHeight = 21;
        this.X = 0;
        this.Y = 0;
    }
}
/**
 * 绘制文字
 * @param option 
 */
public static CreateText(option: CreateTextOptionModel): void
{
    let textList: Array<string> = [];

    let canvas = option.Canvas;
    let text = option.Text;
    let fontSize = option.FontSize;
    let fontColor = option.FontColor;
    let isLineBreak = option.IsLineBreak;
    let isOverflowEllipsis = option.IsOverflowEllipsis;
    let lineCount = option.LineCount;
    let lineWidth = option.LineWidth;
    let lineHeight = option.LineHeight;
    let x = option.X;
    let y = option.Y;


    let canvasContext = canvas.getContext("2d");

    //选择字体颜色
    canvasContext.fillStyle = fontColor;

    //字体大小
    canvasContext.font = `${fontSize}px sans-serif`;

    if (true == isLineBreak)
    {
        //换行
        if (true == isOverflowEllipsis)
        {
            //有省略号
            textList = Canvas2DHelper.GetLineBreakWithOverflowEllipsisTextList(canvas, text, fontSize, lineWidth, lineCount);
        }
        else
        {
            //无省略号
            textList = Canvas2DHelper.GetLineBreakTextList(canvas, text, fontSize, lineWidth);
        }
    }
    else
    {
        //不换行
        if (true == isOverflowEllipsis)
        {
            //有省略号
            textList = Canvas2DHelper.GetLineBreakWithOverflowEllipsisTextList(canvas, text, fontSize, lineWidth, 1);
        }
        else
        {
            //无省略号
            textList = [text];
        }
    }

    //循环绘制文本
    for (let i = 0; i < textList.length; i++)
    {
        const rowText = textList[i];
        let rowY = y + (i * lineHeight);
        //绘制文本
        canvasContext.fillText(rowText, x, rowY);
    }
}

/**
 * 获取换行字符串
 * @param canvas 
 * @param text 文本
 * @param fontSize 字体大小
 * @param lineWidth 行宽
 * @returns 
 */
private static GetLineBreakTextList(canvas: Canvas, text: string, fontSize: number = 14, lineWidth: number): Array<string>
{
    let textList: Array<string> = [];

    let canvasContext = canvas.getContext("2d");
    //字体大小
    canvasContext.font = `${fontSize}px sans-serif`;

    let textLength = text.length;
    let entireText = text;
    let currentRowText = "";
    for (let i = 0; i < text.length; i++)
    {
        let textItem = text[i];
        currentRowText += textItem;
        let currentRowTextCanvas = canvasContext.measureText(currentRowText);
        let currentRowTextWidth = currentRowTextCanvas.width;

        if (currentRowTextWidth > lineWidth)
        {
            currentRowText = currentRowText.substring(0, currentRowText.length - 1);
            //换行
            textList.push(currentRowText);
            //初始化行数据
            currentRowText = "";
            i--;
            entireText = text.substring(i, textLength);
        }
    }

    //最后一行
    textList.push(currentRowText);

    return textList;
}

/**
 * 获取换行省略号字符串
 * @param canvas 
 * @param text 文本
 * @param fontSize 字体大小
 * @param lineWidth 行宽
 * @param lineCount 最大行数
 * @returns 
 */
private static GetLineBreakWithOverflowEllipsisTextList(canvas: Canvas, text: string, fontSize: number = 14, lineWidth: number, lineCount: number = 1): Array<string>
{
    let textList: Array<string> = [];
    let canvasContext = canvas.getContext("2d");
    //字体大小
    canvasContext.font = `${fontSize}px sans-serif`;

    let isAddLast = true;
    let textLength = text.length;
    let entireText = text;
    let currentRowText = "";
    for (let i = 0; i < text.length; i++)
    {
        let textItem = text[i];
        currentRowText += textItem;
        let currentRowTextCanvas = canvasContext.measureText(currentRowText);
        let currentRowTextWidth = currentRowTextCanvas.width;

        if (currentRowTextWidth > lineWidth)
        {
            currentRowText = currentRowText.substring(0, currentRowText.length - 1);
            let currentRowCount = textList.length + 1;
            if (currentRowCount < lineCount)
            {
                //换行
                textList.push(currentRowText);
                //初始化行数据
                currentRowText = "";
                i--;
                entireText = text.substring(i, textLength);
            }
            else
            {
                let lastRowText = Canvas2DHelper.GetLineBreakWithOverflowEllipsisText(canvas, currentRowText, fontSize, lineWidth);
                textList.push(lastRowText);
                isAddLast = false;
                break;
            }
        }
    }

    if (true == isAddLast)
    {
        textList.push(currentRowText);
    }

    return textList;
}

/**
 * 获取增加省略号之后的字符串
 * @param canvas 
 * @param text 文本
 * @param fontSize 字体大小
 * @param lineWidth 行宽
 * @returns 
 */
private static GetLineBreakWithOverflowEllipsisText(canvas: Canvas, text: string, fontSize: number = 14, lineWidth: number): string
{
    let ellipsisText = "";
    let canvasContext = canvas.getContext("2d");
    //字体大小
    canvasContext.font = `${fontSize}px sans-serif`;

    let ellipsis = "...";
    let ellipsisLength = ellipsis.length;
    let currentRowText = text;

    for (let i = text.length - 1; i >= 0; i--)
    {
        const textItem = text[i];

        currentRowText += ellipsis;

        let currentRowTextCanvas = canvasContext.measureText(currentRowText);
        let currentRowTextWidth = currentRowTextCanvas.width;
        if (currentRowTextWidth > lineWidth)
        {
            //删去一个字符
            currentRowText = text.substring(0, i + 1);
        }
        else
        {
            ellipsisText = currentRowText;
            break;
        }
    }

    return ellipsisText;
}

绘制iconfont

这里就很难蚌了,在html里面我们只需要把字体改成iconfont.css里面的,然后用\u+Unicode16进制就行,但是小程序这一坨不支持绘制iconfont,这个特性从canvas刚出来就有人说了,到现在都没有
所以我们直接绘制png图片吧,当然这里就需要注意了,因为图片的缩放会模糊,所以建议自己在cdn里面搞对应的尺寸

export class CreateIconFontOptionModel
{

    private _canvas: Canvas = null;
    /**
     * 画布
     */
    public get Canvas(): Canvas
    {
        return this._canvas;
    }
    public set Canvas(v: Canvas)
    {
        this._canvas = v;
    }

    private _iconUrl: string = "";
    /**
     * 图标链接
     */
    public get IconUrl(): string
    {
        return this._iconUrl;
    }
    public set IconUrl(v: string)
    {
        this._iconUrl = v;
    }

    private _fontSize: number = 14;
    /**
     * 字体大小
     */
    public get FontSize(): number
    {
        return this._fontSize;
    }
    public set FontSize(v: number)
    {
        this._fontSize = v;
    }

    private _fontColor: string = "#000000";
    /**
     * 字体颜色
     */
    public get FontColor(): string
    {
        return this._fontColor;
    }
    public set FontColor(v: string)
    {
        this._fontColor = v;
    }

    private _x: number = 0;
    /**
     * 坐标x
     */
    public get X(): number
    {
        return this._x;
    }
    public set X(v: number)
    {
        this._x = v;
    }

    private _y: number = 0;
    /**
     * 坐标Y
     */
    public get Y(): number
    {
        return this._y;
    }
    public set Y(v: number)
    {
        this._y = v;
    }

    constructor()
    {
        this.Canvas = null;
        this.IconUrl = "";
        this.FontColor = "#000000";
        this.FontSize = 14;
        this.X = 0;
        this.Y = 0;
    }

}

还要注意这个是异步函数,要await

/**
 * 绘制 iconfont 图标
 * @param option 
 * @returns 
 */
public static CreateIconFont(option: CreateIconFontOptionModel): Promise<void>
{
    return new Promise((resolve, reject) =>
    {

        let canvas = option.Canvas;
        let fontSize = option.FontSize;
        let fontColor = option.FontColor;
        let iconUrl = option.IconUrl;
        let x = option.X;
        let y = option.Y;

        let fontColorRgb = ColorHelper.HexColorToRgb(fontColor);
        let fontColorRed = fontColorRgb.Red;
        let fontColorGreen = fontColorRgb.Green;
        let fontColorBlue = fontColorRgb.Blue;

        //加载图标
        let iconCanvas = Canvas2DHelper.CreateOffscreenCanvas();
        let iconImage = iconCanvas.createImage();
        iconImage.onload = () =>
        {
            let iconImageHeight = iconImage.height;
            let iconImageWidth = iconImage.width;

            let zoomRatio = iconImageHeight / fontSize;
            let iconCanvasHeight = Math.round(iconImageHeight / zoomRatio);
            let iconCanvasWidth = Math.round(iconImageWidth / zoomRatio);

            iconCanvas.height = iconCanvasHeight;
            iconCanvas.width = iconCanvasWidth;
            let iconCanvasContext = iconCanvas.getContext("2d");
            iconCanvasContext.drawImage(iconImage, 0, 0, iconCanvas.width, iconCanvas.height);

            let unSetColorIconData = iconCanvasContext.getImageData(0, 0, iconCanvas.width, iconCanvas.height);
            let unSetColorIconPixelList = unSetColorIconData.data;
            for (let i = 0; i < unSetColorIconPixelList.length; i += 4)
            {
                let unSetColorIconPixelRed = unSetColorIconPixelList[i];
                let unSetColorIconPixelGreen = unSetColorIconPixelList[i + 1];
                let unSetColorIconPixelBlue = unSetColorIconPixelList[i + 2];
                let unSetColorIconPixelAlpha = unSetColorIconPixelList[i + 3];

                if (0 != unSetColorIconPixelAlpha)
                {
                    unSetColorIconPixelList[i] = fontColorRed;
                    unSetColorIconPixelList[i + 1] = fontColorGreen;
                    unSetColorIconPixelList[i + 2] = fontColorBlue;
                }
            }

            iconCanvasContext.putImageData(unSetColorIconData, 0, 0);

            let canvasContext = canvas.getContext("2d");

            //绘制图标
            canvasContext.drawImage(iconCanvas, x, y);

            resolve("图片渲染完成");
        };
        iconImage.onerror = () =>
        {
            reject("图片加载失败");
        };
        iconImage.src = iconUrl;
    });
}

绘制图片

这里我们需要注意图片的原点坐标和缩放模式
先搞一个缩放模式的枚举出来

export enum CreateImageMode
{
    /**
     * 保持长宽比,添加黑边
     */
    Contain = 0,
    /**
     * 保持长宽比,裁切
     */
    Cover = 2,
    /**
     * 填充,拉伸
     */
    Fill = 4,
    /**
     * 保持原有尺寸
     */
    None = 8,
}

然后再加配置

import { Canvas } from "@tarojs/taro";
import { CreateImageMode } from "./CreateImageMode";

export class CreateImageOptionModel
{

    private _canvas: Canvas = null;
    /**
     * 画布
     */
    public get Canvas(): Canvas
    {
        return this._canvas;
    }
    public set Canvas(v: Canvas)
    {
        this._canvas = v;
    }


    private _imageUrl: string = "";
    /**
     * 图片链接
     */
    public get ImageUrl(): string
    {
        return this._imageUrl;
    }
    public set ImageUrl(v: string)
    {
        this._imageUrl = v;
    }

    private _mode: CreateImageMode = CreateImageMode.None;
    /**
     * 绘制图像模式
     */
    public get Mode(): CreateImageMode
    {
        return this._mode;
    }
    public set Mode(v: CreateImageMode)
    {
        this._mode = v;
    }


    private _height: number = 0;
    /**
     * 图片高度
     */
    public get Height(): number
    {
        return this._height;
    }
    public set Height(v: number)
    {
        this._height = v;
    }


    private _width: number = 0;
    /**
     * 图片宽度
     */
    public get Width(): number
    {
        return this._width;
    }
    public set Width(v: number)
    {
        this._width = v;
    }

    private _x: number = 0;
    /**
     * 坐标x
     */
    public get X(): number
    {
        return this._x;
    }
    public set X(v: number)
    {
        this._x = v;
    }

    private _y: number = 0;
    /**
     * 坐标Y
     */
    public get Y(): number
    {
        return this._y;
    }
    public set Y(v: number)
    {
        this._y = v;
    }


    constructor()
    {
        this.Canvas = null;
        this.ImageUrl = "";
        this.Mode = CreateImageMode.None;
        this.Height = 0;
        this.Width = 0;
        this.X = 0;
        this.Y = 0;
    }
}

最后是函数,也是异步的

/**
 * 绘制图片
 * @param option 
 * @returns 
 */
public static CreateImage(option: CreateImageOptionModel): Promise<void>
{
    return new Promise((resolve, reject) =>
    {
        let canvas = option.Canvas;
        let imageUrl = option.ImageUrl;
        let mode = option.Mode;
        let height = option.Height;
        let width = option.Width;
        let x = option.X;
        let y = option.Y;

        let proportion = width / height;

        let originX = Math.round(width / 2);
        let originY = Math.round(height / 2);

        let imageCanvas = Canvas2DHelper.CreateOffscreenCanvas();
        let image = imageCanvas.createImage();
        image.onload = () =>
        {
            let imageHeight = image.height;
            let imageWidth = image.width;
            let imageProportion = imageWidth / imageHeight;

            //图片处理后大小
            let createImageHeight = 0;
            let createImageWidth = 0;
            //图片处理后坐标变化
            let createImageOriginX = 0;
            let createImageOriginY = 0;
            let canvasContext = canvas.getContext("2d");
            switch (mode)
            {
                case CreateImageMode.Contain:
                    if (proportion >= imageProportion)
                    {
                        //以高为准
                        createImageHeight = height;
                        let heightZoomRatio = height / imageHeight;
                        createImageWidth = Math.round(imageWidth * heightZoomRatio);
                    }
                    else
                    {
                        //以宽为准
                        createImageWidth = width;
                        let widthZoomRatio = width / imageWidth;
                        createImageHeight = Math.round(imageHeight * widthZoomRatio);
                    }

                    createImageOriginX = x - Math.round(createImageWidth / 2);
                    createImageOriginY = y - Math.round(createImageHeight / 2);


                    //改变坐标系原点
                    canvasContext.translate(originX, originY);

                    //绘制图片
                    canvasContext.drawImage(image, createImageOriginX, createImageOriginY, createImageWidth, createImageHeight);
                    break;
                case CreateImageMode.Cover:
                    let publicZoomRatio = 0;
                    if (proportion >= imageProportion)
                    {
                        //以高为准
                        createImageHeight = height;
                        publicZoomRatio = height / imageHeight;
                        createImageWidth = Math.round(imageWidth * publicZoomRatio);
                    }
                    else
                    {
                        //以宽为准
                        createImageWidth = width;
                        publicZoomRatio = width / imageWidth;
                        createImageHeight = Math.round(imageHeight * publicZoomRatio);
                    }

                    createImageOriginX = x - Math.round(createImageWidth / 2);
                    createImageOriginY = y - Math.round(createImageHeight / 2);


                    //改变坐标系原点
                    canvasContext.translate(originX, originY);

                    //绘制图片
                    canvasContext.drawImage(image, createImageOriginX, createImageOriginY, createImageWidth, createImageHeight);

                    break;
                case CreateImageMode.Fill:
                    createImageHeight = height;
                    createImageWidth = width;
                    createImageOriginX = x - Math.round(createImageWidth / 2);
                    createImageOriginY = y - Math.round(createImageHeight / 2);

                    //改变坐标系原点
                    canvasContext.translate(originX, originY);

                    //绘制图片
                    canvasContext.drawImage(image, createImageOriginX, createImageOriginY, createImageWidth, createImageHeight);
                    break;
                case CreateImageMode.None:
                default:
                    createImageHeight = imageHeight;
                    createImageWidth = imageWidth;

                    createImageOriginX = x - Math.round(createImageWidth / 2);
                    createImageOriginY = y - Math.round(createImageHeight / 2);

                    //改变坐标系原点
                    canvasContext.translate(originX, originY);

                    //绘制图片
                    canvasContext.drawImage(image, createImageOriginX, createImageOriginY, createImageWidth, createImageHeight);
                    break;
            }

            resolve("图片渲染完成");
        };
        image.onerror = () =>
        {
            reject("图片加载失败");
        };
        image.src = imageUrl;

    });
}

转为base64图片

这个还是蛮常用的,毕竟十六进制比二进制短

/**
 * 转换为图片
 * @param canvas 
 * @returns 
 */
public static ConvertToImage(canvas: Canvas): string
{
    // let canvasContext = canvas.getContext("2d");

    let imageUrl = canvas.toDataURL();

    return imageUrl;
}

Canvas 封装 结束

标签:Canvas,封装,option,number,let,canvas,._,public
From: https://www.cnblogs.com/zzy-tongzhi-cnblog/p/18067741

相关文章

  • Vue — v-load封装 loading效果
    <template><divclass="app"><divclass="box"v-load="isLoading"><ul><liv-for="(item,index)inlist":key="index">{{item.name}}&l......
  • uniapp封装公共分享方法
    使用mixins封装分享方法创建share.jsimporturlConfigfrom"@/utils/urlConfig";exportconstshareMixins={data(){return{shareData:{title:'',//分享内容的标题path:'',//分享内容跳转......
  • Vue项目中封装axios统一管理http请求
    <divid="content_views"class="markdown_viewsprism-tomorrow-night"><svgxmlns="http://www.w3.org/2000/svg"style="display:none;"><pathstroke-lineca......
  • python+pytest接口自动化之测试函数、测试类/测试方法的封装
    前言今天呢,笔者想和大家聊聊python+pytest接口自动化中将代码进行封装,只有将测试代码进行封装,才能被测试框架识别执行。例如单个接口的请求代码如下:importrequestsheaders={"user-agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,l......
  • app直播源码,封装调用第三方服务的请求与响应
    在开发app直播源码的过程中,经常会遇到调用一些第三方的请求与响应,如果只是简单的两种请求与响应那么我们只需要去简单的去封装请求头与请求体即可,并且拼接第三方调用的key即可,但是遇到一些流程比较繁琐的调用就显得非常的麻烦了。而高效的去封装这些服务的请求与响应实体不仅......
  • Java面向对象之封装性
    封装性我要用洗衣机,只需按开关即可,无需了解洗衣机的内部结构。以上这句话可能大家在搜索学习封装性的时候可能都听过,可是这句话严重误导了我。可能是由于面向过程的学习太过深刻,我联想到了函数,函数不就是把洗衣服的过程全部“封装”起来了吗?我只需要调用函数方法就可以了呀,确......
  • 委托封装验证功能
    1namespaceConsoleApp1.Delegate.Day32{3usingSystem;4usingSystem.Collections.Generic;5usingSystem.Linq;6usingSystem.Text;7usingSystem.Threading.Tasks;89///<summary>10///比如有一个请求.......
  • 通过canvas实现鼠标绘图的注意点
    问题情景:想设置全屏canvas时,直接修改了canvas的css样式为width:100%。出现问题:绘图时坐标不对应且有明显放大感。问题原因:css中width是将canvas尺寸直接放大,而实际需要的是修改canvas本身的尺寸。解决办法:直接定义canvas.width和canvas.height。我用的是vue3所以用了onMount......
  • 链式前向星封装版
    类-链式前向星(封装)by橙之夏Codestructforstar{vector<int>_h,_e,_ne,_w;intidx=0;forstar(intn)//初始化,n为容量{_h.resize(n+1,-1),_e.resize(n+1),_ne.resize(n+1),_w.resize(n+1);}voidadd(inta,in......
  • JDBC工具类封装v2.0
    JDBC工具类封装v2.01packagecom.atsyc.api.utils;23/*4*TODO:5*利用线程本地变量,存储连接信息,确保一个线程的多个方法可以获取同一个connection6*优势:事务操作的时候service和dao属于同一个线程,不用再传递参数了7*大家都可以调......