UNPKG

vislite

Version:

灵活、快速、简单的数据可视化交互式跨端前端库

189 lines (156 loc) 5.93 kB
import type CanvasConfigType from "../../../types/CanvasConfig" import type CanvasOptsType from '../../../types/CanvasOpts' import PainterRender from "./painter" import assemble from "../assemble" import { linearGradient, radialGradient, conicGradient } from "./gradient" import { initText } from './config' import defaultFactory from "./default" class Canvas extends PainterRender { readonly name: string = "Canvas" private __regionList = {} //区域映射表 private __scaleSize // 步长由1改为10是为了优化区域计算有时候出错问题 // 2023年7月6日 于南京 private __regionAssemble = assemble(0, 255, 10, 3) // 添加scaleSize参数是为了适配画布缩放后的处理 // 2024年1月17日 于南京 constructor(ViewCanvas: HTMLCanvasElement, RegionCanvas: HTMLCanvasElement | null, opts: CanvasOptsType = {}, scaleSize = 1) { super( ViewCanvas, opts, RegionCanvas ? new PainterRender(RegionCanvas, { willReadFrequently: true, }) : undefined, true, scaleSize ) this.__scaleSize = scaleSize this.setRegion("") } config(configs: CanvasConfigType) { for (const key in configs) { this.useConfig(key, (configs as any)[key]) } return this } reset() { this.config(defaultFactory() as CanvasConfigType) return this } // 是否绘制的内容只需要进行区域记录 onlyRegion(flag: boolean) { this.__onlyRegion = flag return this } onlyView(flag: boolean) { this.__onlyView = flag return this } // 设置当前绘制区域名称 setRegion(regionName: string | number) { if (this.__region) { if (regionName) { if ((this.__regionList as any)[regionName] == void 0) { const tempColor = this.__regionAssemble(); (this.__regionList as any)[regionName] = "rgb(" + tempColor[0] + "," + tempColor[1] + "," + tempColor[2] + ")" } this.__region.useConfig("fillStyle", (this.__regionList as any)[regionName]) && this.__region.useConfig("strokeStyle", (this.__regionList as any)[regionName]) } else { this.__region.useConfig("fillStyle", "#000000") && this.__region.useConfig("strokeStyle", "#000000") } } return this } // 获取当前事件触发的区域名称 getRegion(x: number, y: number): Promise<string> { return new Promise((resolve) => { const imgData = this.__region ? this.__region.painter.getImageData(x - 0.5, y - 0.5, 1, 1) : { data: [0, 0, 0, 0] } // 获取点击点的颜色 let currentRGBA = imgData.data const doit = () => { if (this.__region) { // 查找当前点击的区域 for (const key in this.__regionList) { if ( "rgb(" + currentRGBA[0] + "," + currentRGBA[1] + "," + currentRGBA[2] + ")" == (this.__regionList as any)[key] ) { resolve(key) break } } } resolve("") } // 如果有值 if (currentRGBA) { doit() } // 否则就是在Promise中 else { (imgData as any).then((data: Uint8ClampedArray) => { currentRGBA = data doit() }) } }) } textWidth(text: string) { this.painter.save() initText(this.painter, this.__specialConfig, 0, 0, 0) // 虽然我们限制了只可以输入字符串,可是不代表所有环境都可以保证,为了确保方法不失效,强转成字符串 const width = this.painter.measureText(text + "").width this.painter.restore() return width } // 获取原始画笔 getContext(isRegion = false) { return isRegion ? (this.__region ? this.__region.painter : null) : this.painter } // 获取画布信息 getInfo() { return { width: this.painter.canvas.width / this.__scaleSize, height: this.painter.canvas.height / this.__scaleSize } } // 线性渐变 createLinearGradient(x0: number, y0: number, x1: number, y1: number) { return linearGradient(this.painter, x0, y0, x1, y1) } // 环形渐变 createRadialGradient(cx: number, cy: number, r: number) { return radialGradient(this.painter, cx, cy, r) } // 角度渐变 createConicGradient(cx: number, cy: number, beginDeg: number, deg?: number) { return conicGradient(this.painter, cx, cy, beginDeg, deg) } // 获取指定位置颜色 getColor(x: number, y: number) { x *= this.__scaleSize y *= this.__scaleSize const currentRGBA = this.painter.getImageData(x - 0.5, y - 0.5, 1, 1).data return ( "rgba(" + currentRGBA[0] + "," + currentRGBA[1] + "," + currentRGBA[2] + "," + currentRGBA[3] + ")" ) } } export default Canvas