Skip to content

Commit

Permalink
Replace string types with proper string unions
Browse files Browse the repository at this point in the history
Specifically for event types and drawing types.
  • Loading branch information
caleb531 committed May 30, 2024
1 parent f5090f5 commit bbfc671
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 28 deletions.
92 changes: 88 additions & 4 deletions src/jcanvas.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,102 @@ declare module "jcanvas/dist/esm/jcanvas-handles.min.js";
interface JCanvasPluginParams<TProps> {
name: string;
props?: Record<string, any>;
type?: keyofJCanvasMapsdrawings;
type?: string;
fn: (
this: HTMLCanvasElement,
ctx: CanvasRenderingContext2D,
params: JCanvasObject & TProps
) => void;
}

type JCanvasLayerType =
| "arc"
| "bezier"
| "ellipse"
| "function"
| "image"
| "line"
| "path"
| "polygon"
| "slice"
| "quadratic"
| "rectangle"
| "text"
| "vector"
| "save"
| "restore"
| "rotate"
| "scale"
| "translate";

type JCanvasDrawingMethodName =
| "drawArc"
| "drawBezier"
| "drawEllipse"
| "draw"
| "drawImage"
| "drawLine"
| "drawPath"
| "drawPolygon"
| "drawSlice"
| "drawQuadratic"
| "drawRect"
| "drawText"
| "drawVector"
| "saveCanvas"
| "restoreCanvas"
| "rotateCanvas"
| "scaleCanvas"
| "translateCanvas";

type JCanvasMouseEventName =
| "click"
| "dblclick"
| "mousedown"
| "mouseup"
| "mousemove"
| "mouseover"
| "mouseout"
| "contextmenu";

type JCanvasTouchEventName = "touchstart" | "touchmove" | "touchend";

type JCanvasPointerEventName = "pointerdown" | "pointermove" | "pointerup";

type JCanvasDragEventName = "dragstart" | "drag" | "dragstop" | "dragcancel";

type JCanvasInteractionEventName =
| JCanvasMouseEventName
| JCanvasTouchEventName
| JCanvasPointerEventName
| JCanvasDragEventName;

type JCanvasMechanicalEventName =
| "add"
| "remove"
| "change"
| "move"
| "animatestart"
| "animate"
| "animateend"
| "stop"
| "delay";

type JCanvasImageEventName = "load";

type JCanvasEventName =
| JCanvasInteractionEventName
| JCanvasMechanicalEventName
| JCanvasImageEventName;

interface JCanvasMaps {
drawings: Record<string, string>;
touchEvents: Record<string, string>;
mouseEvents: Record<string, string>;
drawings: Record<JCanvasLayerType, JCanvasDrawingMethodName>;
touchEvents: Partial<
Record<JCanvasInteractionEventName, JCanvasTouchEventName>
>;
mouseEvents: Partial<
Record<JCanvasInteractionEventName, JCanvasMouseEventName>
>;
}

interface JCanvasCache {
Expand Down
55 changes: 31 additions & 24 deletions src/jcanvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ const extendObject = Object.assign,
cursors: ["grab", "grabbing", "zoom-in", "zoom-out"],
propsObj: {} as Record<string, boolean>,
},
tangibleEvents = [
tangibleEvents: (JCanvasMouseEventName | JCanvasTouchEventName)[] = [
"mousedown",
"mousemove",
"mouseup",
Expand Down Expand Up @@ -569,7 +569,11 @@ jCanvas.extend = function extend(plugin) {
};
// Add drawing type to drawing map
if (plugin.type) {
maps.drawings[String(plugin.type)] = plugin.name;
// We need to type-assert because the nature of $.jCanvas.extend
// implies that plugin.type is always a custom type which is not
// inherently part of JCanvasLayerType
maps.drawings[plugin.type as JCanvasLayerType] =
plugin.name as JCanvasDrawingMethodName;
}
}
// @ts-expect-error TODO: fix this
Expand Down Expand Up @@ -604,7 +608,7 @@ class JCanvasInternalData {
};
// Data for the current event
event: {
type: string | null;
type: JCanvasInteractionEventName | null;
x: number | null;
y: number | null;
event?: Event | null;
Expand Down Expand Up @@ -1365,7 +1369,7 @@ function _drawLayer(
function _handleLayerDrag(
$canvas: JQuery<HTMLCanvasElement>,
data: JCanvasInternalData,
eventType: string
eventType: JCanvasInteractionEventName
) {
const drag = data.drag;
const layer = drag.layer as JCanvasLayer;
Expand Down Expand Up @@ -1470,7 +1474,7 @@ function _handleLayerDrag(
function _setCursor(
$canvas: JQuery<HTMLCanvasElement>,
layer: JCanvasLayer,
eventType: string
eventType: JCanvasInteractionEventName
) {
let cursor;
if (layer.cursors) {
Expand Down Expand Up @@ -1505,11 +1509,7 @@ function _runEventCallback(
arg: any
) {
// Prevent callback from firing recursively
if (
callbacks[eventType as any] &&
layer._running &&
!layer._running[eventType]
) {
if (callbacks[eventType] && layer._running && !layer._running[eventType]) {
// Signify the start of callback execution for this event
layer._running[eventType] = true;
// Run event callback with the given arguments
Expand All @@ -1520,7 +1520,10 @@ function _runEventCallback(
}

// Determine if the given layer can "legally" fire the given event
function _layerCanFireEvent(layer: JCanvasLayer, eventType: string) {
function _layerCanFireEvent(
layer: JCanvasLayer,
eventType: string
): eventType is JCanvasMouseEventName | JCanvasTouchEventName {
// If events are disable and if
// layer is tangible or event is not tangible
return (
Expand All @@ -1534,7 +1537,7 @@ function _triggerLayerEvent(
$canvas: JQuery<HTMLCanvasElement>,
data: JCanvasInternalData,
layer: JCanvasLayer,
eventType: string,
eventType: JCanvasEventName,
arg?: any
) {
// If layer can legally fire this event type
Expand Down Expand Up @@ -1567,7 +1570,10 @@ $.fn.triggerLayerEvent = function (layerId, eventType) {
const data = _getCanvasData(canvas);
const layer = $canvas.getLayer(layerId);
if (layer) {
_triggerLayerEvent($canvas, data, layer, eventType);
// We need to type assert here because the developer may trigger a
// custom event that is not inherently part of JCanvasEventName;
// this is a use case we want to allow
_triggerLayerEvent($canvas, data, layer, eventType as JCanvasEventName);
}
}
return $canvases;
Expand Down Expand Up @@ -1769,7 +1775,7 @@ function _addLayer(
canvas: HTMLCanvasElement,
params: JCanvasObject,
args?: Partial<JCanvasObject>,
method?: (args: JCanvasObject) => JQuery
method?: (args: JCanvasObject) => JQuery<HTMLElement>
): JCanvasLayer | null {
const layer: JCanvasObject | JCanvasLayer = params._layer
? (args as JCanvasLayer)
Expand All @@ -1791,7 +1797,7 @@ function _addLayer(
} else if (params.method) {
params._method = $.fn[params.method];
} else if (params.type) {
params._method = $.fn[maps.drawings[params.type] as keyof JQuery];
params._method = $.fn[maps.drawings[params.type]];
}
}

Expand Down Expand Up @@ -2340,23 +2346,24 @@ _supportColorProps([
/* Event API */

// Convert mouse event name to a corresponding touch event name (if possible)
function _getTouchEventName(eventName: keyof typeof maps.touchEvents) {
// Detect touch event support
if (maps.touchEvents[eventName]) {
return maps.touchEvents[eventName];
function _getTouchEventName(eventName: JCanvasInteractionEventName) {
const touchEventName = maps.touchEvents[eventName];
if (touchEventName) {
return touchEventName;
}
return eventName;
}
// Convert touch event name to a corresponding mouse event name
function _getMouseEventName(eventName: string) {
if (maps.mouseEvents[eventName]) {
eventName = maps.mouseEvents[eventName];
function _getMouseEventName(eventName: JCanvasInteractionEventName) {
const mouseEventName = maps.mouseEvents[eventName];
if (mouseEventName) {
return mouseEventName;
}
return eventName;
}

// Bind event to jCanvas layer using standard jQuery events
function _createEvent(eventName: string) {
function _createEvent(eventName: JCanvasInteractionEventName) {
jCanvas.events[eventName] = function ($canvas, data) {
// Retrieve canvas's event cache
const eventCache = data.event;
Expand Down Expand Up @@ -2409,7 +2416,7 @@ function _createEvent(eventName: string) {
}
};
}
function _createEvents(eventNames: string[]) {
function _createEvents(eventNames: JCanvasInteractionEventName[]) {
for (let n = 0; n < eventNames.length; n += 1) {
_createEvent(eventNames[n]);
}
Expand Down

0 comments on commit bbfc671

Please sign in to comment.