Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull other static functions #201

Merged
merged 12 commits into from
Nov 8, 2024
9 changes: 7 additions & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export type ImageData = {
export type ULabelSubtasks = { [key: string]: ULabelSubtask };

export class ULabel {
subtasks: ULabelSubtask[];
subtasks: ULabelSubtasks;
state: {
// Viewer state
zoom_val: number;
Expand Down Expand Up @@ -244,7 +244,6 @@ export class ULabel {
public show_annotation_mode(
target_jq?: JQuery<HTMLElement>, // TODO (joshua-dean): validate this type
);
public raise_error(message: string, level?: number);
public rezoom(): void;
public update_frame(delta?: number, new_frame?: number): void;
public handle_id_dialog_hover(
Expand Down Expand Up @@ -356,6 +355,12 @@ export class ULabel {
thumbnail?: boolean,
nonspatial?: boolean,
): void;

// Canvases
public get_init_canvas_context_id(
annotation_id: string,
subtask?: string, // SUBTASK KEY
): string;
}

declare global {
Expand Down
70 changes: 70 additions & 0 deletions src/canvas_utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* Annotation canvas utilities.
* TODO (joshua-dean): Pull the rest of the canvas functions into here
*/

import type { ULabel, ULabelSubtasks } from "..";
import { NONSPATIAL_MODES } from "./annotation";
import { Configuration, DEFAULT_N_ANNOS_PER_CANVAS, TARGET_MAX_N_CANVASES_PER_SUBTASK } from "./configuration";

/**
* If the user doesn't provide a number of annotations per canvas, set it dynamically.
* This should help with performance.
*
* @param config ULabel configuration
* @param subtasks ULabel subtasks
*/
function dynamically_set_n_annos_per_canvas(
config: Configuration,
subtasks: ULabelSubtasks,
) {
// If they didn't provide a value, we'll still be using the default
if (config.n_annos_per_canvas === DEFAULT_N_ANNOS_PER_CANVAS) {
// Count max annotations per subtask
const max_annos = Math.max(
...Object.values(subtasks).map(subtask => subtask.annotations.ordering.length),
);

// Performance starts to deteriorate when we require many canvases to be drawn on
// To be safe, check if max_annos / DEFAULT_N_ANNOS_PER_CANVAS is greater than TARGET_MAX_N_CANVASES_PER_SUBTASK
if (max_annos / DEFAULT_N_ANNOS_PER_CANVAS > TARGET_MAX_N_CANVASES_PER_SUBTASK) {
// If so, raise the default
config.n_annos_per_canvas = Math.ceil(max_annos / TARGET_MAX_N_CANVASES_PER_SUBTASK);
}
}
}

/**
* Initialize annotation canvases and assign annotations to them
*
* @param ulabel ULabel instance
* @param subtask_key Subtask key. If null, this will dynamically initialize for all subtasks.
*/
export function initialize_annotation_canvases(
ulabel: ULabel,
subtask_key: string = null,
) {
if (subtask_key === null) {
dynamically_set_n_annos_per_canvas(
ulabel.config,
ulabel.subtasks,
);
for (const subtask_key in ulabel.subtasks) {
initialize_annotation_canvases(ulabel, subtask_key);
}
return;
}

// TODO (joshua-dean): shouldn't this just be a separate function?
// Create the canvas for each annotation
const subtask = ulabel.subtasks[subtask_key];
for (const annotation_id in subtask.annotations.access) {
const annotation = subtask.annotations.access[annotation_id];
if (!NONSPATIAL_MODES.includes(annotation.spatial_type)) {
annotation["canvas_id"] = ulabel.get_init_canvas_context_id(
annotation_id,
subtask_key,
);
}
}
}
40 changes: 40 additions & 0 deletions src/error_logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Error handling utilities for ULabel.
*/

export enum LogLevel {
VERBOSE = 0,
INFO = 1,
WARNING = 2,
ERROR = 3,
}

/**
* Log a message to the console at a level.
* This was ported from code that didn't use the console log levels,
* and is kept for compatibility.
*
* @param message Message to log
* @param log_level Level to log at
*/
export function log_message(
message: string,
log_level: LogLevel = LogLevel.INFO,
) {
switch (log_level) {
case LogLevel.VERBOSE:
console.debug(message);
break;
case LogLevel.INFO:
console.log(message);
break;
case LogLevel.WARNING:
console.warn(message);
alert("[WARNING] " + message);
break;
case LogLevel.ERROR:
console.error(message);
alert("[ERROR] " + message);
throw new Error(message);
}
}
6 changes: 5 additions & 1 deletion src/html_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
GLOBAL_SVG,
get_init_style,
} from "../src/blobs";
import { log_message, LogLevel } from "./error_logging";

/**
* Creates a style document, populates it with the styles in get_init_style, and appends it to the page.
Expand Down Expand Up @@ -224,7 +225,10 @@ export function prep_window_html(ulabel: ULabel, toolbox_item_order: unknown[] =

// If initial_crop exists but doesn't have the appropriate properties,
// then raise an error and return false
ulabel.raise_error("initial_crop missing necessary properties. Ignoring.");
log_message(
"initial_crop missing necessary properties. Ignoring.",
LogLevel.INFO,
);
return false;
};

Expand Down
Loading