UNPKG

@storiny/obelisk

Version:

Build isometrics elements with canvas

1 lines 147 kB
{"version":3,"file":"index.mjs","sources":["../src/colors/AbstractColor.ts","../src/utils/ColorGeom.ts","../src/colors/CubeColor.ts","../src/colors/LineColor.ts","../src/colors/PyramidColor.ts","../src/colors/SideColor.ts","../src/colors/SlopeColor.ts","../src/dimensions/AbstractDimension.ts","../src/dimensions/BrickDimension.ts","../src/dimensions/CubeDimension.ts","../src/dimensions/LineXDimension.ts","../src/dimensions/LineYDimension.ts","../src/dimensions/LineZDimension.ts","../src/dimensions/PyramidDimension.ts","../src/dimensions/SideXDimension.ts","../src/dimensions/SideYDimension.ts","../src/dimensions/SlopeDimension.ts","../src/primitives/AbstractPrimitive.ts","../src/geom/Matrix.ts","../src/geom/Point.ts","../src/geom/Point3D.ts","../src/utils/CanvasManager.ts","../src/display/BitmapData.ts","../src/primitives/Brick.ts","../src/display/PixelObject.ts","../src/primitives/SideX.ts","../src/primitives/SideY.ts","../src/primitives/Cube.ts","../src/primitives/LineX.ts","../src/primitives/LineY.ts","../src/primitives/LineZ.ts","../src/primitives/Pyramid.ts","../src/primitives/SlopeEast.ts","../src/primitives/SlopeNorth.ts","../src/primitives/SlopeSouth.ts","../src/primitives/SlopeWest.ts","../src/display/PixelView.ts","../src/utils/CanvasTool.ts","../src/utils/ColorPattern.ts"],"sourcesContent":["export class AbstractColor {\r\n /**\r\n * The inner colors for elements of certain primitive\r\n */\r\n public inner: number | null;\r\n\r\n /**\r\n * The border colors for elements of certain primitive\r\n */\r\n public border: number | null;\r\n\r\n /**\r\n * The borderHighlight colors for elements of certain primitive\r\n */\r\n public borderHighlight: number | null;\r\n\r\n /**\r\n * The left side colors for elements of certain primitive\r\n */\r\n public left: number | null;\r\n\r\n /**\r\n * The right side colors for elements of certain primitive\r\n */\r\n public right: number | null;\r\n\r\n /**\r\n * The horizontal colors for elements of certain primitive\r\n */\r\n public horizontal: number | null;\r\n\r\n /**\r\n * The left slot side colors for elements of certain primitive\r\n */\r\n public leftSlope: number | null;\r\n\r\n /**\r\n * The right slot side colors for elements of certain primitive\r\n */\r\n public rightSlope: number | null;\r\n\r\n constructor({\r\n inner = null,\r\n left = null,\r\n right = null,\r\n border = null,\r\n borderHighlight = null,\r\n horizontal = null,\r\n leftSlope = null,\r\n rightSlope = null,\r\n }: {\r\n inner?: number | null;\r\n left?: number | null;\r\n right?: number | null;\r\n border?: number | null;\r\n borderHighlight?: number | null;\r\n horizontal?: number | null;\r\n leftSlope?: number | null;\r\n rightSlope?: number | null;\r\n } = {}) {\r\n this.inner = inner;\r\n this.left = left;\r\n this.right = right;\r\n this.border = border;\r\n this.borderHighlight = borderHighlight;\r\n this.horizontal = horizontal;\r\n this.leftSlope = leftSlope;\r\n this.rightSlope = rightSlope;\r\n }\r\n\r\n public static toString(): string {\r\n return \"[AbstractColor]\";\r\n }\r\n}\r\n","/* eslint-disable no-bitwise */\r\n\r\nexport abstract class ColorGeom {\r\n public static get32(color: number): number {\r\n return color < 0xff000000 ? color + 0xff000000 : color;\r\n }\r\n\r\n public static applyBrightness(\r\n color: number,\r\n brightness: number,\r\n highlight?: boolean\r\n ): number {\r\n let r;\r\n let g;\r\n let b;\r\n let y;\r\n\r\n const a = (color >>> 24) & 0x000000ff;\r\n r = (color >>> 16) & 0x000000ff;\r\n g = (color >>> 8) & 0x000000ff;\r\n b = color & 0x000000ff;\r\n\r\n y = ((r * 313524) >> 20) + ((g * 615514) >> 20) + ((b * 119538) >> 20);\r\n const u =\r\n -((155189 * r) >> 20) - ((303038 * g) >> 20) + ((458227 * b) >> 20);\r\n const v =\r\n ((644874 * r) >> 20) - ((540016 * g) >> 20) - ((104857 * b) >> 20);\r\n\r\n if (!highlight) {\r\n y += brightness;\r\n } else {\r\n y = 60 + y ** 1.2;\r\n }\r\n\r\n r = y + ((1195376 * v) >> 20);\r\n g = y - ((408944 * u) >> 20) - ((608174 * v) >> 20);\r\n b = y + ((2128609 * u) >> 20);\r\n\r\n r = Math.max(0, Math.min(r, 255));\r\n g = Math.max(0, Math.min(g, 255));\r\n b = Math.max(0, Math.min(b, 255));\r\n\r\n return (a << 24) | (r << 16) | (g << 8) | b;\r\n }\r\n}\r\n\r\nColorGeom.toString = () => \"[ColorGeom]\";\r\n","import { AbstractColor } from \"./AbstractColor\";\r\nimport { ColorGeom } from \"../utils/ColorGeom\";\r\n\r\nexport class CubeColor extends AbstractColor {\r\n public brightnessGain = -20;\r\n\r\n constructor(\r\n border?: number,\r\n borderHighlight?: number,\r\n left?: number,\r\n right?: number,\r\n horizontal?: number\r\n ) {\r\n super();\r\n this.border = ColorGeom.get32(border === undefined ? 0x878787 : border);\r\n this.borderHighlight = ColorGeom.get32(\r\n borderHighlight === undefined ? 0xffffff : borderHighlight\r\n );\r\n this.left = ColorGeom.get32(left === undefined ? 0xc9cfd0 : left);\r\n this.right = ColorGeom.get32(right === undefined ? 0xe3e3e3 : right);\r\n this.horizontal = ColorGeom.get32(\r\n horizontal === undefined ? 0xeeeff0 : horizontal\r\n );\r\n }\r\n\r\n public getByHorizontalColor(horizontal: number): CubeColor {\r\n return new CubeColor(\r\n ColorGeom.applyBrightness(horizontal, this.brightnessGain * 4),\r\n // Apply highlight\r\n ColorGeom.applyBrightness(horizontal, 0, true),\r\n ColorGeom.applyBrightness(horizontal, this.brightnessGain * 2),\r\n ColorGeom.applyBrightness(horizontal, this.brightnessGain),\r\n horizontal\r\n );\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[CubeColor]\";\r\n }\r\n}\r\n","import { AbstractColor } from \"./AbstractColor\";\r\nimport { ColorGeom } from \"../utils/ColorGeom\";\r\n\r\nexport class LineColor extends AbstractColor {\r\n constructor(border?: number, inner?: number) {\r\n super({ border: border || null, inner: inner || null });\r\n this.border = ColorGeom.get32(border === undefined ? 0x878787 : border);\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[LineColor]\";\r\n }\r\n}\r\n","import { AbstractColor } from \"./AbstractColor\";\r\nimport { ColorGeom } from \"../utils/ColorGeom\";\r\n\r\nexport class PyramidColor extends AbstractColor {\r\n public brightnessGain = -20;\r\n\r\n constructor(\r\n border?: number,\r\n borderHighlight?: number,\r\n left?: number,\r\n right?: number\r\n ) {\r\n super();\r\n this.border = ColorGeom.get32(border === undefined ? 0x949698 : border);\r\n this.borderHighlight = ColorGeom.get32(\r\n borderHighlight === undefined ? 0xffffff : borderHighlight\r\n );\r\n this.left = ColorGeom.get32(left === undefined ? 0xe6e8e9 : left);\r\n this.right = ColorGeom.get32(right === undefined ? 0xeeeff0 : right);\r\n }\r\n\r\n public getByRightColor(right: number): PyramidColor {\r\n return new PyramidColor(\r\n ColorGeom.applyBrightness(right, this.brightnessGain * 4),\r\n // Apply highlight\r\n ColorGeom.applyBrightness(right, 0, true),\r\n ColorGeom.applyBrightness(right, this.brightnessGain),\r\n right\r\n );\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[PyramidColor]\";\r\n }\r\n}\r\n","import { AbstractColor } from \"./AbstractColor\";\r\nimport { ColorGeom } from \"../utils/ColorGeom\";\r\n\r\nexport class SideColor extends AbstractColor {\r\n public brightnessGain = -20;\r\n\r\n constructor(border?: number, inner?: number) {\r\n super();\r\n this.border = ColorGeom.get32(border === undefined ? 0x878787 : border);\r\n this.inner = ColorGeom.get32(inner === undefined ? 0xeeeeee : inner);\r\n }\r\n\r\n public getByInnerColor(inner: number): SideColor {\r\n return new SideColor(\r\n ColorGeom.applyBrightness(inner, this.brightnessGain * 4),\r\n inner\r\n );\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[SideColor]\";\r\n }\r\n}\r\n","import { AbstractColor } from \"./AbstractColor\";\r\nimport { ColorGeom } from \"../utils/ColorGeom\";\r\n\r\nexport class SlopeColor extends AbstractColor {\r\n public brightnessGain = -20;\r\n\r\n constructor(\r\n border?: number,\r\n borderHighlight?: number,\r\n left?: number,\r\n right?: number,\r\n leftSlope?: number,\r\n rightSlope?: number\r\n ) {\r\n super();\r\n this.border = ColorGeom.get32(border === undefined ? 0x949698 : border);\r\n this.borderHighlight = ColorGeom.get32(\r\n borderHighlight === undefined ? 0xffffff : borderHighlight\r\n );\r\n this.left = ColorGeom.get32(left === undefined ? 0xc9cfd0 : left);\r\n this.right = ColorGeom.get32(right === undefined ? 0xe6e8e9 : right);\r\n this.leftSlope = ColorGeom.get32(\r\n leftSlope === undefined ? 0xdbdbdb : leftSlope\r\n );\r\n this.rightSlope = ColorGeom.get32(\r\n rightSlope === undefined ? 0xdbdbdb : rightSlope\r\n );\r\n }\r\n\r\n /*\r\n * Horizontal side doesn't actually exist in the Slope primitive.\r\n * You can assign the same horizontal color as cube\r\n * so that you will be able to arrange the slope with cube\r\n */\r\n public getByHorizontalColor(horizontal: number): SlopeColor {\r\n return new SlopeColor(\r\n ColorGeom.applyBrightness(horizontal, this.brightnessGain * 4),\r\n // Apply highlight\r\n ColorGeom.applyBrightness(horizontal, 0, true),\r\n ColorGeom.applyBrightness(horizontal, this.brightnessGain * 2),\r\n ColorGeom.applyBrightness(horizontal, this.brightnessGain),\r\n ColorGeom.applyBrightness(horizontal, this.brightnessGain * 1.5),\r\n ColorGeom.applyBrightness(horizontal, this.brightnessGain * 0.5)\r\n );\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[SlopeColor]\";\r\n }\r\n}\r\n","export class AbstractDimension {\r\n /**\r\n * The x Axis dimensions in 22.6 degrees coordinate\r\n */\r\n public xAxis: number | null;\r\n\r\n /**\r\n * The y Axis dimensions in 22.6 degrees coordinate\r\n */\r\n public yAxis: number | null;\r\n\r\n /**\r\n * The z Axis dimensions in 22.6 degrees coordinate\r\n */\r\n public zAxis: number | null;\r\n\r\n /**\r\n * Pyramid tall mode\r\n */\r\n public tall: boolean;\r\n\r\n constructor({\r\n xAxis = null,\r\n yAxis = null,\r\n zAxis = null,\r\n tall = false,\r\n }: {\r\n xAxis?: number | null;\r\n yAxis?: number | null;\r\n zAxis?: number | null;\r\n tall?: boolean;\r\n } = {}) {\r\n this.xAxis = xAxis;\r\n this.yAxis = yAxis;\r\n this.zAxis = zAxis;\r\n this.tall = tall;\r\n }\r\n\r\n public static toString(): string {\r\n return \"[AbstractDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class BrickDimension extends AbstractDimension {\r\n constructor(xAxis?: number, yAxis?: number) {\r\n super();\r\n this.xAxis = xAxis || 30;\r\n this.yAxis = yAxis || 30;\r\n\r\n if (this.xAxis % 2 === 1 || this.yAxis % 2 === 1) {\r\n throw new Error(\"xAxis / yAxis must be an even number\");\r\n }\r\n\r\n // If xAxis or yAxis = 4 then floodFill can not be applied\r\n if (this.xAxis <= 4 || this.yAxis <= 4) {\r\n throw new Error(\"Dimensions are too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[BrickDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class CubeDimension extends AbstractDimension {\r\n constructor(xAxis?: number, yAxis?: number, zAxis?: number) {\r\n super();\r\n this.xAxis = xAxis || 30;\r\n this.yAxis = yAxis || 30;\r\n this.zAxis = zAxis || 30;\r\n\r\n if (this.xAxis % 2 === 1 || this.yAxis % 2 === 1) {\r\n throw new Error(\"xAxis / yAxis must be an even number\");\r\n }\r\n\r\n // If axis = 4 then floodFill can not be applied\r\n if (this.xAxis <= 4 || this.yAxis <= 4 || this.zAxis <= 2) {\r\n throw new Error(\"Dimensions are too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[CubeDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class LineXDimension extends AbstractDimension {\r\n constructor(xAxis?: number) {\r\n super();\r\n this.xAxis = xAxis || 30;\r\n\r\n if (this.xAxis % 2 === 1) {\r\n throw new Error(\"xAxis must be an even number\");\r\n }\r\n\r\n if (this.xAxis < 2) {\r\n throw new Error(\"Dimension is too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[LineXDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class LineYDimension extends AbstractDimension {\r\n constructor(yAxis?: number) {\r\n super();\r\n this.yAxis = yAxis || 30;\r\n\r\n if (this.yAxis % 2 === 1) {\r\n throw new Error(\"yAxis must be an even number\");\r\n }\r\n\r\n if (this.yAxis < 2) {\r\n throw new Error(\"Dimension is too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[LineYDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class LineZDimension extends AbstractDimension {\r\n constructor(zAxis?: number) {\r\n super();\r\n this.zAxis = zAxis || 30;\r\n\r\n if (this.zAxis <= 0) {\r\n throw new Error(\"Dimension is too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[LineZDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class PyramidDimension extends AbstractDimension {\r\n constructor(axis?: number, tall?: boolean) {\r\n super();\r\n this.xAxis = axis || 30;\r\n this.yAxis = axis || 30;\r\n this.tall = tall || false;\r\n\r\n if (this.xAxis % 2 === 1) {\r\n throw new Error(\"Axis must be an even number\");\r\n }\r\n\r\n if (this.xAxis <= 4) {\r\n throw new Error(\"Dimension is too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[PyramidDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class SideXDimension extends AbstractDimension {\r\n constructor(xAxis?: number, zAxis?: number) {\r\n super();\r\n this.xAxis = xAxis || 30;\r\n this.zAxis = zAxis || 30;\r\n\r\n if (this.xAxis % 2 === 1) {\r\n throw new Error(\"xAxis must be an even number\");\r\n }\r\n\r\n // If xAxis or zAxis = 4 floodFill cannot be applied\r\n if (this.xAxis <= 4 || this.zAxis <= 2) {\r\n throw new Error(\"Dimensions are too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[SideXDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class SideYDimension extends AbstractDimension {\r\n constructor(yAxis?: number, zAxis?: number) {\r\n super();\r\n this.yAxis = yAxis || 30;\r\n this.zAxis = zAxis || 30;\r\n\r\n if (this.yAxis % 2 === 1) {\r\n throw new Error(\"yAxis must be an even number\");\r\n }\r\n\r\n // If yAxis or zAxis = 4 floodFill cannot be applied\r\n if (this.yAxis <= 4 || this.zAxis <= 2) {\r\n throw new Error(\"Dimensions are too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[SideYDimension]\";\r\n }\r\n}\r\n","import { AbstractDimension } from \"./AbstractDimension\";\r\n\r\nexport class SlopeDimension extends AbstractDimension {\r\n constructor(xAxis?: number, yAxis?: number) {\r\n super();\r\n this.xAxis = xAxis || 30;\r\n this.yAxis = yAxis || 30;\r\n\r\n if (this.xAxis % 2 === 1 || this.yAxis % 2 === 1) {\r\n throw new Error(\"xAxis and yAxis must be even numbers\");\r\n }\r\n\r\n if (this.xAxis <= 4 || this.yAxis <= 4) {\r\n throw new Error(\"Dimensions are too small\");\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[SlopeDimension]\";\r\n }\r\n}\r\n","import type { Dimension } from \"../dimensions\";\r\nimport type { Color } from \"../colors\";\r\nimport type { BitmapData } from \"../display/BitmapData\";\r\nimport type { Matrix } from \"../geom\";\r\n\r\nexport class AbstractPrimitive {\r\n /**\r\n * The canvas for drawImage\r\n */\r\n public canvas: HTMLCanvasElement | null;\r\n\r\n /**\r\n * The width of the bitmap in 2d flash coordinate\r\n */\r\n protected w: number | null;\r\n\r\n /**\r\n * The height of the bitmap in 2d flash coordinate\r\n */\r\n protected h: number | null;\r\n\r\n /**\r\n * The dimension of primitive in 3d pixel coordinate\r\n */\r\n protected dimension: Dimension | null;\r\n\r\n /**\r\n * The color obj of the primitive\r\n */\r\n protected color: Color | null;\r\n\r\n /**\r\n * The border option of the primitive\r\n */\r\n protected border: boolean | null;\r\n\r\n /**\r\n * The source bitmapData containing pixel graphic\r\n */\r\n protected bitmapData: BitmapData | null;\r\n\r\n /**\r\n * The preserve canvas option\r\n */\r\n protected useDefaultCanvas: boolean | null;\r\n\r\n /**\r\n * The matrix offset between the bitmap and the 3d pixel coordinate zero point\r\n */\r\n protected matrix: Matrix | null;\r\n\r\n constructor({\r\n canvas = null,\r\n w = null,\r\n h = null,\r\n dimension = null,\r\n color = null,\r\n border = null,\r\n bitmapData = null,\r\n useDefaultCanvas = null,\r\n matrix = null,\r\n }: {\r\n canvas?: HTMLCanvasElement | null;\r\n w?: number | null;\r\n h?: number | null;\r\n dimension?: Dimension | null;\r\n color?: Color | null;\r\n border?: boolean | null;\r\n bitmapData?: BitmapData | null;\r\n useDefaultCanvas?: boolean | null;\r\n matrix?: Matrix | null;\r\n } = {}) {\r\n this.canvas = canvas;\r\n this.w = w;\r\n this.h = h;\r\n this.dimension = dimension;\r\n this.color = color;\r\n this.border = border;\r\n this.bitmapData = bitmapData;\r\n this.useDefaultCanvas = useDefaultCanvas;\r\n this.matrix = matrix;\r\n }\r\n\r\n public static toString(): string {\r\n return \"[AbstractPrimitive]\";\r\n }\r\n}\r\n","export class Matrix {\r\n /**\r\n * Position (0, 0) in a 3x3 matrix.\r\n * */\r\n public a: number;\r\n\r\n /**\r\n * Position (0, 1) in a 3x3 matrix.\r\n * */\r\n public b: number;\r\n\r\n /**\r\n * Position (1, 0) in a 3x3 matrix.\r\n * */\r\n public c: number;\r\n\r\n /**\r\n * Position (1, 1) in a 3x3 matrix.\r\n * */\r\n public d: number;\r\n\r\n /**\r\n * Position (2, 0) in a 3x3 matrix.\r\n * */\r\n public tx: number;\r\n\r\n /**\r\n * Position (2, 1) in a 3x3 matrix.\r\n * */\r\n public ty: number;\r\n\r\n constructor(\r\n a?: number,\r\n b?: number,\r\n c?: number,\r\n d?: number,\r\n tx?: number,\r\n ty?: number\r\n ) {\r\n this.a = a === undefined ? 1 : a;\r\n this.b = b || 0;\r\n this.c = c || 0;\r\n this.d = d === undefined ? 1 : d;\r\n this.tx = tx || 0;\r\n this.ty = ty || 0;\r\n }\r\n\r\n public static toString(): string {\r\n return \"[Matrix]\";\r\n }\r\n}\r\n","export class Point {\r\n public x: number;\r\n\r\n public y: number;\r\n\r\n constructor(x?: number, y?: number) {\r\n this.x = x === undefined ? 0 : x;\r\n this.y = y === undefined ? 0 : y;\r\n }\r\n\r\n public toString(): string {\r\n return `[Point x: ${this.x}, y: ${this.y}]`;\r\n }\r\n}\r\n","import { Point } from \"./Point\";\r\n\r\nexport class Point3D {\r\n public x: number;\r\n\r\n public y: number;\r\n\r\n public z: number;\r\n\r\n constructor(x?: number, y?: number, z?: number) {\r\n this.x = x === undefined ? 0 : x;\r\n this.y = y === undefined ? 0 : y;\r\n this.z = z === undefined ? 0 : z;\r\n }\r\n\r\n public toGlobalCoordinates(offset?: { x: number; y: number }): Point {\r\n const p2D = new Point(\r\n this.x - this.y,\r\n Math.floor(this.x / 2 + this.y / 2) - this.z\r\n );\r\n\r\n if (offset !== undefined) {\r\n p2D.x += offset.x;\r\n p2D.y += offset.y;\r\n }\r\n\r\n return p2D;\r\n }\r\n\r\n public toString(): string {\r\n return `[Point3D x : ${this.x}, y : ${this.y}, z: ${this.z}]`;\r\n }\r\n}\r\n","export abstract class CanvasManager {\r\n public static defaultCanvas: HTMLCanvasElement | null;\r\n\r\n public static getDefaultCanvas(): HTMLCanvasElement | null {\r\n this.defaultCanvas = this.defaultCanvas || document.createElement(\"canvas\");\r\n return this.defaultCanvas;\r\n }\r\n\r\n public static getNewCanvas(): HTMLCanvasElement {\r\n return document.createElement(\"canvas\");\r\n }\r\n\r\n public static toString(): string {\r\n return \"[CanvasManager]\";\r\n }\r\n}\r\n","/* eslint-disable no-bitwise */\r\n\r\nimport { CanvasManager } from \"../utils/CanvasManager\";\r\n\r\nexport class BitmapData {\r\n public imageData: ImageData | null;\r\n\r\n public canvas: HTMLCanvasElement | null;\r\n\r\n public context: CanvasRenderingContext2D | null;\r\n\r\n constructor(w?: number, h?: number, useDefaultCanvas?: boolean) {\r\n if (w === undefined || h === undefined) {\r\n throw new Error(\"BitmapData width or height is missing\");\r\n }\r\n\r\n if (useDefaultCanvas) {\r\n this.canvas = CanvasManager.getDefaultCanvas();\r\n } else {\r\n this.canvas = CanvasManager.getNewCanvas();\r\n }\r\n\r\n this.imageData = null;\r\n this.context = null;\r\n\r\n if (this.canvas) {\r\n this.canvas.setAttribute(\"width\", w.toString());\r\n this.canvas.setAttribute(\"height\", h.toString());\r\n\r\n this.context = this.canvas.getContext(\"2d\") || null;\r\n\r\n if (this.context) {\r\n this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);\r\n\r\n (this.context as any).mozImageSmoothingEnabled = false;\r\n (this.context as any).msImageSmoothingEnabled = false;\r\n this.context.imageSmoothingEnabled = false;\r\n\r\n this.imageData = this.context.createImageData(w, h);\r\n }\r\n }\r\n }\r\n\r\n public setPixel(posX: number, posY: number, color: number): void {\r\n if (this.imageData) {\r\n const index = (posY * this.imageData.width + posX) * 4;\r\n this.setPixelByIndex(index, color);\r\n }\r\n }\r\n\r\n public setPixelByIndex(index: number, color: number): void {\r\n if (this.imageData) {\r\n const pixels = this.imageData.data;\r\n\r\n pixels[index] = (color >>> 16) & 0xff;\r\n pixels[index + 1] = (color >>> 8) & 0xff;\r\n pixels[index + 2] = (color >>> 0) & 0xff;\r\n pixels[index + 3] = (color >>> 24) & 0xff;\r\n }\r\n }\r\n\r\n public checkPixelAvailable(x: number, y: number): boolean {\r\n if (this.imageData) {\r\n const index = (y * this.imageData.width + x) * 4;\r\n return this.imageData.data[index + 3] === 0;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n public floodFill(posX: number, posY: number, color: number): void {\r\n if (((color >>> 24) & 0xff) === 0x00 || !this.imageData) {\r\n // Transparent flood fill\r\n return;\r\n }\r\n\r\n let x = posX;\r\n let y = posY;\r\n\r\n const stack: number[] = [];\r\n let nowCol: number[] = [];\r\n let prevCol: number[] = [];\r\n\r\n let col: number;\r\n let row: number;\r\n let matchFlag: boolean;\r\n let newStart: number;\r\n\r\n const w = this.imageData.width;\r\n const h = this.imageData.height;\r\n\r\n let i: number;\r\n let j: number;\r\n\r\n // Bound reach\r\n if (x < 0 || y < 0 || x >= w || y >= h) {\r\n return;\r\n }\r\n\r\n // First point check fail\r\n if (!this.checkPixelAvailable(x, y)) {\r\n throw new Error(\"Start point for flood fill is already filled\");\r\n }\r\n\r\n // Left side flood fill\r\n for (col = x; col >= 0; col -= 1) {\r\n // Top side\r\n for (row = y; row >= 0; row -= 1) {\r\n if (this.checkPixelAvailable(col, row)) {\r\n // Available pixel\r\n stack.push((row * w + col) * 4);\r\n nowCol.push(row);\r\n } else {\r\n // First one is invalid pixel and not at col top\r\n if (row === y && this.checkPixelAvailable(col + 1, row - 1)) {\r\n // Next one is valid\r\n if (this.checkPixelAvailable(col, row - 1)) {\r\n newStart = row - 1;\r\n } else if (this.checkPixelAvailable(col + 1, row - 2)) {\r\n newStart = row - 2;\r\n } else {\r\n // Fail, assign max value to avoid loop below\r\n newStart = -1;\r\n }\r\n\r\n for (row = newStart; row >= 0; row -= 1) {\r\n if (this.checkPixelAvailable(col, row)) {\r\n // Available pixel\r\n stack.push((row * w + col) * 4);\r\n nowCol.push(row);\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n // Bottom side\r\n for (row = y; row < h; row += 1) {\r\n if (this.checkPixelAvailable(col, row)) {\r\n // Available pixel\r\n stack.push((row * w + col) * 4);\r\n nowCol.push(row);\r\n } else {\r\n // First one is invalid pixel and not at col bottom\r\n if (row === y && this.checkPixelAvailable(col + 1, row + 1)) {\r\n // Next one is valid\r\n if (this.checkPixelAvailable(col, row + 1)) {\r\n newStart = row + 1;\r\n } else if (this.checkPixelAvailable(col + 1, row + 2)) {\r\n newStart = row + 2;\r\n } else {\r\n // Fail, assign max value to avoid loop below\r\n newStart = h;\r\n }\r\n\r\n for (row = newStart; row < h; row += 1) {\r\n if (this.checkPixelAvailable(col, row)) {\r\n // AAvailable pixel\r\n stack.push((row * w + col) * 4);\r\n nowCol.push(row);\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n // Compare with previous column\r\n // for first column,\r\n // the given point should be inside the container\r\n if (col === x) {\r\n prevCol = nowCol.concat();\r\n }\r\n\r\n matchFlag = false;\r\n\r\n for (i = 0; i < prevCol.length; i += 1) {\r\n for (j = 0; j < prevCol.length; j += 1) {\r\n if (nowCol[j] === prevCol[i]) {\r\n matchFlag = true;\r\n y = prevCol[i]!;\r\n break;\r\n }\r\n }\r\n\r\n if (matchFlag) {\r\n break;\r\n }\r\n }\r\n\r\n if (matchFlag) {\r\n prevCol = nowCol.concat();\r\n nowCol = [];\r\n } else {\r\n // Bound reach\r\n break;\r\n }\r\n }\r\n\r\n // Reset start point\r\n x = posX;\r\n y = posY;\r\n prevCol = [];\r\n nowCol = [];\r\n\r\n // Right side flood fill\r\n for (col = x; col < w; col += 1) {\r\n // Top side\r\n for (row = y; row >= 0; row -= 1) {\r\n if (this.checkPixelAvailable(col, row)) {\r\n // Available pixel\r\n stack.push((row * w + col) * 4);\r\n nowCol.push(row);\r\n } else {\r\n // First one is invalid pixel and not at col top\r\n if (row === y && this.checkPixelAvailable(col - 1, row - 1)) {\r\n // Next one is valid\r\n if (this.checkPixelAvailable(col, row - 1)) {\r\n newStart = row - 1;\r\n } else if (this.checkPixelAvailable(col - 1, row - 2)) {\r\n newStart = row - 2;\r\n } else {\r\n // Fail, assign max value to avoid loop below\r\n newStart = -1;\r\n }\r\n\r\n for (row = newStart; row >= 0; row -= 1) {\r\n if (this.checkPixelAvailable(col, row)) {\r\n // Available pixel\r\n stack.push((row * w + col) * 4);\r\n nowCol.push(row);\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n // Bottom side\r\n for (row = y; row < h; row += 1) {\r\n if (this.checkPixelAvailable(col, row)) {\r\n // Available pixel\r\n stack.push((row * w + col) * 4);\r\n nowCol.push(row);\r\n } else {\r\n // First one is invalid pixel && not at col bottom\r\n if (row === y && this.checkPixelAvailable(col - 1, row + 1)) {\r\n // Next one is valid\r\n if (this.checkPixelAvailable(col, row + 1)) {\r\n newStart = row + 1;\r\n } else if (this.checkPixelAvailable(col - 1, row + 2)) {\r\n newStart = row + 2;\r\n } else {\r\n // Fail, assign max value to avoid loop below\r\n newStart = h;\r\n }\r\n\r\n for (row = newStart; row < h; row += 1) {\r\n if (this.checkPixelAvailable(col, row)) {\r\n // Available pixel\r\n stack.push((row * w + col) * 4);\r\n nowCol.push(row);\r\n } else {\r\n break;\r\n }\r\n }\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n // Compare with previous column\r\n // for first column,\r\n // the given point should be inside the container\r\n if (col === x) {\r\n prevCol = nowCol.concat();\r\n }\r\n\r\n matchFlag = false;\r\n\r\n for (i = 0; i < prevCol.length; i += 1) {\r\n for (j = 0; j < prevCol.length; j += 1) {\r\n if (nowCol[j] === prevCol[i]) {\r\n matchFlag = true;\r\n y = prevCol[i]!;\r\n break;\r\n }\r\n }\r\n\r\n if (matchFlag) {\r\n break;\r\n }\r\n }\r\n\r\n if (matchFlag) {\r\n prevCol = nowCol.concat();\r\n nowCol = [];\r\n } else {\r\n // Bound reach\r\n break;\r\n }\r\n }\r\n\r\n // Fill image data\r\n for (i = 0; i < stack.length; i += 1) {\r\n this.setPixelByIndex(stack[i]!, color);\r\n }\r\n }\r\n\r\n public static toString(): string {\r\n return \"[BitmapData]\";\r\n }\r\n}\r\n","import { BrickDimension } from \"../dimensions\";\r\nimport { SideColor } from \"../colors\";\r\nimport { Matrix } from \"../geom\";\r\nimport { BitmapData } from \"../display/BitmapData\";\r\nimport { AbstractPrimitive } from \"./AbstractPrimitive\";\r\n\r\nexport class Brick extends AbstractPrimitive {\r\n constructor(\r\n dimension?: BrickDimension,\r\n color?: SideColor,\r\n border?: boolean,\r\n useDefaultCanvas?: boolean\r\n ) {\r\n super();\r\n\r\n this.useDefaultCanvas = useDefaultCanvas || false;\r\n this.border = border || border === undefined;\r\n this.dimension = dimension === undefined ? new BrickDimension() : dimension;\r\n this.color = color === undefined ? new SideColor() : color;\r\n\r\n this.initRectangle();\r\n this.initBitmapData();\r\n this.build();\r\n this.renderBitmapDataForCanvas();\r\n }\r\n\r\n private initRectangle(): void {\r\n this.w = this.dimension!.xAxis! + this.dimension!.yAxis!;\r\n this.h = (this.dimension!.xAxis! + this.dimension!.yAxis!) / 2;\r\n\r\n // 22.6 degrees implementation\r\n this.w -= 2;\r\n this.h -= 1;\r\n\r\n // The matrix offset between the bitmap and the 3d pixel coordinate ZERO point\r\n this.matrix = new Matrix();\r\n this.matrix.tx = -this.dimension!.yAxis! + 2;\r\n this.matrix.ty = 0;\r\n }\r\n\r\n private initBitmapData(): void {\r\n this.bitmapData = new BitmapData(\r\n this.w!,\r\n this.h!,\r\n this.useDefaultCanvas || undefined\r\n );\r\n }\r\n\r\n private renderBitmapDataForCanvas(): void {\r\n this.bitmapData!.context!.putImageData(this.bitmapData!.imageData!, 0, 0);\r\n this.canvas = this.bitmapData!.canvas;\r\n }\r\n\r\n private build(): void {\r\n const xOffsetInner = this.dimension!.yAxis! - 2;\r\n const yOffsetInner = 0;\r\n const xOffsetOut = this.dimension!.xAxis! - 1;\r\n const yOffsetOut = (this.h || 0) - 1;\r\n const borderColor = this.border ? this.color!.border! : this.color!.inner!;\r\n\r\n // X axis\r\n for (let i = 0; i < this.dimension!.xAxis!; i += 1) {\r\n this.bitmapData!.setPixel(\r\n xOffsetInner + i,\r\n yOffsetInner + Math.floor(i / 2),\r\n borderColor\r\n );\r\n\r\n this.bitmapData!.setPixel(\r\n xOffsetOut - i,\r\n yOffsetOut - Math.floor(i / 2),\r\n borderColor\r\n );\r\n }\r\n\r\n // Y axis\r\n for (let j = 0; j < this.dimension!.yAxis!; j += 1) {\r\n this.bitmapData!.setPixel(\r\n xOffsetInner + 1 - j,\r\n yOffsetInner + Math.floor(j / 2),\r\n borderColor\r\n );\r\n\r\n this.bitmapData!.setPixel(\r\n xOffsetOut - 1 + j,\r\n yOffsetOut - Math.floor(j / 2),\r\n borderColor\r\n );\r\n }\r\n\r\n // Fill a pixel graphic enclosed\r\n this.bitmapData!.floodFill(\r\n Math.floor(this.w! / 2),\r\n Math.floor(this.h! / 2),\r\n this.color!.inner!\r\n );\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[Brick]\";\r\n }\r\n}\r\n","import { Point3D } from \"../geom\";\r\nimport type { AbstractPrimitive } from \"../primitives\";\r\n\r\nexport class PixelObject {\r\n public x: number | null;\r\n\r\n public y: number | null;\r\n\r\n public canvas: HTMLCanvasElement | null;\r\n\r\n constructor(primitive?: AbstractPrimitive, point3D?: Point3D) {\r\n if (!primitive) {\r\n throw new Error(\"Primitive is not defined\");\r\n }\r\n\r\n const p3D = point3D || new Point3D();\r\n\r\n this.canvas = primitive.canvas;\r\n this.x = (primitive as any).matrix!.tx + p3D.x - p3D.y;\r\n this.y =\r\n (primitive as any).matrix!.ty + Math.floor(p3D.x / 2 + p3D.y / 2) - p3D.z;\r\n }\r\n\r\n public static toString(): string {\r\n return \"[PixelObject]\";\r\n }\r\n}\r\n","import { SideXDimension } from \"../dimensions\";\r\nimport { SideColor } from \"../colors\";\r\nimport { Matrix } from \"../geom\";\r\nimport { BitmapData } from \"../display/BitmapData\";\r\nimport { AbstractPrimitive } from \"./AbstractPrimitive\";\r\n\r\nexport class SideX extends AbstractPrimitive {\r\n constructor(\r\n dimension?: SideXDimension,\r\n color?: SideColor,\r\n border?: boolean,\r\n useDefaultCanvas?: boolean\r\n ) {\r\n super();\r\n\r\n this.useDefaultCanvas = useDefaultCanvas || false;\r\n this.border = border || border === undefined;\r\n this.dimension = dimension === undefined ? new SideXDimension() : dimension;\r\n this.color = color === undefined ? new SideColor() : color;\r\n\r\n this.initRectangle();\r\n this.initBitmapData();\r\n this.build();\r\n this.renderBitmapDataForCanvas();\r\n }\r\n\r\n private initRectangle(): void {\r\n this.w = this.dimension!.xAxis;\r\n this.h = this.dimension!.zAxis! + this.dimension!.xAxis! / 2;\r\n\r\n // The matrix offset between the bitmap and the 3d pixel coordinate zero point\r\n this.matrix = new Matrix();\r\n this.matrix.tx = 0;\r\n this.matrix.ty = -this.dimension!.zAxis!;\r\n }\r\n\r\n private initBitmapData(): void {\r\n this.bitmapData = new BitmapData(\r\n this.w!,\r\n this.h!,\r\n this.useDefaultCanvas || undefined\r\n );\r\n }\r\n\r\n private renderBitmapDataForCanvas(): void {\r\n this.bitmapData!.context!.putImageData(this.bitmapData!.imageData!, 0, 0);\r\n this.canvas = this.bitmapData!.canvas;\r\n }\r\n\r\n private build(): void {\r\n const xOffsetInner = 0;\r\n const yOffsetInner = this.dimension!.zAxis!;\r\n const xOffsetOut = this.dimension!.xAxis! - 1;\r\n const yOffsetOut = this.h! - this.dimension!.zAxis! - 1;\r\n const borderColor = this.border ? this.color!.border! : this.color!.inner!;\r\n\r\n // X axis\r\n for (let i = 0; i < this.dimension!.xAxis!; i += 1) {\r\n this.bitmapData!.setPixel(\r\n xOffsetInner + i,\r\n yOffsetInner + Math.floor(i / 2),\r\n borderColor\r\n );\r\n this.bitmapData!.setPixel(\r\n xOffsetOut - i,\r\n yOffsetOut - Math.floor(i / 2),\r\n borderColor\r\n );\r\n }\r\n\r\n // Z axis\r\n for (let j = 0; j < this.dimension!.zAxis!; j += 1) {\r\n this.bitmapData!.setPixel(xOffsetInner, yOffsetInner - j, borderColor);\r\n this.bitmapData!.setPixel(xOffsetOut, yOffsetOut + j, borderColor);\r\n }\r\n\r\n // fill an pixel graphic enclosed\r\n this.bitmapData!.floodFill(\r\n Math.floor(this.w! / 2),\r\n Math.floor(this.h! / 2),\r\n this.color!.inner!\r\n );\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[SideX]\";\r\n }\r\n}\r\n","import { SideYDimension } from \"../dimensions\";\r\nimport { SideColor } from \"../colors\";\r\nimport { Matrix } from \"../geom\";\r\nimport { BitmapData } from \"../display/BitmapData\";\r\nimport { AbstractPrimitive } from \"./AbstractPrimitive\";\r\n\r\nexport class SideY extends AbstractPrimitive {\r\n constructor(\r\n dimension?: SideYDimension,\r\n color?: SideColor,\r\n border?: boolean,\r\n useDefaultCanvas?: boolean\r\n ) {\r\n super();\r\n\r\n this.useDefaultCanvas = useDefaultCanvas || false;\r\n this.border = border || border === undefined;\r\n this.dimension = dimension === undefined ? new SideYDimension() : dimension;\r\n this.color = color === undefined ? new SideColor() : color;\r\n\r\n this.initRectangle();\r\n this.initBitmapData();\r\n this.build();\r\n this.renderBitmapDataForCanvas();\r\n }\r\n\r\n private initRectangle(): void {\r\n this.w = this.dimension!.yAxis!;\r\n this.h = this.dimension!.zAxis! + this.dimension!.yAxis! / 2;\r\n\r\n // The matrix offset between the bitmap and the 3d pixel coordinate zero point\r\n this.matrix = new Matrix();\r\n this.matrix.tx = -this.dimension!.yAxis! + 2;\r\n this.matrix.ty = -this.dimension!.zAxis!;\r\n }\r\n\r\n private initBitmapData(): void {\r\n this.bitmapData = new BitmapData(\r\n this.w!,\r\n this.h!,\r\n this.useDefaultCanvas || undefined\r\n );\r\n }\r\n\r\n private renderBitmapDataForCanvas(): void {\r\n this.bitmapData!.context!.putImageData(this.bitmapData!.imageData!, 0, 0);\r\n this.canvas = this.bitmapData!.canvas;\r\n }\r\n\r\n private build(): void {\r\n const xOffsetInner = 0;\r\n const yOffsetInner = this.h! - this.dimension!.zAxis! - 1;\r\n const xOffsetOut = this.dimension!.yAxis! - 1;\r\n const yOffsetOut = this.dimension!.zAxis!;\r\n const borderColor = this.border ? this.color!.border! : this.color!.inner!;\r\n\r\n // Y axis\r\n for (let i = 0; i < this.dimension!.yAxis!; i += 1) {\r\n this.bitmapData!.setPixel(\r\n xOffsetInner + i,\r\n yOffsetInner - Math.floor(i / 2),\r\n borderColor\r\n );\r\n\r\n this.bitmapData!.setPixel(\r\n xOffsetOut - i,\r\n yOffsetOut + Math.floor(i / 2),\r\n borderColor\r\n );\r\n }\r\n\r\n // Z axis\r\n for (let j = 0; j < this.dimension!.zAxis!; j += 1) {\r\n this.bitmapData!.setPixel(xOffsetInner, yOffsetInner + j, borderColor);\r\n this.bitmapData!.setPixel(xOffsetOut, yOffsetOut - j, borderColor);\r\n }\r\n\r\n // Fill a pixel graphic enclosed\r\n this.bitmapData!.floodFill(\r\n Math.floor(this.w! / 2),\r\n Math.floor(this.h! / 2),\r\n this.color!.inner!\r\n );\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[SideY]\";\r\n }\r\n}\r\n","import {\r\n CubeDimension,\r\n BrickDimension,\r\n SideYDimension,\r\n SideXDimension,\r\n} from \"../dimensions\";\r\nimport { CubeColor, SideColor } from \"../colors\";\r\nimport { Matrix } from \"../geom\";\r\nimport { PixelObject } from \"../display/PixelObject\";\r\nimport { BitmapData } from \"../display/BitmapData\";\r\nimport { AbstractPrimitive } from \"./AbstractPrimitive\";\r\nimport { Brick } from \"./Brick\";\r\nimport { SideX } from \"./SideX\";\r\nimport { SideY } from \"./SideY\";\r\n\r\nexport class Cube extends AbstractPrimitive {\r\n constructor(\r\n dimension?: CubeDimension,\r\n color?: CubeColor,\r\n border?: boolean,\r\n useDefaultCanvas?: boolean\r\n ) {\r\n super();\r\n\r\n this.useDefaultCanvas = useDefaultCanvas || false;\r\n this.border = border || border === undefined;\r\n this.dimension = dimension === undefined ? new CubeDimension() : dimension;\r\n this.color = color === undefined ? new CubeColor() : color;\r\n\r\n this.initRectangle();\r\n this.initBitmapData();\r\n this.build();\r\n this.renderBitmapDataForCanvas();\r\n }\r\n\r\n private initRectangle(): void {\r\n this.w = this.dimension!.xAxis! + this.dimension!.yAxis!;\r\n this.h =\r\n this.dimension!.zAxis! +\r\n (this.dimension!.xAxis! + this.dimension!.yAxis!) / 2;\r\n\r\n // 22.6 degrees implementation\r\n this.w -= 2;\r\n this.h -= 1;\r\n\r\n // The matrix offset between the bitmap and the 3d pixel coordinate zero point\r\n this.matrix = new Matrix();\r\n this.matrix.tx = -this.dimension!.yAxis! + 2;\r\n this.matrix.ty = -this.dimension!.zAxis!;\r\n }\r\n\r\n private initBitmapData(): void {\r\n this.bitmapData = new BitmapData(\r\n this.w!,\r\n this.h!,\r\n this.useDefaultCanvas || undefined\r\n );\r\n }\r\n\r\n private renderBitmapDataForCanvas(): void {\r\n this.canvas = this.bitmapData!.canvas;\r\n }\r\n\r\n private build(): void {\r\n let offsetX: number;\r\n let offsetY: number;\r\n\r\n // Horizontal layer\r\n const brick = new Brick(\r\n new BrickDimension(this.dimension!.xAxis!, this.dimension!.yAxis!),\r\n new SideColor(this.color!.border!, this.color!.horizontal!),\r\n this.border!\r\n );\r\n\r\n // Left side\r\n const sideX = new SideX(\r\n new SideXDimension(this.dimension!.xAxis!, this.dimension!.zAxis!),\r\n new SideColor(this.color!.border!, this.color!.left!),\r\n this.border!\r\n );\r\n\r\n // Right side\r\n const sideY = new SideY(\r\n new SideYDimension(this.dimension!.yAxis!, this.dimension!.zAxis!),\r\n new SideColor(this.color!.border!, this.color!.right!),\r\n this.border!\r\n );\r\n\r\n const poBrick = new PixelObject(brick);\r\n const poX = new PixelObject(sideX);\r\n const poY = new PixelObject(sideY);\r\n\r\n const ctx = this.bitmapData!.context!;\r\n\r\n ctx.drawImage(\r\n poBrick.canvas!,\r\n poBrick.x! + this.dimension!.yAxis! - 2,\r\n poBrick.y!\r\n );\r\n\r\n ctx.drawImage(\r\n poX.canvas!,\r\n poX.x!,\r\n poX.y! + this.dimension!.zAxis! + this.dimension!.yAxis! / 2 - 1\r\n );\r\n\r\n ctx.drawImage(\r\n poY.canvas!,\r\n poY.x! + this.w! - 2,\r\n poX.y! + this.dimension!.zAxis! + this.dimension!.xAxis! / 2 - 1\r\n );\r\n\r\n // Highlight & highlight fix\r\n const bmd = new BitmapData(this.w!, this.h!);\r\n\r\n if (this.border) {\r\n offsetX = this.dimension!.xAxis! - 2;\r\n offsetY = (this.dimension!.xAxis! + this.dimension!.yAxis!) / 2 - 2;\r\n\r\n // The 2px in bounding without highlight\r\n for (let i = 0; i < this.dimension!.xAxis! - 2; i += 1) {\r\n bmd.setPixel(\r\n offsetX + 1 - i,\r\n offsetY - Math.floor(i / 2),\r\n this.color!.borderHighlight!\r\n );\r\n }\r\n\r\n // the 2px in bounding without highlight\r\n for (let j = 0; j < this.dimension!.yAxis! - 2; j += 1) {\r\n bmd.setPixel(\r\n offsetX + j,\r\n offsetY - Math.floor(j / 2),\r\n this.color!.borderHighlight!\r\n );\r\n }\r\n\r\n for (let k = 0; k < this.dimension!.zAxis!; k += 1) {\r\n bmd.setPixel(offsetX, offsetY + k, this.color!.borderHighlight!);\r\n }\r\n } else {\r\n for (let i = 0; i < this.dimension!.zAxis!; i += 1) {\r\n bmd.setPixel(\r\n this.dimension!.xAxis! - 2,\r\n (this.dimension!.xAxis! + this.dimension!.yAxis!) / 2 - 1 + i,\r\n this.color!.left!\r\n );\r\n }\r\n }\r\n\r\n bmd.context!.putImageData(bmd.imageData!, 0, 0);\r\n ctx.drawImage(bmd.canvas!, 0, 0);\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[Cube]\";\r\n }\r\n}\r\n","import { LineXDimension } from \"../dimensions\";\r\nimport { LineColor } from \"../colors\";\r\nimport { Matrix } from \"../geom\";\r\nimport { BitmapData } from \"../display/BitmapData\";\r\nimport { AbstractPrimitive } from \"./AbstractPrimitive\";\r\n\r\nexport class LineX extends AbstractPrimitive {\r\n constructor(\r\n dimension?: LineXDimension,\r\n color?: LineColor,\r\n useDefaultCanvas?: boolean\r\n ) {\r\n super();\r\n\r\n this.useDefaultCanvas = useDefaultCanvas || false;\r\n this.dimension = dimension === undefined ? new LineXDimension() : dimension;\r\n this.color = color === undefined ? new LineColor() : color;\r\n\r\n this.initRectangle();\r\n this.initBitmapData();\r\n this.build();\r\n this.renderBitmapDataForCanvas();\r\n }\r\n\r\n private initRectangle(): void {\r\n this.w = this.dimension!.xAxis!;\r\n this.h = this.dimension!.xAxis! / 2;\r\n\r\n // The matrix offset between the bitmap and the 3d pixel coordinate zero point\r\n this.matrix = new Matrix();\r\n this.matrix.tx = 0;\r\n this.matrix.ty = 0;\r\n }\r\n\r\n private initBitmapData(): void {\r\n this.bitmapData = new BitmapData(\r\n this.w!,\r\n this.h!,\r\n this.useDefaultCanvas || undefined\r\n );\r\n }\r\n\r\n private renderBitmapDataForCanvas(): void {\r\n this.bitmapData!.context!.putImageData(this.bitmapData!.imageData!, 0, 0);\r\n this.canvas = this.bitmapData!.canvas;\r\n }\r\n\r\n private build(): void {\r\n const xOffsetBorder = 0;\r\n const yOffsetBorder = 0;\r\n const borderColor = this.color!.border!;\r\n\r\n // X axis\r\n for (let i = 0; i < this.dimension!.xAxis!; i += 1) {\r\n this.bitmapData!.setPixel(\r\n xOffsetBorder + i,\r\n yOffsetBorder + Math.floor(i / 2),\r\n borderColor\r\n );\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[LineX]\";\r\n }\r\n}\r\n","import { LineYDimension } from \"../dimensions\";\r\nimport { LineColor } from \"../colors\";\r\nimport { Matrix } from \"../geom\";\r\nimport { BitmapData } from \"../display/BitmapData\";\r\nimport { AbstractPrimitive } from \"./AbstractPrimitive\";\r\n\r\nexport class LineY extends AbstractPrimitive {\r\n constructor(\r\n dimension?: LineYDimension,\r\n color?: LineColor,\r\n useDefaultCanvas?: boolean\r\n ) {\r\n super();\r\n\r\n this.useDefaultCanvas = useDefaultCanvas || false;\r\n this.dimension = dimension === undefined ? new LineYDimension() : dimension;\r\n this.color = color === undefined ? new LineColor() : color;\r\n\r\n this.initRectangle();\r\n this.initBitmapData();\r\n this.build();\r\n this.renderBitmapDataForCanvas();\r\n }\r\n\r\n private initRectangle(): void {\r\n this.w = this.dimension!.yAxis!;\r\n this.h = this.dimension!.yAxis! / 2;\r\n\r\n // The matrix offset between the bitmap and the 3d pixel coordinate zero point\r\n this.matrix = new Matrix();\r\n this.matrix.tx = -this.dimension!.yAxis! + 2;\r\n this.matrix.ty = 0;\r\n }\r\n\r\n private initBitmapData(): void {\r\n this.bitmapData = new BitmapData(\r\n this.w!,\r\n this.h!,\r\n this.useDefaultCanvas || undefined\r\n );\r\n }\r\n\r\n private renderBitmapDataForCanvas(): void {\r\n this.bitmapData!.context!.putImageData(this.bitmapData!.imageData!, 0, 0);\r\n this.canvas = this.bitmapData!.canvas;\r\n }\r\n\r\n private build(): void {\r\n const xOffsetBorder = this.dimension!.yAxis! - 1;\r\n const yOffsetBorder = 0;\r\n const borderColor = this.color!.border!;\r\n\r\n // Y axis\r\n for (let i = 0; i < this.dimension!.yAxis!; i += 1) {\r\n this.bitmapData!.setPixel(\r\n xOffsetBorder - i,\r\n yOffsetBorder + Math.floor(i / 2),\r\n borderColor\r\n );\r\n }\r\n }\r\n\r\n public static override toString(): string {\r\n return \"[LineY]\";\r\n }\r\n}\r\n","import { LineZDimension } from \"../dimensions\";\r\nimport { LineColor } from \"../colors\";\r\nimport { Matrix } from \"../geom\";\r\nimport { BitmapData } from \"../display/BitmapData\";\r\nimport { AbstractPrimitive } from \"./AbstractPrimitive\";\r\n\r\nexport class LineZ extends AbstractPrimitive {\r\n constructor(\r\n dimension?: LineZDimension,\r\n color?: LineColor,\r\n useDefaultCanvas?: boolean\r\n ) {\r\n super();\r\n\r\n this.useDefaultCanvas = useDefaultCanvas || false;\r\n this.dimension = dimension === undefined ? new LineZDimension() : dimension;\r\n this.color = color === undefined ? new LineColor() : color;\r\n\r\n this.initRectangle();\r\n this.initBitmapData();\r\n this.buil