yanyan-ui
Version:
适用于vue3的前端xy组件库
210 lines (205 loc) • 6.21 kB
text/typescript
import Rectangular from "./Rectangular"
import Circle from "./Circle"
import Triangle from "./Triangle"
export default class DrawGraph {
private _canvas: HTMLCanvasElement;
private readonly _ctx: CanvasRenderingContext2D;
private _width: number;
private _height: number;
private _canvasBG: string;
private readonly _dpi: number;
private _ifDraw: boolean;
private _shape: any[];
private _graphColor: string;
private _customShape: Object;
private _currentGraph: string;
/**
* 构造函数 - 创建一个绘图对象。
* @param canvas - 画布元素。
* @param ctx - 画布上下文。
*/
constructor(
canvas:HTMLCanvasElement,
ctx:CanvasRenderingContext2D
) {
this._canvas = canvas;
this._ctx = ctx;
this._width = 800;
this._height = 600;
this._canvasBG = "#191919";
this._dpi = window.devicePixelRatio || 1;
this._ifDraw = false;
this._shape = [];
this._graphColor = "#b5b5b5";
this._customShape = {Rectangular:Rectangular,Circle:Circle,Triangle:Triangle};
this._currentGraph = "Rectangular";
}
/**
* 根据坐标获取图形。
* @param x - X 坐标。
* @param y - Y 坐标。
* @return 如果找到图形,返回图形对象,否则返回 null。
*/
getGraph(x:number, y:number):any {
for (let i = this._shape.length - 1; i >= 0; i--) {
const s = this._shape[i];
if (s.isInside(x, y)) {
return s;
}
}
return null;
}
/**
* 绘制图形。
*/
drawShape():void {
requestAnimationFrame(()=>this.drawShape());
if (this._ifDraw) {
this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
this._ctx.fillStyle = this._canvasBG;
this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);
for (const item of this._shape) {
item.draw();
}
}
}
/**
* canvas是否被点击
* @param e - 鼠标事件
*/
isCanvasDown = (e:MouseEvent):void => {
const rect = this._canvas.getBoundingClientRect();
if (e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom) {
return;
}
const startx:number = e.clientX - rect.left;
const starty:number = e.clientY - rect.top;
const ifMove = this.getGraph(startx, starty);
if (ifMove) {
//将ifMove移动到_shape的最后 --问题ctrl+z会删除当前点击的最后一个元素
// const index = this._shape.indexOf(ifMove);
// this._shape.splice(index, 1);
// this._shape.push(ifMove);
let tempX = startx;
let tempY = starty;
this._ifDraw = true;
window.onmousemove = (e) => {
const disX = e.clientX - rect.left;
const disY = e.clientY - rect.top;
ifMove.moveGraph(disX - tempX, disY - tempY);
tempX = disX;
tempY = disY;
}
} else {
// @ts-ignore
const graph = new this._customShape[this._currentGraph](
this._graphColor,
startx,
starty,
this._ctx,
this._width,
this._height,
this._dpi
)
this._shape.push(graph);
this._ifDraw = true;
window.onmousemove = (e:MouseEvent):void => {
graph.endX = e.clientX - rect.left;
graph.endY = e.clientY - rect.top;
}
}
window.onmouseup = ():void => {
window.onmousemove = null;
window.onmouseup = null;
this._ifDraw = false;
}
}
/**
* 初始化绘图
* @param width - 画布宽度
* @param height - 画布高度
* @param canvasBG - 画布背景颜色
* @param graphColor - 图形颜色
*/
init(width:number, height:number, canvasBG:string,graphColor:string):void {
this._width = width || this._width;
this._height = height || this._height;
this._canvasBG = canvasBG || this._canvasBG;
this._graphColor = graphColor || this._graphColor;
this._canvas.width = this._width * this._dpi;
this._canvas.height = this._height * this._dpi;
this._canvas.style.width = `${this._width}px`;
this._canvas.style.height = `${this._height}px`;
this._ctx.fillStyle = this._canvasBG;
this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);
this._canvas.onmousedown = (e:MouseEvent):void => {
this.isCanvasDown(e);
}
window.onkeydown = (e:KeyboardEvent):void => {
if (e.ctrlKey && (e.key === "z" || e.key === 'Z')) {
this._shape.pop();
this._ifDraw = true;
}
}
window.onkeyup = ():void => {
this._ifDraw = false;
}
}
/**
* 修改画布背景颜色
* @param canvasBG - 画布背景颜色
* */
changeCanvasBG(canvasBG:string):void{
this._canvasBG = canvasBG;
this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
this._ctx.fillStyle = this._canvasBG;
this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);
for (const item of this._shape) {
item.draw();
}
}
/**
* 销毁绘图
*/
destruction():void{
this._canvas.onmousedown = null;
window.onkeydown = null;
window.onkeyup = null;
this._shape = [];
}
/**
* 设置自定义图形
* @param customShape - 自定义图形
* */
setShape(customShape:Object):void{
this._customShape = {
...customShape,
...this._customShape
}
}
/**
* 设置当前图形
* @param currentGraph - 当前图形
* */
setCurrentGraph(currentGraph:string):void{
this._currentGraph = currentGraph;
}
/**
* 改变填充颜色
*@param graphColor - 填充颜色
*/
changeGraphColor(graphColor:string):void{
this._graphColor = graphColor;
}
/**
* 下载canvas
* */
downloadCanvas():void {
const pngName:string = Math.random().toString(36).substr(2);
const image:string = this._canvas.toDataURL('image/png');
const link:HTMLAnchorElement = document.createElement('a');
link.href = image;
link.download = `${pngName}.png`;
link.click();
}
}