@fieldnotes/core 0.20.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +481 -472
- package/dist/index.cjs +86 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +86 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -595,6 +595,10 @@ interface ViewportOptions {
|
|
|
595
595
|
x: number;
|
|
596
596
|
y: number;
|
|
597
597
|
}) => void;
|
|
598
|
+
onImageError?: (info: {
|
|
599
|
+
src: string;
|
|
600
|
+
elementIds: string[];
|
|
601
|
+
}) => void;
|
|
598
602
|
}
|
|
599
603
|
declare class Viewport {
|
|
600
604
|
private readonly container;
|
|
@@ -695,12 +699,14 @@ declare class ElementRenderer {
|
|
|
695
699
|
private store;
|
|
696
700
|
private imageCache;
|
|
697
701
|
private onImageLoad;
|
|
702
|
+
private onImageError;
|
|
698
703
|
private camera;
|
|
699
704
|
private canvasSize;
|
|
700
705
|
private hexTileCache;
|
|
701
706
|
private hexTileCacheKey;
|
|
702
707
|
setStore(store: ElementStore): void;
|
|
703
708
|
setOnImageLoad(callback: () => void): void;
|
|
709
|
+
setOnImageError(callback: (src: string) => void): void;
|
|
704
710
|
setCamera(camera: Camera): void;
|
|
705
711
|
setCanvasSize(w: number, h: number): void;
|
|
706
712
|
isDomElement(element: CanvasElement): boolean;
|
|
@@ -718,6 +724,7 @@ declare class ElementRenderer {
|
|
|
718
724
|
private renderHexTemplate;
|
|
719
725
|
private renderRadiusMarker;
|
|
720
726
|
private renderImage;
|
|
727
|
+
private renderImagePlaceholder;
|
|
721
728
|
private getHexTile;
|
|
722
729
|
private getImage;
|
|
723
730
|
}
|
|
@@ -1240,6 +1247,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1240
1247
|
undo(_store: ElementStore): void;
|
|
1241
1248
|
}
|
|
1242
1249
|
|
|
1243
|
-
declare const VERSION = "0.
|
|
1250
|
+
declare const VERSION = "0.21.0";
|
|
1244
1251
|
|
|
1245
1252
|
export { type ActiveFormats, AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, DEFAULT_FONT_SIZE_PRESETS, DEFAULT_NOTE_FONT_SIZE, DoubleTapDetector, type DoubleTapDetectorOptions, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FilterAction, type FilteredEvent, type FilteredUpEvent, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputFilter, InputHandler, type InputHandlerOptions, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, NoteEditor, type NoteEditorOptions, type NoteElement, NoteTool, type NoteToolOptions, NoteToolbar, PencilTool, type PencilToolOptions, type Point, type PointerState, Quadtree, RemoveElementCommand, RemoveLayerCommand, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StrokeElement, type StrokePoint, type StyledRun, type TemplateElement, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, boundsIntersect, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportState, findBindTarget, findBoundArrows, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, isNoteContentEmpty, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
|
package/dist/index.d.ts
CHANGED
|
@@ -595,6 +595,10 @@ interface ViewportOptions {
|
|
|
595
595
|
x: number;
|
|
596
596
|
y: number;
|
|
597
597
|
}) => void;
|
|
598
|
+
onImageError?: (info: {
|
|
599
|
+
src: string;
|
|
600
|
+
elementIds: string[];
|
|
601
|
+
}) => void;
|
|
598
602
|
}
|
|
599
603
|
declare class Viewport {
|
|
600
604
|
private readonly container;
|
|
@@ -695,12 +699,14 @@ declare class ElementRenderer {
|
|
|
695
699
|
private store;
|
|
696
700
|
private imageCache;
|
|
697
701
|
private onImageLoad;
|
|
702
|
+
private onImageError;
|
|
698
703
|
private camera;
|
|
699
704
|
private canvasSize;
|
|
700
705
|
private hexTileCache;
|
|
701
706
|
private hexTileCacheKey;
|
|
702
707
|
setStore(store: ElementStore): void;
|
|
703
708
|
setOnImageLoad(callback: () => void): void;
|
|
709
|
+
setOnImageError(callback: (src: string) => void): void;
|
|
704
710
|
setCamera(camera: Camera): void;
|
|
705
711
|
setCanvasSize(w: number, h: number): void;
|
|
706
712
|
isDomElement(element: CanvasElement): boolean;
|
|
@@ -718,6 +724,7 @@ declare class ElementRenderer {
|
|
|
718
724
|
private renderHexTemplate;
|
|
719
725
|
private renderRadiusMarker;
|
|
720
726
|
private renderImage;
|
|
727
|
+
private renderImagePlaceholder;
|
|
721
728
|
private getHexTile;
|
|
722
729
|
private getImage;
|
|
723
730
|
}
|
|
@@ -1240,6 +1247,6 @@ declare class UpdateLayerCommand implements Command {
|
|
|
1240
1247
|
undo(_store: ElementStore): void;
|
|
1241
1248
|
}
|
|
1242
1249
|
|
|
1243
|
-
declare const VERSION = "0.
|
|
1250
|
+
declare const VERSION = "0.21.0";
|
|
1244
1251
|
|
|
1245
1252
|
export { type ActiveFormats, AddElementCommand, type ArrowElement, ArrowTool, type ArrowToolOptions, AutoSave, type AutoSaveOptions, Background, type BackgroundOptions, type BackgroundPattern, BatchCommand, type Binding, type Bounds, Camera, type CameraChangeInfo, type CameraOptions, type CanvasElement, type CanvasState, type Command, CreateLayerCommand, DEFAULT_FONT_SIZE_PRESETS, DEFAULT_NOTE_FONT_SIZE, DoubleTapDetector, type DoubleTapDetectorOptions, ElementRenderer, ElementStore, type ElementType, type ElementUpdateEvent, EraserTool, type EraserToolOptions, EventBus, type ExportImageOptions, type FilterAction, type FilteredEvent, type FilteredUpEvent, type FontSizePreset, type GridElement, type GridInfo, HandTool, type HexOrientation, HistoryRecorder, HistoryStack, type HistoryStackOptions, type HtmlElement, type ImageElement, ImageTool, type ImageToolOptions, InputFilter, InputHandler, type InputHandlerOptions, type Layer, LayerManager, MeasureTool, type MeasureToolOptions, type Measurement, NoteEditor, type NoteEditorOptions, type NoteElement, NoteTool, type NoteToolOptions, NoteToolbar, PencilTool, type PencilToolOptions, type Point, type PointerState, Quadtree, RemoveElementCommand, RemoveLayerCommand, type RenderStatsSnapshot, SelectTool, type ShapeElement, type ShapeKind, ShapeTool, type ShapeToolOptions, type ShortcutBindings, type ShortcutOptions, type ShortcutsApi, type Size, type StrokeElement, type StrokePoint, type StyledRun, type TemplateElement, type TemplateShape, TemplateTool, type TemplateToolOptions, type TextElement, TextTool, type TextToolOptions, type Tool, type ToolContext, ToolManager, type ToolName, UpdateElementCommand, UpdateLayerCommand, VERSION, Viewport, type ViewportOptions, boundsIntersect, clearStaleBindings, createArrow, createGrid, createHtmlElement, createId, createImage, createNote, createShape, createStroke, createTemplate, createText, drawHexPath, exportImage, exportState, findBindTarget, findBoundArrows, getActiveFormats, getArrowBounds, getArrowControlPoint, getArrowMidpoint, getArrowTangentAngle, getBendFromPoint, getEdgeIntersection, getElementBounds, getElementCenter, getElementsBoundingBox, getHexCellsInCone, getHexCellsInLine, getHexCellsInRadius, getHexCellsInSquare, getHexDistance, isBindable, isNearBezier, isNoteContentEmpty, parseState, sanitizeNoteHtml, setFontSize, smartSnap, snapPoint, snapToHexCenter, toggleBold, toggleItalic, toggleStrikethrough, toggleUnderline, unbindArrow, updateBoundArrow };
|
package/dist/index.js
CHANGED
|
@@ -2609,6 +2609,7 @@ var ElementRenderer = class {
|
|
|
2609
2609
|
store = null;
|
|
2610
2610
|
imageCache = /* @__PURE__ */ new Map();
|
|
2611
2611
|
onImageLoad = null;
|
|
2612
|
+
onImageError = null;
|
|
2612
2613
|
camera = null;
|
|
2613
2614
|
canvasSize = null;
|
|
2614
2615
|
hexTileCache = null;
|
|
@@ -2619,6 +2620,9 @@ var ElementRenderer = class {
|
|
|
2619
2620
|
setOnImageLoad(callback) {
|
|
2620
2621
|
this.onImageLoad = callback;
|
|
2621
2622
|
}
|
|
2623
|
+
setOnImageError(callback) {
|
|
2624
|
+
this.onImageError = callback;
|
|
2625
|
+
}
|
|
2622
2626
|
setCamera(camera) {
|
|
2623
2627
|
this.camera = camera;
|
|
2624
2628
|
}
|
|
@@ -2977,6 +2981,10 @@ var ElementRenderer = class {
|
|
|
2977
2981
|
ctx.restore();
|
|
2978
2982
|
}
|
|
2979
2983
|
renderImage(ctx, image) {
|
|
2984
|
+
if (this.imageCache.get(image.src) === "failed") {
|
|
2985
|
+
this.renderImagePlaceholder(ctx, image);
|
|
2986
|
+
return;
|
|
2987
|
+
}
|
|
2980
2988
|
const img = this.getImage(image.src);
|
|
2981
2989
|
if (!img) return;
|
|
2982
2990
|
ctx.drawImage(
|
|
@@ -2987,6 +2995,27 @@ var ElementRenderer = class {
|
|
|
2987
2995
|
image.size.h
|
|
2988
2996
|
);
|
|
2989
2997
|
}
|
|
2998
|
+
renderImagePlaceholder(ctx, image) {
|
|
2999
|
+
const { x, y } = image.position;
|
|
3000
|
+
const { w, h } = image.size;
|
|
3001
|
+
ctx.save();
|
|
3002
|
+
ctx.fillStyle = "#eeeeee";
|
|
3003
|
+
ctx.fillRect(x, y, w, h);
|
|
3004
|
+
ctx.strokeStyle = "#bdbdbd";
|
|
3005
|
+
ctx.lineWidth = 1;
|
|
3006
|
+
ctx.strokeRect(x, y, w, h);
|
|
3007
|
+
const glyph = Math.min(24, w / 2, h / 2);
|
|
3008
|
+
const cx = x + w / 2;
|
|
3009
|
+
const cy = y + h / 2;
|
|
3010
|
+
ctx.strokeStyle = "#9e9e9e";
|
|
3011
|
+
ctx.lineWidth = 2;
|
|
3012
|
+
ctx.beginPath();
|
|
3013
|
+
ctx.arc(cx, cy, glyph / 2, 0, Math.PI * 2);
|
|
3014
|
+
ctx.moveTo(cx - glyph / 2, cy + glyph / 2);
|
|
3015
|
+
ctx.lineTo(cx + glyph / 2, cy - glyph / 2);
|
|
3016
|
+
ctx.stroke();
|
|
3017
|
+
ctx.restore();
|
|
3018
|
+
}
|
|
2990
3019
|
getHexTile(cellSize, orientation, strokeColor, strokeWidth, opacity, scale) {
|
|
2991
3020
|
const key = `${cellSize}:${orientation}:${strokeColor}:${strokeWidth}:${opacity}:${scale}`;
|
|
2992
3021
|
if (this.hexTileCacheKey === key && this.hexTileCache) {
|
|
@@ -3002,6 +3031,7 @@ var ElementRenderer = class {
|
|
|
3002
3031
|
getImage(src) {
|
|
3003
3032
|
const cached = this.imageCache.get(src);
|
|
3004
3033
|
if (cached) {
|
|
3034
|
+
if (cached === "failed") return null;
|
|
3005
3035
|
if (cached instanceof HTMLImageElement) return cached.complete ? cached : null;
|
|
3006
3036
|
return cached;
|
|
3007
3037
|
}
|
|
@@ -3018,6 +3048,11 @@ var ElementRenderer = class {
|
|
|
3018
3048
|
});
|
|
3019
3049
|
}
|
|
3020
3050
|
};
|
|
3051
|
+
img.onerror = () => {
|
|
3052
|
+
this.imageCache.set(src, "failed");
|
|
3053
|
+
this.onImageError?.(src);
|
|
3054
|
+
this.onImageLoad?.();
|
|
3055
|
+
};
|
|
3021
3056
|
return null;
|
|
3022
3057
|
}
|
|
3023
3058
|
};
|
|
@@ -4929,6 +4964,17 @@ var Viewport = class {
|
|
|
4929
4964
|
this.renderLoop.markAllLayersDirty();
|
|
4930
4965
|
this.requestRender();
|
|
4931
4966
|
});
|
|
4967
|
+
this.renderer.setOnImageError((src) => {
|
|
4968
|
+
const elementIds = [];
|
|
4969
|
+
for (const el of this.store.getAll()) {
|
|
4970
|
+
if (el.type === "image" && el.src === src) elementIds.push(el.id);
|
|
4971
|
+
}
|
|
4972
|
+
if (options.onImageError) {
|
|
4973
|
+
options.onImageError({ src, elementIds });
|
|
4974
|
+
} else {
|
|
4975
|
+
console.warn(`[fieldnotes] image failed to load: ${src}`);
|
|
4976
|
+
}
|
|
4977
|
+
});
|
|
4932
4978
|
this.noteEditor = new NoteEditor({
|
|
4933
4979
|
fontSizePresets: options.fontSizePresets,
|
|
4934
4980
|
toolbar: options.toolbar,
|
|
@@ -5633,6 +5679,43 @@ var PencilTool = class {
|
|
|
5633
5679
|
}
|
|
5634
5680
|
};
|
|
5635
5681
|
|
|
5682
|
+
// src/elements/stroke-hit.ts
|
|
5683
|
+
function distSqToSegment(p, a, b) {
|
|
5684
|
+
const abx = b.x - a.x;
|
|
5685
|
+
const aby = b.y - a.y;
|
|
5686
|
+
const apx = p.x - a.x;
|
|
5687
|
+
const apy = p.y - a.y;
|
|
5688
|
+
const lenSq = abx * abx + aby * aby;
|
|
5689
|
+
if (lenSq === 0) {
|
|
5690
|
+
return apx * apx + apy * apy;
|
|
5691
|
+
}
|
|
5692
|
+
const t = Math.max(0, Math.min(1, (apx * abx + apy * aby) / lenSq));
|
|
5693
|
+
const dx = p.x - (a.x + t * abx);
|
|
5694
|
+
const dy = p.y - (a.y + t * aby);
|
|
5695
|
+
return dx * dx + dy * dy;
|
|
5696
|
+
}
|
|
5697
|
+
function hitTestStroke(stroke, point, radius) {
|
|
5698
|
+
const bounds = getElementBounds(stroke);
|
|
5699
|
+
if (!bounds) return false;
|
|
5700
|
+
if (point.x < bounds.x - radius || point.x > bounds.x + bounds.w + radius || point.y < bounds.y - radius || point.y > bounds.y + bounds.h + radius) {
|
|
5701
|
+
return false;
|
|
5702
|
+
}
|
|
5703
|
+
const radiusSq = radius * radius;
|
|
5704
|
+
const local = { x: point.x - stroke.position.x, y: point.y - stroke.position.y };
|
|
5705
|
+
const { segments } = getStrokeRenderData(stroke);
|
|
5706
|
+
if (segments.length === 0) {
|
|
5707
|
+
const p = stroke.points[0];
|
|
5708
|
+
if (!p) return false;
|
|
5709
|
+
const dx = p.x - local.x;
|
|
5710
|
+
const dy = p.y - local.y;
|
|
5711
|
+
return dx * dx + dy * dy <= radiusSq;
|
|
5712
|
+
}
|
|
5713
|
+
for (const seg of segments) {
|
|
5714
|
+
if (distSqToSegment(local, seg.start, seg.end) <= radiusSq) return true;
|
|
5715
|
+
}
|
|
5716
|
+
return false;
|
|
5717
|
+
}
|
|
5718
|
+
|
|
5636
5719
|
// src/tools/eraser-tool.ts
|
|
5637
5720
|
var DEFAULT_RADIUS = 20;
|
|
5638
5721
|
function makeEraserCursor(radius) {
|
|
@@ -5691,12 +5774,7 @@ var EraserTool = class {
|
|
|
5691
5774
|
if (erased) ctx.requestRender();
|
|
5692
5775
|
}
|
|
5693
5776
|
strokeIntersects(stroke, point) {
|
|
5694
|
-
|
|
5695
|
-
return stroke.points.some((p) => {
|
|
5696
|
-
const dx = p.x + stroke.position.x - point.x;
|
|
5697
|
-
const dy = p.y + stroke.position.y - point.y;
|
|
5698
|
-
return dx * dx + dy * dy <= radiusSq;
|
|
5699
|
-
});
|
|
5777
|
+
return hitTestStroke(stroke, point, this.radius);
|
|
5700
5778
|
}
|
|
5701
5779
|
};
|
|
5702
5780
|
|
|
@@ -6376,12 +6454,7 @@ var SelectTool = class {
|
|
|
6376
6454
|
return point.x >= el.position.x && point.x <= el.position.x + s.w && point.y >= el.position.y && point.y <= el.position.y + s.h;
|
|
6377
6455
|
}
|
|
6378
6456
|
if (el.type === "stroke") {
|
|
6379
|
-
|
|
6380
|
-
return el.points.some((p) => {
|
|
6381
|
-
const dx = p.x + el.position.x - point.x;
|
|
6382
|
-
const dy = p.y + el.position.y - point.y;
|
|
6383
|
-
return dx * dx + dy * dy <= HIT_RADIUS * HIT_RADIUS;
|
|
6384
|
-
});
|
|
6457
|
+
return hitTestStroke(el, point, 10);
|
|
6385
6458
|
}
|
|
6386
6459
|
if (el.type === "arrow") {
|
|
6387
6460
|
return isNearBezier(point, el.from, el.to, el.bend, 10);
|
|
@@ -7217,7 +7290,7 @@ var TemplateTool = class {
|
|
|
7217
7290
|
};
|
|
7218
7291
|
|
|
7219
7292
|
// src/index.ts
|
|
7220
|
-
var VERSION = "0.
|
|
7293
|
+
var VERSION = "0.21.0";
|
|
7221
7294
|
export {
|
|
7222
7295
|
AddElementCommand,
|
|
7223
7296
|
ArrowTool,
|