|
| 1 | +/** |
| 2 | + * SVGCanvas - Draw on SVG using Canvas's 2D Context API |
| 3 | + * |
| 4 | + * This library provides a Canvas 2D Context API implementation that generates SVG |
| 5 | + * instead of drawing to a bitmap canvas. |
| 6 | + * |
| 7 | + * @example |
| 8 | + * ```javascript |
| 9 | + * import { Context } from 'svgcanvas'; |
| 10 | + * |
| 11 | + * const ctx = new Context({ width: 500, height: 500 }); |
| 12 | + * ctx.fillStyle = 'red'; |
| 13 | + * ctx.fillRect(10, 10, 100, 100); |
| 14 | + * const svgElement = ctx.getSvg(); |
| 15 | + * document.body.appendChild(svgElement); |
| 16 | + * ``` |
| 17 | + */ |
| 18 | + |
| 19 | +/** |
| 20 | + * Options for creating a Context or Element |
| 21 | + */ |
| 22 | +export interface C2SOptions { |
| 23 | + /** Width of the canvas (default: 500) */ |
| 24 | + width?: number; |
| 25 | + /** Height of the canvas (default: 500) */ |
| 26 | + height?: number; |
| 27 | + /** Enable mirroring for getImageData (default: false) */ |
| 28 | + enableMirroring?: boolean; |
| 29 | + /** Document object (default: global document) */ |
| 30 | + document?: Document; |
| 31 | + /** Existing Context2D to wrap around */ |
| 32 | + ctx?: CanvasRenderingContext2D; |
| 33 | + /** Enable debug logging */ |
| 34 | + debug?: boolean; |
| 35 | +} |
| 36 | + |
| 37 | +/** |
| 38 | + * CanvasGradient for creating color gradients |
| 39 | + */ |
| 40 | +export interface CanvasGradient { |
| 41 | + /** |
| 42 | + * Adds a color stop to the gradient |
| 43 | + * @param offset - A number between 0 and 1 |
| 44 | + * @param color - A CSS color string |
| 45 | + */ |
| 46 | + addColorStop(offset: number, color: string): void; |
| 47 | +} |
| 48 | + |
| 49 | +/** |
| 50 | + * CanvasPattern for creating pattern fills |
| 51 | + */ |
| 52 | +// eslint-disable-next-line @typescript-eslint/no-empty-interface |
| 53 | +export interface CanvasPattern {} |
| 54 | + |
| 55 | +/** |
| 56 | + * TextMetrics - measurement results from measureText() |
| 57 | + */ |
| 58 | +export interface TextMetrics { |
| 59 | + width: number; |
| 60 | +} |
| 61 | + |
| 62 | +/** |
| 63 | + * Context - implements most of CanvasRenderingContext2D API but generates SVG |
| 64 | + * |
| 65 | + * This class provides a Canvas 2D-like API that generates SVG elements instead |
| 66 | + * of drawing to a bitmap. Most standard Canvas 2D methods are supported. |
| 67 | + */ |
| 68 | +export class Context { |
| 69 | + // Canvas properties |
| 70 | + readonly canvas: Context; |
| 71 | + width: number; |
| 72 | + height: number; |
| 73 | + |
| 74 | + // Style properties |
| 75 | + fillStyle: string | CanvasGradient | CanvasPattern; |
| 76 | + strokeStyle: string | CanvasGradient | CanvasPattern; |
| 77 | + lineWidth: number; |
| 78 | + lineCap: CanvasLineCap; |
| 79 | + lineJoin: CanvasLineJoin; |
| 80 | + miterLimit: number; |
| 81 | + globalAlpha: number; |
| 82 | + font: string; |
| 83 | + textAlign: CanvasTextAlign; |
| 84 | + textBaseline: CanvasTextBaseline; |
| 85 | + shadowColor: string; |
| 86 | + shadowBlur: number; |
| 87 | + shadowOffsetX: number; |
| 88 | + shadowOffsetY: number; |
| 89 | + lineDash: string | null; |
| 90 | + |
| 91 | + constructor(options?: C2SOptions); |
| 92 | + constructor(width: number, height: number); |
| 93 | + |
| 94 | + // Drawing state |
| 95 | + save(): void; |
| 96 | + restore(): void; |
| 97 | + |
| 98 | + // Transformations |
| 99 | + scale(x: number, y?: number): void; |
| 100 | + rotate(angle: number): void; |
| 101 | + translate(x: number, y: number): void; |
| 102 | + transform(a: number, b: number, c: number, d: number, e: number, f: number): void; |
| 103 | + setTransform(a: number, b: number, c: number, d: number, e: number, f: number): void; |
| 104 | + setTransform(matrix: DOMMatrix): void; |
| 105 | + getTransform(): DOMMatrix; |
| 106 | + resetTransform(): void; |
| 107 | + |
| 108 | + // Path methods |
| 109 | + beginPath(): void; |
| 110 | + closePath(): void; |
| 111 | + moveTo(x: number, y: number): void; |
| 112 | + lineTo(x: number, y: number): void; |
| 113 | + bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void; |
| 114 | + quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void; |
| 115 | + arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterClockwise?: boolean): void; |
| 116 | + arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void; |
| 117 | + ellipse( |
| 118 | + x: number, |
| 119 | + y: number, |
| 120 | + radiusX: number, |
| 121 | + radiusY: number, |
| 122 | + rotation: number, |
| 123 | + startAngle: number, |
| 124 | + endAngle: number, |
| 125 | + counterClockwise?: boolean, |
| 126 | + ): void; |
| 127 | + rect(x: number, y: number, width: number, height: number): void; |
| 128 | + roundRect(x: number, y: number, w: number, h: number, radii: number | [number, number, number, number]): void; |
| 129 | + |
| 130 | + // Drawing methods |
| 131 | + fill(): void; |
| 132 | + stroke(): void; |
| 133 | + clip(): void; |
| 134 | + fillRect(x: number, y: number, width: number, height: number): void; |
| 135 | + strokeRect(x: number, y: number, width: number, height: number): void; |
| 136 | + clearRect(x: number, y: number, width: number, height: number): void; |
| 137 | + |
| 138 | + // Text methods |
| 139 | + fillText(text: string, x: number, y: number): void; |
| 140 | + strokeText(text: string, x: number, y: number): void; |
| 141 | + measureText(text: string): TextMetrics; |
| 142 | + |
| 143 | + // Image methods - supports Context instances for nested SVG |
| 144 | + drawImage( |
| 145 | + image: HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | Context, |
| 146 | + dx: number, |
| 147 | + dy: number, |
| 148 | + ): void; |
| 149 | + drawImage( |
| 150 | + image: HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | Context, |
| 151 | + dx: number, |
| 152 | + dy: number, |
| 153 | + dWidth: number, |
| 154 | + dHeight: number, |
| 155 | + ): void; |
| 156 | + drawImage( |
| 157 | + image: HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | Context, |
| 158 | + sx: number, |
| 159 | + sy: number, |
| 160 | + sWidth: number, |
| 161 | + sHeight: number, |
| 162 | + dx: number, |
| 163 | + dy: number, |
| 164 | + dWidth: number, |
| 165 | + dHeight: number, |
| 166 | + ): void; |
| 167 | + |
| 168 | + // Gradient and pattern methods |
| 169 | + createLinearGradient(x1: number, y1: number, x2: number, y2: number): CanvasGradient; |
| 170 | + createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number): CanvasGradient; |
| 171 | + createPattern( |
| 172 | + image: HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageBitmap | Context, |
| 173 | + repetition: "repeat" | "repeat-x" | "repeat-y" | "no-repeat", |
| 174 | + ): CanvasPattern | null; |
| 175 | + |
| 176 | + // Line dash |
| 177 | + setLineDash(dashArray: ReadonlyArray<number> | null): void; |
| 178 | + |
| 179 | + // Image data methods (async versions) |
| 180 | + getImageData( |
| 181 | + sx: number, |
| 182 | + sy: number, |
| 183 | + sw: number, |
| 184 | + sh: number, |
| 185 | + options?: { async?: boolean }, |
| 186 | + ): ImageData | Promise<ImageData>; |
| 187 | + createImageData(): ImageData; |
| 188 | + putImageData(): void; |
| 189 | + |
| 190 | + // SVG-specific methods |
| 191 | + /** |
| 192 | + * Returns the SVG as a serialized string |
| 193 | + * @param fixNamedEntities - If true, fixes named entities to numbered entities |
| 194 | + */ |
| 195 | + getSerializedSvg(fixNamedEntities?: boolean): string; |
| 196 | + |
| 197 | + /** |
| 198 | + * Returns the SVG root element |
| 199 | + */ |
| 200 | + getSvg(): SVGSVGElement; |
| 201 | +} |
| 202 | + |
| 203 | +/** |
| 204 | + * Element - A canvas-like element that uses SVG |
| 205 | + * |
| 206 | + * This class provides a wrapper that mimics HTMLCanvasElement behavior |
| 207 | + * while using SVG as the underlying rendering technology. |
| 208 | + */ |
| 209 | +export class Element { |
| 210 | + ctx: Context; |
| 211 | + svg: SVGSVGElement; |
| 212 | + wrapper: HTMLDivElement; |
| 213 | + className: string; |
| 214 | + readonly tagName: string; |
| 215 | + width: number; |
| 216 | + height: number; |
| 217 | + style: CSSStyleDeclaration; |
| 218 | + id: string; |
| 219 | + |
| 220 | + constructor(options?: C2SOptions); |
| 221 | + |
| 222 | + /** |
| 223 | + * Get the 2D rendering context |
| 224 | + */ |
| 225 | + getContext(type: "2d"): Context; |
| 226 | + |
| 227 | + /** |
| 228 | + * Returns an object URL for the SVG |
| 229 | + * Remember to call URL.revokeObjectURL when done |
| 230 | + */ |
| 231 | + toObjectURL(): string; |
| 232 | + |
| 233 | + /** |
| 234 | + * Returns a data URI containing a representation of the image |
| 235 | + * @param type - Image format (image/svg+xml, image/jpeg, image/png) |
| 236 | + * @param encoderOptions - Quality for lossy formats (0-1) |
| 237 | + * @param options - If async is true, returns a Promise |
| 238 | + */ |
| 239 | + toDataURL(type?: string, encoderOptions?: number, options?: { async?: boolean }): string | Promise<string>; |
| 240 | + |
| 241 | + addEventListener( |
| 242 | + type: string, |
| 243 | + listener: EventListenerOrEventListenerObject, |
| 244 | + options?: boolean | AddEventListenerOptions, |
| 245 | + ): void; |
| 246 | + getElement(): HTMLDivElement; |
| 247 | + getAttribute(prop: string): string | null; |
| 248 | + setAttribute(prop: string, val: string): void; |
| 249 | + getBoundingClientRect(): DOMRect; |
| 250 | +} |
0 commit comments