@nex125/seatmap-core 0.1.0 → 0.1.1

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/dist/index.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var uuid = require('uuid');
3
4
  var RBush = require('rbush');
4
5
  var pixi_js = require('pixi.js');
5
6
 
@@ -8,6 +9,22 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
9
  var RBush__default = /*#__PURE__*/_interopDefault(RBush);
9
10
 
10
11
  // src/models/helpers.ts
12
+ var AVAILABLE_STATUS_ID = "available";
13
+ var DEFAULT_SEAT_STATUSES = [
14
+ { id: AVAILABLE_STATUS_ID, name: "Available", color: "#4caf50" },
15
+ { id: "locked", name: "Locked", color: "#f44336" },
16
+ { id: "booked", name: "Booked", color: "#9e9e9e" }
17
+ ];
18
+ var LEGACY_STATUS_MAP = {
19
+ held: "locked",
20
+ blocked: "locked",
21
+ sold: "booked"
22
+ };
23
+ function normalizeStatusId(rawStatus, allowedStatuses) {
24
+ const mapped = LEGACY_STATUS_MAP[rawStatus] ?? rawStatus;
25
+ if (allowedStatuses.has(mapped)) return mapped;
26
+ return AVAILABLE_STATUS_ID;
27
+ }
11
28
  function seatWorldPosition(section, seat) {
12
29
  const cos = Math.cos(section.rotation);
13
30
  const sin = Math.sin(section.rotation);
@@ -111,9 +128,37 @@ function clampToPolygon(point, polygon, margin = 5) {
111
128
  }
112
129
  return { x: bestX, y: bestY };
113
130
  }
114
- var _nextId = 1;
131
+ function normalizeVenue(venue) {
132
+ const seatStatuses = venue.seatStatuses && venue.seatStatuses.length > 0 ? venue.seatStatuses : DEFAULT_SEAT_STATUSES;
133
+ const clonedStatuses = seatStatuses.map((status) => ({ ...status }));
134
+ const allowedStatuses = new Set(clonedStatuses.map((status) => status.id));
135
+ const sections = venue.sections.map((section) => ({
136
+ ...section,
137
+ rows: section.rows.map((row) => ({
138
+ ...row,
139
+ seats: row.seats.map((seat) => ({
140
+ ...seat,
141
+ status: normalizeStatusId(seat.status, allowedStatuses)
142
+ }))
143
+ }))
144
+ }));
145
+ const tables = venue.tables.map((table) => ({
146
+ ...table,
147
+ seats: table.seats.map((seat) => ({
148
+ ...seat,
149
+ status: normalizeStatusId(seat.status, allowedStatuses)
150
+ }))
151
+ }));
152
+ return {
153
+ ...venue,
154
+ seatStatuses: clonedStatuses,
155
+ sections,
156
+ tables
157
+ };
158
+ }
115
159
  function generateId(prefix = "") {
116
- return `${prefix}${prefix ? "-" : ""}${Date.now().toString(36)}-${(_nextId++).toString(36)}`;
160
+ const id = uuid.v7();
161
+ return prefix ? `${prefix}-${id}` : id;
117
162
  }
118
163
  var SpatialIndex = class {
119
164
  tree = new RBush__default.default();
@@ -256,31 +301,44 @@ function getLODLevel(zoom) {
256
301
  if (zoom < DETAIL_THRESHOLD) return "section" /* Section */;
257
302
  return "detail" /* Detail */;
258
303
  }
259
- var STATUS_COLORS = {
260
- available: 5025616,
261
- held: 16750592,
262
- sold: 10395294,
263
- blocked: 16007990,
304
+ var UI_TEXTURE_COLORS = {
264
305
  selected: 2201331,
265
306
  hovered: 6600182
266
307
  };
267
- function createSeatTextures(renderer, radius = 7, categoryColor, textureResolution) {
308
+ function parseHexColor(color) {
309
+ return parseInt(color.replace("#", ""), 16);
310
+ }
311
+ function createSeatTextures(renderer, seatStatuses, radius = 7, categoryColor, textureResolution) {
268
312
  const result = {};
269
- const diameter = (radius + 4) * 2;
270
313
  const resolution = textureResolution ?? 4 * (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1);
271
- for (const [status, color] of Object.entries(STATUS_COLORS)) {
314
+ for (const status of seatStatuses) {
272
315
  const g = new pixi_js.Graphics();
273
- const fillColor = status === "available" && categoryColor != null ? categoryColor : color;
316
+ const fillColor = status.id === "available" && categoryColor != null ? categoryColor : parseHexColor(status.color);
274
317
  g.circle(radius + 4, radius + 4, radius);
275
318
  g.fill({ color: fillColor });
276
- if (status === "selected") {
319
+ const texture = renderer.textureGenerator.generateTexture({
320
+ target: g,
321
+ resolution,
322
+ antialias: true
323
+ });
324
+ g.destroy();
325
+ result[status.id] = texture;
326
+ }
327
+ for (const [statusId, color] of Object.entries(UI_TEXTURE_COLORS)) {
328
+ const g = new pixi_js.Graphics();
329
+ g.circle(radius + 4, radius + 4, radius);
330
+ g.fill({ color });
331
+ if (statusId === "selected") {
277
332
  g.circle(radius + 4, radius + 4, radius + 2);
278
333
  g.stroke({ color: 16777215, width: 2 });
279
334
  }
280
- const texture = pixi_js.RenderTexture.create({ width: diameter, height: diameter, resolution });
281
- renderer.render({ container: g, target: texture });
335
+ const texture = renderer.textureGenerator.generateTexture({
336
+ target: g,
337
+ resolution,
338
+ antialias: true
339
+ });
282
340
  g.destroy();
283
- result[status] = texture;
341
+ result[statusId] = texture;
284
342
  }
285
343
  return result;
286
344
  }
@@ -294,12 +352,12 @@ function destroySeatTextures(textures) {
294
352
  var CategoryTextureCache = class {
295
353
  cache = /* @__PURE__ */ new Map();
296
354
  defaultTextures = null;
297
- create(renderer, categories, seatRadius = 7) {
355
+ create(renderer, categories, seatStatuses, seatRadius = 7) {
298
356
  this.destroy();
299
- this.defaultTextures = createSeatTextures(renderer, seatRadius);
357
+ this.defaultTextures = createSeatTextures(renderer, seatStatuses, seatRadius);
300
358
  for (const cat of categories) {
301
359
  const color = parseInt(cat.color.replace("#", ""), 16);
302
- this.cache.set(cat.id, createSeatTextures(renderer, seatRadius, color));
360
+ this.cache.set(cat.id, createSeatTextures(renderer, seatStatuses, seatRadius, color));
303
361
  }
304
362
  }
305
363
  get(categoryId) {
@@ -369,11 +427,13 @@ function serializeVenue(venue) {
369
427
  return JSON.stringify(venue, null, 2);
370
428
  }
371
429
  function deserializeVenue(json) {
372
- return JSON.parse(json);
430
+ return normalizeVenue(JSON.parse(json));
373
431
  }
374
432
 
433
+ exports.AVAILABLE_STATUS_ID = AVAILABLE_STATUS_ID;
375
434
  exports.CategoryTextureCache = CategoryTextureCache;
376
435
  exports.CommandHistory = CommandHistory;
436
+ exports.DEFAULT_SEAT_STATUSES = DEFAULT_SEAT_STATUSES;
377
437
  exports.LODLevel = LODLevel;
378
438
  exports.SpatialIndex = SpatialIndex;
379
439
  exports.Viewport = Viewport;
@@ -383,6 +443,7 @@ exports.deserializeVenue = deserializeVenue;
383
443
  exports.destroySeatTextures = destroySeatTextures;
384
444
  exports.generateId = generateId;
385
445
  exports.getLODLevel = getLODLevel;
446
+ exports.normalizeVenue = normalizeVenue;
386
447
  exports.pointInPolygon = pointInPolygon;
387
448
  exports.seatWorldPosition = seatWorldPosition;
388
449
  exports.sectionAABB = sectionAABB;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/models/helpers.ts","../src/spatial/SpatialIndex.ts","../src/rendering/Viewport.ts","../src/rendering/LODLevel.ts","../src/rendering/SpriteAtlas.ts","../src/rendering/CategoryTextureCache.ts","../src/commands/CommandHistory.ts","../src/serialization/index.ts"],"names":["RBush","LODLevel","Graphics","RenderTexture"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AABB, Section, Seat, Vec2, Venue } from \"./types\";\n\nexport function seatWorldPosition(section: Section, seat: Seat): Vec2 {\n const cos = Math.cos(section.rotation);\n const sin = Math.sin(section.rotation);\n return {\n x: section.position.x + seat.position.x * cos - seat.position.y * sin,\n y: section.position.y + seat.position.x * sin + seat.position.y * cos,\n };\n}\n\nexport function sectionAABB(section: Section): AABB {\n const allPoints: Vec2[] = [];\n\n if (section.outline.length > 0) {\n const cos = Math.cos(section.rotation);\n const sin = Math.sin(section.rotation);\n for (const p of section.outline) {\n allPoints.push({\n x: section.position.x + p.x * cos - p.y * sin,\n y: section.position.y + p.x * sin + p.y * cos,\n });\n }\n }\n\n const allSeats = section.rows.flatMap((r) => r.seats);\n for (const seat of allSeats) {\n allPoints.push(seatWorldPosition(section, seat));\n }\n\n if (allPoints.length === 0) {\n return {\n minX: section.position.x,\n minY: section.position.y,\n maxX: section.position.x,\n maxY: section.position.y,\n };\n }\n\n const pad = 10;\n return {\n minX: Math.min(...allPoints.map((p) => p.x)) - pad,\n minY: Math.min(...allPoints.map((p) => p.y)) - pad,\n maxX: Math.max(...allPoints.map((p) => p.x)) + pad,\n maxY: Math.max(...allPoints.map((p) => p.y)) + pad,\n };\n}\n\nexport function venueAABB(venue: Venue): AABB {\n if (venue.sections.length === 0) {\n return { minX: 0, minY: 0, maxX: venue.bounds.width, maxY: venue.bounds.height };\n }\n const boxes = venue.sections.map(sectionAABB);\n return {\n minX: Math.min(...boxes.map((b) => b.minX)),\n minY: Math.min(...boxes.map((b) => b.minY)),\n maxX: Math.max(...boxes.map((b) => b.maxX)),\n maxY: Math.max(...boxes.map((b) => b.maxY)),\n };\n}\n\n/** Ray-casting point-in-polygon test. Works with any simple polygon. */\nexport function pointInPolygon(point: Vec2, polygon: Vec2[]): boolean {\n if (polygon.length < 3) return false;\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const xi = polygon[i].x, yi = polygon[i].y;\n const xj = polygon[j].x, yj = polygon[j].y;\n if ((yi > point.y) !== (yj > point.y) &&\n point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/** Clamp a point to the nearest position inside a polygon (with margin). */\nexport function clampToPolygon(point: Vec2, polygon: Vec2[], margin = 5): Vec2 {\n if (polygon.length < 3 || pointInPolygon(point, polygon)) return point;\n\n // Find the closest point on any polygon edge\n let bestX = point.x, bestY = point.y, bestDist = Infinity;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const ax = polygon[j].x, ay = polygon[j].y;\n const bx = polygon[i].x, by = polygon[i].y;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) continue;\n const t = Math.max(0, Math.min(1, ((point.x - ax) * dx + (point.y - ay) * dy) / len2));\n const cx = ax + t * dx - margin * dy / Math.sqrt(len2);\n const cy = ay + t * dy + margin * dx / Math.sqrt(len2);\n const d = Math.hypot(point.x - cx, point.y - cy);\n if (d < bestDist) { bestDist = d; bestX = cx; bestY = cy; }\n }\n\n // Verify the clamped point is inside; if not just project onto edge without margin\n if (!pointInPolygon({ x: bestX, y: bestY }, polygon)) {\n bestDist = Infinity;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const ax = polygon[j].x, ay = polygon[j].y;\n const bx = polygon[i].x, by = polygon[i].y;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) continue;\n const t = Math.max(0, Math.min(1, ((point.x - ax) * dx + (point.y - ay) * dy) / len2));\n const cx = ax + t * dx, cy = ay + t * dy;\n const d = Math.hypot(point.x - cx, point.y - cy);\n if (d < bestDist) { bestDist = d; bestX = cx; bestY = cy; }\n }\n }\n\n return { x: bestX, y: bestY };\n}\n\nlet _nextId = 1;\nexport function generateId(prefix = \"\"): string {\n return `${prefix}${prefix ? \"-\" : \"\"}${Date.now().toString(36)}-${(_nextId++).toString(36)}`;\n}\n","import RBush from \"rbush\";\nimport type { AABB, Section, Vec2 } from \"../models/types\";\nimport { seatWorldPosition, sectionAABB } from \"../models/helpers\";\n\nexport interface SpatialItem extends AABB {\n type: \"section\" | \"seat\";\n sectionId: string;\n seatId?: string;\n}\n\nexport class SpatialIndex {\n private tree = new RBush<SpatialItem>();\n private items: SpatialItem[] = [];\n\n buildFromSections(sections: Section[]): void {\n this.items = [];\n\n for (const section of sections) {\n const box = sectionAABB(section);\n this.items.push({\n ...box,\n type: \"section\",\n sectionId: section.id,\n });\n\n for (const row of section.rows) {\n for (const seat of row.seats) {\n const wp = seatWorldPosition(section, seat);\n const r = 8;\n this.items.push({\n minX: wp.x - r,\n minY: wp.y - r,\n maxX: wp.x + r,\n maxY: wp.y + r,\n type: \"seat\",\n sectionId: section.id,\n seatId: seat.id,\n });\n }\n }\n }\n\n this.tree.clear();\n this.tree.load(this.items);\n }\n\n queryViewport(viewport: AABB): SpatialItem[] {\n return this.tree.search(viewport);\n }\n\n queryPoint(point: Vec2, radius = 8): SpatialItem[] {\n return this.tree.search({\n minX: point.x - radius,\n minY: point.y - radius,\n maxX: point.x + radius,\n maxY: point.y + radius,\n });\n }\n\n queryRect(rect: AABB): SpatialItem[] {\n return this.tree.search(rect);\n }\n}\n","import type { AABB, Vec2 } from \"../models/types\";\n\nexport interface ViewportState {\n x: number;\n y: number;\n zoom: number;\n}\n\nconst MIN_ZOOM = 0.05;\nconst MAX_ZOOM = 4;\n\nexport class Viewport {\n x = 0;\n y = 0;\n zoom = 1;\n screenWidth = 0;\n screenHeight = 0;\n\n private listeners = new Set<() => void>();\n\n setScreenSize(width: number, height: number): void {\n this.screenWidth = width;\n this.screenHeight = height;\n this.notify();\n }\n\n pan(dx: number, dy: number): void {\n this.x += dx / this.zoom;\n this.y += dy / this.zoom;\n this.notify();\n }\n\n zoomAt(screenPoint: Vec2, factor: number): void {\n const newZoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, this.zoom * factor));\n\n // 1) World coordinate currently under the cursor\n const wx = screenPoint.x / this.zoom - this.x;\n const wy = screenPoint.y / this.zoom - this.y;\n\n // 2) Solve for the offset that keeps that world point at the same screen position\n // screenPoint = (world + offset) * newZoom → offset = screenPoint / newZoom - world\n this.x = screenPoint.x / newZoom - wx;\n this.y = screenPoint.y / newZoom - wy;\n this.zoom = newZoom;\n this.notify();\n }\n\n setZoom(zoom: number): void {\n this.zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));\n this.notify();\n }\n\n fitBounds(aabb: AABB, padding = 40): void {\n const contentW = aabb.maxX - aabb.minX;\n const contentH = aabb.maxY - aabb.minY;\n if (contentW <= 0 || contentH <= 0) return;\n\n const scaleX = (this.screenWidth - padding * 2) / contentW;\n const scaleY = (this.screenHeight - padding * 2) / contentH;\n this.zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, Math.min(scaleX, scaleY)));\n\n this.x = -(aabb.minX + contentW / 2) + this.screenWidth / (2 * this.zoom);\n this.y = -(aabb.minY + contentH / 2) + this.screenHeight / (2 * this.zoom);\n this.notify();\n }\n\n screenToWorld(screenX: number, screenY: number): Vec2 {\n return {\n x: screenX / this.zoom - this.x,\n y: screenY / this.zoom - this.y,\n };\n }\n\n worldToScreen(worldX: number, worldY: number): Vec2 {\n return {\n x: (worldX + this.x) * this.zoom,\n y: (worldY + this.y) * this.zoom,\n };\n }\n\n getVisibleAABB(): AABB {\n const topLeft = this.screenToWorld(0, 0);\n const bottomRight = this.screenToWorld(this.screenWidth, this.screenHeight);\n return {\n minX: topLeft.x,\n minY: topLeft.y,\n maxX: bottomRight.x,\n maxY: bottomRight.y,\n };\n }\n\n getState(): ViewportState {\n return { x: this.x, y: this.y, zoom: this.zoom };\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","export enum LODLevel {\n Overview = \"overview\",\n Section = \"section\",\n Detail = \"detail\",\n}\n\nconst SECTION_THRESHOLD = 0.3;\nconst DETAIL_THRESHOLD = 0.7;\n\nexport function getLODLevel(zoom: number): LODLevel {\n if (zoom < SECTION_THRESHOLD) return LODLevel.Overview;\n if (zoom < DETAIL_THRESHOLD) return LODLevel.Section;\n return LODLevel.Detail;\n}\n","import { Graphics, RenderTexture, type Renderer } from \"pixi.js\";\n\nexport interface SeatTextureSet {\n available: RenderTexture;\n held: RenderTexture;\n sold: RenderTexture;\n blocked: RenderTexture;\n selected: RenderTexture;\n hovered: RenderTexture;\n}\n\nconst STATUS_COLORS: Record<string, number> = {\n available: 0x4caf50,\n held: 0xff9800,\n sold: 0x9e9e9e,\n blocked: 0xf44336,\n selected: 0x2196f3,\n hovered: 0x64b5f6,\n};\n\nexport function createSeatTextures(\n renderer: Renderer,\n radius = 7,\n categoryColor?: number,\n textureResolution?: number,\n): SeatTextureSet {\n const result: Partial<SeatTextureSet> = {};\n const diameter = (radius + 4) * 2;\n const resolution = textureResolution ?? (4 * (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1));\n\n for (const [status, color] of Object.entries(STATUS_COLORS)) {\n const g = new Graphics();\n const fillColor = status === \"available\" && categoryColor != null ? categoryColor : color;\n g.circle(radius + 4, radius + 4, radius);\n g.fill({ color: fillColor });\n\n if (status === \"selected\") {\n g.circle(radius + 4, radius + 4, radius + 2);\n g.stroke({ color: 0xffffff, width: 2 });\n }\n\n const texture = RenderTexture.create({ width: diameter, height: diameter, resolution });\n renderer.render({ container: g, target: texture });\n g.destroy();\n\n result[status as keyof SeatTextureSet] = texture;\n }\n\n return result as SeatTextureSet;\n}\n\nexport function destroySeatTextures(textures: SeatTextureSet): void {\n for (const tex of Object.values(textures)) {\n (tex as RenderTexture).destroy(true);\n }\n}\n","import type { Renderer } from \"pixi.js\";\nimport {\n createSeatTextures,\n destroySeatTextures,\n type SeatTextureSet,\n} from \"./SpriteAtlas\";\n\nexport class CategoryTextureCache {\n private cache = new Map<string, SeatTextureSet>();\n private defaultTextures: SeatTextureSet | null = null;\n\n create(renderer: Renderer, categories: { id: string; color: string }[], seatRadius = 7): void {\n this.destroy();\n this.defaultTextures = createSeatTextures(renderer, seatRadius);\n\n for (const cat of categories) {\n const color = parseInt(cat.color.replace(\"#\", \"\"), 16);\n this.cache.set(cat.id, createSeatTextures(renderer, seatRadius, color));\n }\n }\n\n get(categoryId: string): SeatTextureSet {\n return this.cache.get(categoryId) ?? this.defaultTextures!;\n }\n\n destroy(): void {\n for (const textures of this.cache.values()) {\n destroySeatTextures(textures);\n }\n if (this.defaultTextures) {\n destroySeatTextures(this.defaultTextures);\n }\n this.cache.clear();\n this.defaultTextures = null;\n }\n}\n","export interface Command {\n execute(): void;\n undo(): void;\n description: string;\n}\n\nexport class CommandHistory {\n private undoStack: Command[] = [];\n private redoStack: Command[] = [];\n private listeners = new Set<() => void>();\n\n execute(command: Command): void {\n command.execute();\n this.undoStack.push(command);\n this.redoStack = [];\n this.notify();\n }\n\n undo(): void {\n const command = this.undoStack.pop();\n if (!command) return;\n command.undo();\n this.redoStack.push(command);\n this.notify();\n }\n\n redo(): void {\n const command = this.redoStack.pop();\n if (!command) return;\n command.execute();\n this.undoStack.push(command);\n this.notify();\n }\n\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n clear(): void {\n this.undoStack = [];\n this.redoStack = [];\n this.notify();\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","import type { Venue } from \"../models/types\";\n\nexport function serializeVenue(venue: Venue): string {\n return JSON.stringify(venue, null, 2);\n}\n\nexport function deserializeVenue(json: string): Venue {\n return JSON.parse(json) as Venue;\n}\n"]}
1
+ {"version":3,"sources":["../src/models/helpers.ts","../src/spatial/SpatialIndex.ts","../src/rendering/Viewport.ts","../src/rendering/LODLevel.ts","../src/rendering/SpriteAtlas.ts","../src/rendering/CategoryTextureCache.ts","../src/commands/CommandHistory.ts","../src/serialization/index.ts"],"names":["uuidv7","RBush","LODLevel","Graphics"],"mappings":"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","file":"index.cjs","sourcesContent":["import { v7 as uuidv7 } from \"uuid\";\nimport type { AABB, Section, Seat, SeatStatusDefinition, Vec2, Venue } from \"./types\";\n\nexport const AVAILABLE_STATUS_ID = \"available\";\n\nexport const DEFAULT_SEAT_STATUSES: SeatStatusDefinition[] = [\n { id: AVAILABLE_STATUS_ID, name: \"Available\", color: \"#4caf50\" },\n { id: \"locked\", name: \"Locked\", color: \"#f44336\" },\n { id: \"booked\", name: \"Booked\", color: \"#9e9e9e\" },\n];\n\nconst LEGACY_STATUS_MAP: Record<string, string> = {\n held: \"locked\",\n blocked: \"locked\",\n sold: \"booked\",\n};\n\nfunction normalizeStatusId(rawStatus: string, allowedStatuses: Set<string>): string {\n const mapped = LEGACY_STATUS_MAP[rawStatus] ?? rawStatus;\n if (allowedStatuses.has(mapped)) return mapped;\n return AVAILABLE_STATUS_ID;\n}\n\nexport function seatWorldPosition(section: Section, seat: Seat): Vec2 {\n const cos = Math.cos(section.rotation);\n const sin = Math.sin(section.rotation);\n return {\n x: section.position.x + seat.position.x * cos - seat.position.y * sin,\n y: section.position.y + seat.position.x * sin + seat.position.y * cos,\n };\n}\n\nexport function sectionAABB(section: Section): AABB {\n const allPoints: Vec2[] = [];\n\n if (section.outline.length > 0) {\n const cos = Math.cos(section.rotation);\n const sin = Math.sin(section.rotation);\n for (const p of section.outline) {\n allPoints.push({\n x: section.position.x + p.x * cos - p.y * sin,\n y: section.position.y + p.x * sin + p.y * cos,\n });\n }\n }\n\n const allSeats = section.rows.flatMap((r) => r.seats);\n for (const seat of allSeats) {\n allPoints.push(seatWorldPosition(section, seat));\n }\n\n if (allPoints.length === 0) {\n return {\n minX: section.position.x,\n minY: section.position.y,\n maxX: section.position.x,\n maxY: section.position.y,\n };\n }\n\n const pad = 10;\n return {\n minX: Math.min(...allPoints.map((p) => p.x)) - pad,\n minY: Math.min(...allPoints.map((p) => p.y)) - pad,\n maxX: Math.max(...allPoints.map((p) => p.x)) + pad,\n maxY: Math.max(...allPoints.map((p) => p.y)) + pad,\n };\n}\n\nexport function venueAABB(venue: Venue): AABB {\n if (venue.sections.length === 0) {\n return { minX: 0, minY: 0, maxX: venue.bounds.width, maxY: venue.bounds.height };\n }\n const boxes = venue.sections.map(sectionAABB);\n return {\n minX: Math.min(...boxes.map((b) => b.minX)),\n minY: Math.min(...boxes.map((b) => b.minY)),\n maxX: Math.max(...boxes.map((b) => b.maxX)),\n maxY: Math.max(...boxes.map((b) => b.maxY)),\n };\n}\n\n/** Ray-casting point-in-polygon test. Works with any simple polygon. */\nexport function pointInPolygon(point: Vec2, polygon: Vec2[]): boolean {\n if (polygon.length < 3) return false;\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const xi = polygon[i].x, yi = polygon[i].y;\n const xj = polygon[j].x, yj = polygon[j].y;\n if ((yi > point.y) !== (yj > point.y) &&\n point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/** Clamp a point to the nearest position inside a polygon (with margin). */\nexport function clampToPolygon(point: Vec2, polygon: Vec2[], margin = 5): Vec2 {\n if (polygon.length < 3 || pointInPolygon(point, polygon)) return point;\n\n // Find the closest point on any polygon edge\n let bestX = point.x, bestY = point.y, bestDist = Infinity;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const ax = polygon[j].x, ay = polygon[j].y;\n const bx = polygon[i].x, by = polygon[i].y;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) continue;\n const t = Math.max(0, Math.min(1, ((point.x - ax) * dx + (point.y - ay) * dy) / len2));\n const cx = ax + t * dx - margin * dy / Math.sqrt(len2);\n const cy = ay + t * dy + margin * dx / Math.sqrt(len2);\n const d = Math.hypot(point.x - cx, point.y - cy);\n if (d < bestDist) { bestDist = d; bestX = cx; bestY = cy; }\n }\n\n // Verify the clamped point is inside; if not just project onto edge without margin\n if (!pointInPolygon({ x: bestX, y: bestY }, polygon)) {\n bestDist = Infinity;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const ax = polygon[j].x, ay = polygon[j].y;\n const bx = polygon[i].x, by = polygon[i].y;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) continue;\n const t = Math.max(0, Math.min(1, ((point.x - ax) * dx + (point.y - ay) * dy) / len2));\n const cx = ax + t * dx, cy = ay + t * dy;\n const d = Math.hypot(point.x - cx, point.y - cy);\n if (d < bestDist) { bestDist = d; bestX = cx; bestY = cy; }\n }\n }\n\n return { x: bestX, y: bestY };\n}\n\nexport function normalizeVenue(venue: Venue): Venue {\n const seatStatuses =\n venue.seatStatuses && venue.seatStatuses.length > 0\n ? venue.seatStatuses\n : DEFAULT_SEAT_STATUSES;\n const clonedStatuses = seatStatuses.map((status) => ({ ...status }));\n const allowedStatuses = new Set(clonedStatuses.map((status) => status.id));\n\n const sections = venue.sections.map((section) => ({\n ...section,\n rows: section.rows.map((row) => ({\n ...row,\n seats: row.seats.map((seat) => ({\n ...seat,\n status: normalizeStatusId(seat.status, allowedStatuses),\n })),\n })),\n }));\n\n const tables = venue.tables.map((table) => ({\n ...table,\n seats: table.seats.map((seat) => ({\n ...seat,\n status: normalizeStatusId(seat.status, allowedStatuses),\n })),\n }));\n\n return {\n ...venue,\n seatStatuses: clonedStatuses,\n sections,\n tables,\n };\n}\n\nexport function generateId(prefix = \"\"): string {\n const id = uuidv7();\n return prefix ? `${prefix}-${id}` : id;\n}\n","import RBush from \"rbush\";\nimport type { AABB, Section, Vec2 } from \"../models/types\";\nimport { seatWorldPosition, sectionAABB } from \"../models/helpers\";\n\nexport interface SpatialItem extends AABB {\n type: \"section\" | \"seat\";\n sectionId: string;\n seatId?: string;\n}\n\nexport class SpatialIndex {\n private tree = new RBush<SpatialItem>();\n private items: SpatialItem[] = [];\n\n buildFromSections(sections: Section[]): void {\n this.items = [];\n\n for (const section of sections) {\n const box = sectionAABB(section);\n this.items.push({\n ...box,\n type: \"section\",\n sectionId: section.id,\n });\n\n for (const row of section.rows) {\n for (const seat of row.seats) {\n const wp = seatWorldPosition(section, seat);\n const r = 8;\n this.items.push({\n minX: wp.x - r,\n minY: wp.y - r,\n maxX: wp.x + r,\n maxY: wp.y + r,\n type: \"seat\",\n sectionId: section.id,\n seatId: seat.id,\n });\n }\n }\n }\n\n this.tree.clear();\n this.tree.load(this.items);\n }\n\n queryViewport(viewport: AABB): SpatialItem[] {\n return this.tree.search(viewport);\n }\n\n queryPoint(point: Vec2, radius = 8): SpatialItem[] {\n return this.tree.search({\n minX: point.x - radius,\n minY: point.y - radius,\n maxX: point.x + radius,\n maxY: point.y + radius,\n });\n }\n\n queryRect(rect: AABB): SpatialItem[] {\n return this.tree.search(rect);\n }\n}\n","import type { AABB, Vec2 } from \"../models/types\";\n\nexport interface ViewportState {\n x: number;\n y: number;\n zoom: number;\n}\n\nconst MIN_ZOOM = 0.05;\nconst MAX_ZOOM = 4;\n\nexport class Viewport {\n x = 0;\n y = 0;\n zoom = 1;\n screenWidth = 0;\n screenHeight = 0;\n\n private listeners = new Set<() => void>();\n\n setScreenSize(width: number, height: number): void {\n this.screenWidth = width;\n this.screenHeight = height;\n this.notify();\n }\n\n pan(dx: number, dy: number): void {\n this.x += dx / this.zoom;\n this.y += dy / this.zoom;\n this.notify();\n }\n\n zoomAt(screenPoint: Vec2, factor: number): void {\n const newZoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, this.zoom * factor));\n\n // 1) World coordinate currently under the cursor\n const wx = screenPoint.x / this.zoom - this.x;\n const wy = screenPoint.y / this.zoom - this.y;\n\n // 2) Solve for the offset that keeps that world point at the same screen position\n // screenPoint = (world + offset) * newZoom → offset = screenPoint / newZoom - world\n this.x = screenPoint.x / newZoom - wx;\n this.y = screenPoint.y / newZoom - wy;\n this.zoom = newZoom;\n this.notify();\n }\n\n setZoom(zoom: number): void {\n this.zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));\n this.notify();\n }\n\n fitBounds(aabb: AABB, padding = 40): void {\n const contentW = aabb.maxX - aabb.minX;\n const contentH = aabb.maxY - aabb.minY;\n if (contentW <= 0 || contentH <= 0) return;\n\n const scaleX = (this.screenWidth - padding * 2) / contentW;\n const scaleY = (this.screenHeight - padding * 2) / contentH;\n this.zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, Math.min(scaleX, scaleY)));\n\n this.x = -(aabb.minX + contentW / 2) + this.screenWidth / (2 * this.zoom);\n this.y = -(aabb.minY + contentH / 2) + this.screenHeight / (2 * this.zoom);\n this.notify();\n }\n\n screenToWorld(screenX: number, screenY: number): Vec2 {\n return {\n x: screenX / this.zoom - this.x,\n y: screenY / this.zoom - this.y,\n };\n }\n\n worldToScreen(worldX: number, worldY: number): Vec2 {\n return {\n x: (worldX + this.x) * this.zoom,\n y: (worldY + this.y) * this.zoom,\n };\n }\n\n getVisibleAABB(): AABB {\n const topLeft = this.screenToWorld(0, 0);\n const bottomRight = this.screenToWorld(this.screenWidth, this.screenHeight);\n return {\n minX: topLeft.x,\n minY: topLeft.y,\n maxX: bottomRight.x,\n maxY: bottomRight.y,\n };\n }\n\n getState(): ViewportState {\n return { x: this.x, y: this.y, zoom: this.zoom };\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","export enum LODLevel {\n Overview = \"overview\",\n Section = \"section\",\n Detail = \"detail\",\n}\n\nconst SECTION_THRESHOLD = 0.3;\nconst DETAIL_THRESHOLD = 0.7;\n\nexport function getLODLevel(zoom: number): LODLevel {\n if (zoom < SECTION_THRESHOLD) return LODLevel.Overview;\n if (zoom < DETAIL_THRESHOLD) return LODLevel.Section;\n return LODLevel.Detail;\n}\n","import { Graphics, type Texture, type Renderer } from \"pixi.js\";\nimport type { SeatStatusDefinition } from \"../models\";\n\nexport interface SeatTextureSet {\n [statusId: string]: Texture;\n selected: Texture;\n hovered: Texture;\n}\n\nconst UI_TEXTURE_COLORS: Record<string, number> = {\n selected: 0x2196f3,\n hovered: 0x64b5f6,\n};\n\nfunction parseHexColor(color: string): number {\n return parseInt(color.replace(\"#\", \"\"), 16);\n}\n\nexport function createSeatTextures(\n renderer: Renderer,\n seatStatuses: SeatStatusDefinition[],\n radius = 7,\n categoryColor?: number,\n textureResolution?: number,\n): SeatTextureSet {\n const result: Partial<SeatTextureSet> = {};\n const resolution = textureResolution ?? (4 * (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1));\n\n for (const status of seatStatuses) {\n const g = new Graphics();\n const fillColor = status.id === \"available\" && categoryColor != null\n ? categoryColor\n : parseHexColor(status.color);\n g.circle(radius + 4, radius + 4, radius);\n g.fill({ color: fillColor });\n\n const texture = renderer.textureGenerator.generateTexture({\n target: g,\n resolution,\n antialias: true,\n });\n g.destroy();\n\n result[status.id] = texture;\n }\n\n for (const [statusId, color] of Object.entries(UI_TEXTURE_COLORS)) {\n const g = new Graphics();\n g.circle(radius + 4, radius + 4, radius);\n g.fill({ color });\n\n if (statusId === \"selected\") {\n g.circle(radius + 4, radius + 4, radius + 2);\n g.stroke({ color: 0xffffff, width: 2 });\n }\n\n const texture = renderer.textureGenerator.generateTexture({\n target: g,\n resolution,\n antialias: true,\n });\n g.destroy();\n\n result[statusId] = texture;\n }\n\n return result as SeatTextureSet;\n}\n\nexport function destroySeatTextures(textures: SeatTextureSet): void {\n for (const tex of Object.values(textures)) {\n tex.destroy(true);\n }\n}\n","import type { Renderer } from \"pixi.js\";\nimport type { SeatStatusDefinition } from \"../models\";\nimport {\n createSeatTextures,\n destroySeatTextures,\n type SeatTextureSet,\n} from \"./SpriteAtlas\";\n\nexport class CategoryTextureCache {\n private cache = new Map<string, SeatTextureSet>();\n private defaultTextures: SeatTextureSet | null = null;\n\n create(\n renderer: Renderer,\n categories: { id: string; color: string }[],\n seatStatuses: SeatStatusDefinition[],\n seatRadius = 7,\n ): void {\n this.destroy();\n this.defaultTextures = createSeatTextures(renderer, seatStatuses, seatRadius);\n\n for (const cat of categories) {\n const color = parseInt(cat.color.replace(\"#\", \"\"), 16);\n this.cache.set(cat.id, createSeatTextures(renderer, seatStatuses, seatRadius, color));\n }\n }\n\n get(categoryId: string): SeatTextureSet {\n return this.cache.get(categoryId) ?? this.defaultTextures!;\n }\n\n destroy(): void {\n for (const textures of this.cache.values()) {\n destroySeatTextures(textures);\n }\n if (this.defaultTextures) {\n destroySeatTextures(this.defaultTextures);\n }\n this.cache.clear();\n this.defaultTextures = null;\n }\n}\n","export interface Command {\n execute(): void;\n undo(): void;\n description: string;\n}\n\nexport class CommandHistory {\n private undoStack: Command[] = [];\n private redoStack: Command[] = [];\n private listeners = new Set<() => void>();\n\n execute(command: Command): void {\n command.execute();\n this.undoStack.push(command);\n this.redoStack = [];\n this.notify();\n }\n\n undo(): void {\n const command = this.undoStack.pop();\n if (!command) return;\n command.undo();\n this.redoStack.push(command);\n this.notify();\n }\n\n redo(): void {\n const command = this.redoStack.pop();\n if (!command) return;\n command.execute();\n this.undoStack.push(command);\n this.notify();\n }\n\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n clear(): void {\n this.undoStack = [];\n this.redoStack = [];\n this.notify();\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","import type { Venue } from \"../models/types\";\nimport { normalizeVenue } from \"../models/helpers\";\n\nexport function serializeVenue(venue: Venue): string {\n return JSON.stringify(venue, null, 2);\n}\n\nexport function deserializeVenue(json: string): Venue {\n return normalizeVenue(JSON.parse(json) as Venue);\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { RenderTexture, Renderer } from 'pixi.js';
1
+ import { Texture, Renderer } from 'pixi.js';
2
2
 
3
3
  interface Vec2 {
4
4
  x: number;
@@ -14,7 +14,12 @@ interface AABB {
14
14
  maxX: number;
15
15
  maxY: number;
16
16
  }
17
- type SeatStatus = "available" | "held" | "sold" | "blocked";
17
+ type SeatStatus = string;
18
+ interface SeatStatusDefinition {
19
+ id: string;
20
+ name: string;
21
+ color: string;
22
+ }
18
23
  interface PricingCategory {
19
24
  id: string;
20
25
  name: string;
@@ -62,12 +67,21 @@ interface Venue {
62
67
  bounds: Bounds;
63
68
  backgroundImage?: string;
64
69
  backgroundImageOpacity?: number;
70
+ backgroundImageWidth?: number;
71
+ backgroundImageHeight?: number;
72
+ backgroundImageX?: number;
73
+ backgroundImageY?: number;
74
+ backgroundImageAspectRatio?: number;
75
+ backgroundImageKeepAspectRatio?: boolean;
65
76
  sections: Section[];
66
77
  gaAreas: GeneralAdmissionArea[];
67
78
  tables: Table[];
68
79
  categories: PricingCategory[];
80
+ seatStatuses: SeatStatusDefinition[];
69
81
  }
70
82
 
83
+ declare const AVAILABLE_STATUS_ID = "available";
84
+ declare const DEFAULT_SEAT_STATUSES: SeatStatusDefinition[];
71
85
  declare function seatWorldPosition(section: Section, seat: Seat): Vec2;
72
86
  declare function sectionAABB(section: Section): AABB;
73
87
  declare function venueAABB(venue: Venue): AABB;
@@ -75,6 +89,7 @@ declare function venueAABB(venue: Venue): AABB;
75
89
  declare function pointInPolygon(point: Vec2, polygon: Vec2[]): boolean;
76
90
  /** Clamp a point to the nearest position inside a polygon (with margin). */
77
91
  declare function clampToPolygon(point: Vec2, polygon: Vec2[], margin?: number): Vec2;
92
+ declare function normalizeVenue(venue: Venue): Venue;
78
93
  declare function generateId(prefix?: string): string;
79
94
 
80
95
  interface SpatialItem extends AABB {
@@ -124,14 +139,11 @@ declare enum LODLevel {
124
139
  declare function getLODLevel(zoom: number): LODLevel;
125
140
 
126
141
  interface SeatTextureSet {
127
- available: RenderTexture;
128
- held: RenderTexture;
129
- sold: RenderTexture;
130
- blocked: RenderTexture;
131
- selected: RenderTexture;
132
- hovered: RenderTexture;
133
- }
134
- declare function createSeatTextures(renderer: Renderer, radius?: number, categoryColor?: number, textureResolution?: number): SeatTextureSet;
142
+ [statusId: string]: Texture;
143
+ selected: Texture;
144
+ hovered: Texture;
145
+ }
146
+ declare function createSeatTextures(renderer: Renderer, seatStatuses: SeatStatusDefinition[], radius?: number, categoryColor?: number, textureResolution?: number): SeatTextureSet;
135
147
  declare function destroySeatTextures(textures: SeatTextureSet): void;
136
148
 
137
149
  declare class CategoryTextureCache {
@@ -140,7 +152,7 @@ declare class CategoryTextureCache {
140
152
  create(renderer: Renderer, categories: {
141
153
  id: string;
142
154
  color: string;
143
- }[], seatRadius?: number): void;
155
+ }[], seatStatuses: SeatStatusDefinition[], seatRadius?: number): void;
144
156
  get(categoryId: string): SeatTextureSet;
145
157
  destroy(): void;
146
158
  }
@@ -167,4 +179,4 @@ declare class CommandHistory {
167
179
  declare function serializeVenue(venue: Venue): string;
168
180
  declare function deserializeVenue(json: string): Venue;
169
181
 
170
- export { type AABB, type Bounds, CategoryTextureCache, type Command, CommandHistory, type GeneralAdmissionArea, LODLevel, type PricingCategory, type Row, type Seat, type SeatStatus, type SeatTextureSet, type Section, SpatialIndex, type SpatialItem, type Table, type Vec2, type Venue, Viewport, type ViewportState, clampToPolygon, createSeatTextures, deserializeVenue, destroySeatTextures, generateId, getLODLevel, pointInPolygon, seatWorldPosition, sectionAABB, serializeVenue, venueAABB };
182
+ export { type AABB, AVAILABLE_STATUS_ID, type Bounds, CategoryTextureCache, type Command, CommandHistory, DEFAULT_SEAT_STATUSES, type GeneralAdmissionArea, LODLevel, type PricingCategory, type Row, type Seat, type SeatStatus, type SeatStatusDefinition, type SeatTextureSet, type Section, SpatialIndex, type SpatialItem, type Table, type Vec2, type Venue, Viewport, type ViewportState, clampToPolygon, createSeatTextures, deserializeVenue, destroySeatTextures, generateId, getLODLevel, normalizeVenue, pointInPolygon, seatWorldPosition, sectionAABB, serializeVenue, venueAABB };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { RenderTexture, Renderer } from 'pixi.js';
1
+ import { Texture, Renderer } from 'pixi.js';
2
2
 
3
3
  interface Vec2 {
4
4
  x: number;
@@ -14,7 +14,12 @@ interface AABB {
14
14
  maxX: number;
15
15
  maxY: number;
16
16
  }
17
- type SeatStatus = "available" | "held" | "sold" | "blocked";
17
+ type SeatStatus = string;
18
+ interface SeatStatusDefinition {
19
+ id: string;
20
+ name: string;
21
+ color: string;
22
+ }
18
23
  interface PricingCategory {
19
24
  id: string;
20
25
  name: string;
@@ -62,12 +67,21 @@ interface Venue {
62
67
  bounds: Bounds;
63
68
  backgroundImage?: string;
64
69
  backgroundImageOpacity?: number;
70
+ backgroundImageWidth?: number;
71
+ backgroundImageHeight?: number;
72
+ backgroundImageX?: number;
73
+ backgroundImageY?: number;
74
+ backgroundImageAspectRatio?: number;
75
+ backgroundImageKeepAspectRatio?: boolean;
65
76
  sections: Section[];
66
77
  gaAreas: GeneralAdmissionArea[];
67
78
  tables: Table[];
68
79
  categories: PricingCategory[];
80
+ seatStatuses: SeatStatusDefinition[];
69
81
  }
70
82
 
83
+ declare const AVAILABLE_STATUS_ID = "available";
84
+ declare const DEFAULT_SEAT_STATUSES: SeatStatusDefinition[];
71
85
  declare function seatWorldPosition(section: Section, seat: Seat): Vec2;
72
86
  declare function sectionAABB(section: Section): AABB;
73
87
  declare function venueAABB(venue: Venue): AABB;
@@ -75,6 +89,7 @@ declare function venueAABB(venue: Venue): AABB;
75
89
  declare function pointInPolygon(point: Vec2, polygon: Vec2[]): boolean;
76
90
  /** Clamp a point to the nearest position inside a polygon (with margin). */
77
91
  declare function clampToPolygon(point: Vec2, polygon: Vec2[], margin?: number): Vec2;
92
+ declare function normalizeVenue(venue: Venue): Venue;
78
93
  declare function generateId(prefix?: string): string;
79
94
 
80
95
  interface SpatialItem extends AABB {
@@ -124,14 +139,11 @@ declare enum LODLevel {
124
139
  declare function getLODLevel(zoom: number): LODLevel;
125
140
 
126
141
  interface SeatTextureSet {
127
- available: RenderTexture;
128
- held: RenderTexture;
129
- sold: RenderTexture;
130
- blocked: RenderTexture;
131
- selected: RenderTexture;
132
- hovered: RenderTexture;
133
- }
134
- declare function createSeatTextures(renderer: Renderer, radius?: number, categoryColor?: number, textureResolution?: number): SeatTextureSet;
142
+ [statusId: string]: Texture;
143
+ selected: Texture;
144
+ hovered: Texture;
145
+ }
146
+ declare function createSeatTextures(renderer: Renderer, seatStatuses: SeatStatusDefinition[], radius?: number, categoryColor?: number, textureResolution?: number): SeatTextureSet;
135
147
  declare function destroySeatTextures(textures: SeatTextureSet): void;
136
148
 
137
149
  declare class CategoryTextureCache {
@@ -140,7 +152,7 @@ declare class CategoryTextureCache {
140
152
  create(renderer: Renderer, categories: {
141
153
  id: string;
142
154
  color: string;
143
- }[], seatRadius?: number): void;
155
+ }[], seatStatuses: SeatStatusDefinition[], seatRadius?: number): void;
144
156
  get(categoryId: string): SeatTextureSet;
145
157
  destroy(): void;
146
158
  }
@@ -167,4 +179,4 @@ declare class CommandHistory {
167
179
  declare function serializeVenue(venue: Venue): string;
168
180
  declare function deserializeVenue(json: string): Venue;
169
181
 
170
- export { type AABB, type Bounds, CategoryTextureCache, type Command, CommandHistory, type GeneralAdmissionArea, LODLevel, type PricingCategory, type Row, type Seat, type SeatStatus, type SeatTextureSet, type Section, SpatialIndex, type SpatialItem, type Table, type Vec2, type Venue, Viewport, type ViewportState, clampToPolygon, createSeatTextures, deserializeVenue, destroySeatTextures, generateId, getLODLevel, pointInPolygon, seatWorldPosition, sectionAABB, serializeVenue, venueAABB };
182
+ export { type AABB, AVAILABLE_STATUS_ID, type Bounds, CategoryTextureCache, type Command, CommandHistory, DEFAULT_SEAT_STATUSES, type GeneralAdmissionArea, LODLevel, type PricingCategory, type Row, type Seat, type SeatStatus, type SeatStatusDefinition, type SeatTextureSet, type Section, SpatialIndex, type SpatialItem, type Table, type Vec2, type Venue, Viewport, type ViewportState, clampToPolygon, createSeatTextures, deserializeVenue, destroySeatTextures, generateId, getLODLevel, normalizeVenue, pointInPolygon, seatWorldPosition, sectionAABB, serializeVenue, venueAABB };
package/dist/index.js CHANGED
@@ -1,7 +1,24 @@
1
+ import { v7 } from 'uuid';
1
2
  import RBush from 'rbush';
2
- import { Graphics, RenderTexture } from 'pixi.js';
3
+ import { Graphics } from 'pixi.js';
3
4
 
4
5
  // src/models/helpers.ts
6
+ var AVAILABLE_STATUS_ID = "available";
7
+ var DEFAULT_SEAT_STATUSES = [
8
+ { id: AVAILABLE_STATUS_ID, name: "Available", color: "#4caf50" },
9
+ { id: "locked", name: "Locked", color: "#f44336" },
10
+ { id: "booked", name: "Booked", color: "#9e9e9e" }
11
+ ];
12
+ var LEGACY_STATUS_MAP = {
13
+ held: "locked",
14
+ blocked: "locked",
15
+ sold: "booked"
16
+ };
17
+ function normalizeStatusId(rawStatus, allowedStatuses) {
18
+ const mapped = LEGACY_STATUS_MAP[rawStatus] ?? rawStatus;
19
+ if (allowedStatuses.has(mapped)) return mapped;
20
+ return AVAILABLE_STATUS_ID;
21
+ }
5
22
  function seatWorldPosition(section, seat) {
6
23
  const cos = Math.cos(section.rotation);
7
24
  const sin = Math.sin(section.rotation);
@@ -105,9 +122,37 @@ function clampToPolygon(point, polygon, margin = 5) {
105
122
  }
106
123
  return { x: bestX, y: bestY };
107
124
  }
108
- var _nextId = 1;
125
+ function normalizeVenue(venue) {
126
+ const seatStatuses = venue.seatStatuses && venue.seatStatuses.length > 0 ? venue.seatStatuses : DEFAULT_SEAT_STATUSES;
127
+ const clonedStatuses = seatStatuses.map((status) => ({ ...status }));
128
+ const allowedStatuses = new Set(clonedStatuses.map((status) => status.id));
129
+ const sections = venue.sections.map((section) => ({
130
+ ...section,
131
+ rows: section.rows.map((row) => ({
132
+ ...row,
133
+ seats: row.seats.map((seat) => ({
134
+ ...seat,
135
+ status: normalizeStatusId(seat.status, allowedStatuses)
136
+ }))
137
+ }))
138
+ }));
139
+ const tables = venue.tables.map((table) => ({
140
+ ...table,
141
+ seats: table.seats.map((seat) => ({
142
+ ...seat,
143
+ status: normalizeStatusId(seat.status, allowedStatuses)
144
+ }))
145
+ }));
146
+ return {
147
+ ...venue,
148
+ seatStatuses: clonedStatuses,
149
+ sections,
150
+ tables
151
+ };
152
+ }
109
153
  function generateId(prefix = "") {
110
- return `${prefix}${prefix ? "-" : ""}${Date.now().toString(36)}-${(_nextId++).toString(36)}`;
154
+ const id = v7();
155
+ return prefix ? `${prefix}-${id}` : id;
111
156
  }
112
157
  var SpatialIndex = class {
113
158
  tree = new RBush();
@@ -250,31 +295,44 @@ function getLODLevel(zoom) {
250
295
  if (zoom < DETAIL_THRESHOLD) return "section" /* Section */;
251
296
  return "detail" /* Detail */;
252
297
  }
253
- var STATUS_COLORS = {
254
- available: 5025616,
255
- held: 16750592,
256
- sold: 10395294,
257
- blocked: 16007990,
298
+ var UI_TEXTURE_COLORS = {
258
299
  selected: 2201331,
259
300
  hovered: 6600182
260
301
  };
261
- function createSeatTextures(renderer, radius = 7, categoryColor, textureResolution) {
302
+ function parseHexColor(color) {
303
+ return parseInt(color.replace("#", ""), 16);
304
+ }
305
+ function createSeatTextures(renderer, seatStatuses, radius = 7, categoryColor, textureResolution) {
262
306
  const result = {};
263
- const diameter = (radius + 4) * 2;
264
307
  const resolution = textureResolution ?? 4 * (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1);
265
- for (const [status, color] of Object.entries(STATUS_COLORS)) {
308
+ for (const status of seatStatuses) {
266
309
  const g = new Graphics();
267
- const fillColor = status === "available" && categoryColor != null ? categoryColor : color;
310
+ const fillColor = status.id === "available" && categoryColor != null ? categoryColor : parseHexColor(status.color);
268
311
  g.circle(radius + 4, radius + 4, radius);
269
312
  g.fill({ color: fillColor });
270
- if (status === "selected") {
313
+ const texture = renderer.textureGenerator.generateTexture({
314
+ target: g,
315
+ resolution,
316
+ antialias: true
317
+ });
318
+ g.destroy();
319
+ result[status.id] = texture;
320
+ }
321
+ for (const [statusId, color] of Object.entries(UI_TEXTURE_COLORS)) {
322
+ const g = new Graphics();
323
+ g.circle(radius + 4, radius + 4, radius);
324
+ g.fill({ color });
325
+ if (statusId === "selected") {
271
326
  g.circle(radius + 4, radius + 4, radius + 2);
272
327
  g.stroke({ color: 16777215, width: 2 });
273
328
  }
274
- const texture = RenderTexture.create({ width: diameter, height: diameter, resolution });
275
- renderer.render({ container: g, target: texture });
329
+ const texture = renderer.textureGenerator.generateTexture({
330
+ target: g,
331
+ resolution,
332
+ antialias: true
333
+ });
276
334
  g.destroy();
277
- result[status] = texture;
335
+ result[statusId] = texture;
278
336
  }
279
337
  return result;
280
338
  }
@@ -288,12 +346,12 @@ function destroySeatTextures(textures) {
288
346
  var CategoryTextureCache = class {
289
347
  cache = /* @__PURE__ */ new Map();
290
348
  defaultTextures = null;
291
- create(renderer, categories, seatRadius = 7) {
349
+ create(renderer, categories, seatStatuses, seatRadius = 7) {
292
350
  this.destroy();
293
- this.defaultTextures = createSeatTextures(renderer, seatRadius);
351
+ this.defaultTextures = createSeatTextures(renderer, seatStatuses, seatRadius);
294
352
  for (const cat of categories) {
295
353
  const color = parseInt(cat.color.replace("#", ""), 16);
296
- this.cache.set(cat.id, createSeatTextures(renderer, seatRadius, color));
354
+ this.cache.set(cat.id, createSeatTextures(renderer, seatStatuses, seatRadius, color));
297
355
  }
298
356
  }
299
357
  get(categoryId) {
@@ -363,9 +421,9 @@ function serializeVenue(venue) {
363
421
  return JSON.stringify(venue, null, 2);
364
422
  }
365
423
  function deserializeVenue(json) {
366
- return JSON.parse(json);
424
+ return normalizeVenue(JSON.parse(json));
367
425
  }
368
426
 
369
- export { CategoryTextureCache, CommandHistory, LODLevel, SpatialIndex, Viewport, clampToPolygon, createSeatTextures, deserializeVenue, destroySeatTextures, generateId, getLODLevel, pointInPolygon, seatWorldPosition, sectionAABB, serializeVenue, venueAABB };
427
+ export { AVAILABLE_STATUS_ID, CategoryTextureCache, CommandHistory, DEFAULT_SEAT_STATUSES, LODLevel, SpatialIndex, Viewport, clampToPolygon, createSeatTextures, deserializeVenue, destroySeatTextures, generateId, getLODLevel, normalizeVenue, pointInPolygon, seatWorldPosition, sectionAABB, serializeVenue, venueAABB };
370
428
  //# sourceMappingURL=index.js.map
371
429
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/models/helpers.ts","../src/spatial/SpatialIndex.ts","../src/rendering/Viewport.ts","../src/rendering/LODLevel.ts","../src/rendering/SpriteAtlas.ts","../src/rendering/CategoryTextureCache.ts","../src/commands/CommandHistory.ts","../src/serialization/index.ts"],"names":["LODLevel"],"mappings":"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","file":"index.js","sourcesContent":["import type { AABB, Section, Seat, Vec2, Venue } from \"./types\";\n\nexport function seatWorldPosition(section: Section, seat: Seat): Vec2 {\n const cos = Math.cos(section.rotation);\n const sin = Math.sin(section.rotation);\n return {\n x: section.position.x + seat.position.x * cos - seat.position.y * sin,\n y: section.position.y + seat.position.x * sin + seat.position.y * cos,\n };\n}\n\nexport function sectionAABB(section: Section): AABB {\n const allPoints: Vec2[] = [];\n\n if (section.outline.length > 0) {\n const cos = Math.cos(section.rotation);\n const sin = Math.sin(section.rotation);\n for (const p of section.outline) {\n allPoints.push({\n x: section.position.x + p.x * cos - p.y * sin,\n y: section.position.y + p.x * sin + p.y * cos,\n });\n }\n }\n\n const allSeats = section.rows.flatMap((r) => r.seats);\n for (const seat of allSeats) {\n allPoints.push(seatWorldPosition(section, seat));\n }\n\n if (allPoints.length === 0) {\n return {\n minX: section.position.x,\n minY: section.position.y,\n maxX: section.position.x,\n maxY: section.position.y,\n };\n }\n\n const pad = 10;\n return {\n minX: Math.min(...allPoints.map((p) => p.x)) - pad,\n minY: Math.min(...allPoints.map((p) => p.y)) - pad,\n maxX: Math.max(...allPoints.map((p) => p.x)) + pad,\n maxY: Math.max(...allPoints.map((p) => p.y)) + pad,\n };\n}\n\nexport function venueAABB(venue: Venue): AABB {\n if (venue.sections.length === 0) {\n return { minX: 0, minY: 0, maxX: venue.bounds.width, maxY: venue.bounds.height };\n }\n const boxes = venue.sections.map(sectionAABB);\n return {\n minX: Math.min(...boxes.map((b) => b.minX)),\n minY: Math.min(...boxes.map((b) => b.minY)),\n maxX: Math.max(...boxes.map((b) => b.maxX)),\n maxY: Math.max(...boxes.map((b) => b.maxY)),\n };\n}\n\n/** Ray-casting point-in-polygon test. Works with any simple polygon. */\nexport function pointInPolygon(point: Vec2, polygon: Vec2[]): boolean {\n if (polygon.length < 3) return false;\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const xi = polygon[i].x, yi = polygon[i].y;\n const xj = polygon[j].x, yj = polygon[j].y;\n if ((yi > point.y) !== (yj > point.y) &&\n point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/** Clamp a point to the nearest position inside a polygon (with margin). */\nexport function clampToPolygon(point: Vec2, polygon: Vec2[], margin = 5): Vec2 {\n if (polygon.length < 3 || pointInPolygon(point, polygon)) return point;\n\n // Find the closest point on any polygon edge\n let bestX = point.x, bestY = point.y, bestDist = Infinity;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const ax = polygon[j].x, ay = polygon[j].y;\n const bx = polygon[i].x, by = polygon[i].y;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) continue;\n const t = Math.max(0, Math.min(1, ((point.x - ax) * dx + (point.y - ay) * dy) / len2));\n const cx = ax + t * dx - margin * dy / Math.sqrt(len2);\n const cy = ay + t * dy + margin * dx / Math.sqrt(len2);\n const d = Math.hypot(point.x - cx, point.y - cy);\n if (d < bestDist) { bestDist = d; bestX = cx; bestY = cy; }\n }\n\n // Verify the clamped point is inside; if not just project onto edge without margin\n if (!pointInPolygon({ x: bestX, y: bestY }, polygon)) {\n bestDist = Infinity;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const ax = polygon[j].x, ay = polygon[j].y;\n const bx = polygon[i].x, by = polygon[i].y;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) continue;\n const t = Math.max(0, Math.min(1, ((point.x - ax) * dx + (point.y - ay) * dy) / len2));\n const cx = ax + t * dx, cy = ay + t * dy;\n const d = Math.hypot(point.x - cx, point.y - cy);\n if (d < bestDist) { bestDist = d; bestX = cx; bestY = cy; }\n }\n }\n\n return { x: bestX, y: bestY };\n}\n\nlet _nextId = 1;\nexport function generateId(prefix = \"\"): string {\n return `${prefix}${prefix ? \"-\" : \"\"}${Date.now().toString(36)}-${(_nextId++).toString(36)}`;\n}\n","import RBush from \"rbush\";\nimport type { AABB, Section, Vec2 } from \"../models/types\";\nimport { seatWorldPosition, sectionAABB } from \"../models/helpers\";\n\nexport interface SpatialItem extends AABB {\n type: \"section\" | \"seat\";\n sectionId: string;\n seatId?: string;\n}\n\nexport class SpatialIndex {\n private tree = new RBush<SpatialItem>();\n private items: SpatialItem[] = [];\n\n buildFromSections(sections: Section[]): void {\n this.items = [];\n\n for (const section of sections) {\n const box = sectionAABB(section);\n this.items.push({\n ...box,\n type: \"section\",\n sectionId: section.id,\n });\n\n for (const row of section.rows) {\n for (const seat of row.seats) {\n const wp = seatWorldPosition(section, seat);\n const r = 8;\n this.items.push({\n minX: wp.x - r,\n minY: wp.y - r,\n maxX: wp.x + r,\n maxY: wp.y + r,\n type: \"seat\",\n sectionId: section.id,\n seatId: seat.id,\n });\n }\n }\n }\n\n this.tree.clear();\n this.tree.load(this.items);\n }\n\n queryViewport(viewport: AABB): SpatialItem[] {\n return this.tree.search(viewport);\n }\n\n queryPoint(point: Vec2, radius = 8): SpatialItem[] {\n return this.tree.search({\n minX: point.x - radius,\n minY: point.y - radius,\n maxX: point.x + radius,\n maxY: point.y + radius,\n });\n }\n\n queryRect(rect: AABB): SpatialItem[] {\n return this.tree.search(rect);\n }\n}\n","import type { AABB, Vec2 } from \"../models/types\";\n\nexport interface ViewportState {\n x: number;\n y: number;\n zoom: number;\n}\n\nconst MIN_ZOOM = 0.05;\nconst MAX_ZOOM = 4;\n\nexport class Viewport {\n x = 0;\n y = 0;\n zoom = 1;\n screenWidth = 0;\n screenHeight = 0;\n\n private listeners = new Set<() => void>();\n\n setScreenSize(width: number, height: number): void {\n this.screenWidth = width;\n this.screenHeight = height;\n this.notify();\n }\n\n pan(dx: number, dy: number): void {\n this.x += dx / this.zoom;\n this.y += dy / this.zoom;\n this.notify();\n }\n\n zoomAt(screenPoint: Vec2, factor: number): void {\n const newZoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, this.zoom * factor));\n\n // 1) World coordinate currently under the cursor\n const wx = screenPoint.x / this.zoom - this.x;\n const wy = screenPoint.y / this.zoom - this.y;\n\n // 2) Solve for the offset that keeps that world point at the same screen position\n // screenPoint = (world + offset) * newZoom → offset = screenPoint / newZoom - world\n this.x = screenPoint.x / newZoom - wx;\n this.y = screenPoint.y / newZoom - wy;\n this.zoom = newZoom;\n this.notify();\n }\n\n setZoom(zoom: number): void {\n this.zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));\n this.notify();\n }\n\n fitBounds(aabb: AABB, padding = 40): void {\n const contentW = aabb.maxX - aabb.minX;\n const contentH = aabb.maxY - aabb.minY;\n if (contentW <= 0 || contentH <= 0) return;\n\n const scaleX = (this.screenWidth - padding * 2) / contentW;\n const scaleY = (this.screenHeight - padding * 2) / contentH;\n this.zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, Math.min(scaleX, scaleY)));\n\n this.x = -(aabb.minX + contentW / 2) + this.screenWidth / (2 * this.zoom);\n this.y = -(aabb.minY + contentH / 2) + this.screenHeight / (2 * this.zoom);\n this.notify();\n }\n\n screenToWorld(screenX: number, screenY: number): Vec2 {\n return {\n x: screenX / this.zoom - this.x,\n y: screenY / this.zoom - this.y,\n };\n }\n\n worldToScreen(worldX: number, worldY: number): Vec2 {\n return {\n x: (worldX + this.x) * this.zoom,\n y: (worldY + this.y) * this.zoom,\n };\n }\n\n getVisibleAABB(): AABB {\n const topLeft = this.screenToWorld(0, 0);\n const bottomRight = this.screenToWorld(this.screenWidth, this.screenHeight);\n return {\n minX: topLeft.x,\n minY: topLeft.y,\n maxX: bottomRight.x,\n maxY: bottomRight.y,\n };\n }\n\n getState(): ViewportState {\n return { x: this.x, y: this.y, zoom: this.zoom };\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","export enum LODLevel {\n Overview = \"overview\",\n Section = \"section\",\n Detail = \"detail\",\n}\n\nconst SECTION_THRESHOLD = 0.3;\nconst DETAIL_THRESHOLD = 0.7;\n\nexport function getLODLevel(zoom: number): LODLevel {\n if (zoom < SECTION_THRESHOLD) return LODLevel.Overview;\n if (zoom < DETAIL_THRESHOLD) return LODLevel.Section;\n return LODLevel.Detail;\n}\n","import { Graphics, RenderTexture, type Renderer } from \"pixi.js\";\n\nexport interface SeatTextureSet {\n available: RenderTexture;\n held: RenderTexture;\n sold: RenderTexture;\n blocked: RenderTexture;\n selected: RenderTexture;\n hovered: RenderTexture;\n}\n\nconst STATUS_COLORS: Record<string, number> = {\n available: 0x4caf50,\n held: 0xff9800,\n sold: 0x9e9e9e,\n blocked: 0xf44336,\n selected: 0x2196f3,\n hovered: 0x64b5f6,\n};\n\nexport function createSeatTextures(\n renderer: Renderer,\n radius = 7,\n categoryColor?: number,\n textureResolution?: number,\n): SeatTextureSet {\n const result: Partial<SeatTextureSet> = {};\n const diameter = (radius + 4) * 2;\n const resolution = textureResolution ?? (4 * (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1));\n\n for (const [status, color] of Object.entries(STATUS_COLORS)) {\n const g = new Graphics();\n const fillColor = status === \"available\" && categoryColor != null ? categoryColor : color;\n g.circle(radius + 4, radius + 4, radius);\n g.fill({ color: fillColor });\n\n if (status === \"selected\") {\n g.circle(radius + 4, radius + 4, radius + 2);\n g.stroke({ color: 0xffffff, width: 2 });\n }\n\n const texture = RenderTexture.create({ width: diameter, height: diameter, resolution });\n renderer.render({ container: g, target: texture });\n g.destroy();\n\n result[status as keyof SeatTextureSet] = texture;\n }\n\n return result as SeatTextureSet;\n}\n\nexport function destroySeatTextures(textures: SeatTextureSet): void {\n for (const tex of Object.values(textures)) {\n (tex as RenderTexture).destroy(true);\n }\n}\n","import type { Renderer } from \"pixi.js\";\nimport {\n createSeatTextures,\n destroySeatTextures,\n type SeatTextureSet,\n} from \"./SpriteAtlas\";\n\nexport class CategoryTextureCache {\n private cache = new Map<string, SeatTextureSet>();\n private defaultTextures: SeatTextureSet | null = null;\n\n create(renderer: Renderer, categories: { id: string; color: string }[], seatRadius = 7): void {\n this.destroy();\n this.defaultTextures = createSeatTextures(renderer, seatRadius);\n\n for (const cat of categories) {\n const color = parseInt(cat.color.replace(\"#\", \"\"), 16);\n this.cache.set(cat.id, createSeatTextures(renderer, seatRadius, color));\n }\n }\n\n get(categoryId: string): SeatTextureSet {\n return this.cache.get(categoryId) ?? this.defaultTextures!;\n }\n\n destroy(): void {\n for (const textures of this.cache.values()) {\n destroySeatTextures(textures);\n }\n if (this.defaultTextures) {\n destroySeatTextures(this.defaultTextures);\n }\n this.cache.clear();\n this.defaultTextures = null;\n }\n}\n","export interface Command {\n execute(): void;\n undo(): void;\n description: string;\n}\n\nexport class CommandHistory {\n private undoStack: Command[] = [];\n private redoStack: Command[] = [];\n private listeners = new Set<() => void>();\n\n execute(command: Command): void {\n command.execute();\n this.undoStack.push(command);\n this.redoStack = [];\n this.notify();\n }\n\n undo(): void {\n const command = this.undoStack.pop();\n if (!command) return;\n command.undo();\n this.redoStack.push(command);\n this.notify();\n }\n\n redo(): void {\n const command = this.redoStack.pop();\n if (!command) return;\n command.execute();\n this.undoStack.push(command);\n this.notify();\n }\n\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n clear(): void {\n this.undoStack = [];\n this.redoStack = [];\n this.notify();\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","import type { Venue } from \"../models/types\";\n\nexport function serializeVenue(venue: Venue): string {\n return JSON.stringify(venue, null, 2);\n}\n\nexport function deserializeVenue(json: string): Venue {\n return JSON.parse(json) as Venue;\n}\n"]}
1
+ {"version":3,"sources":["../src/models/helpers.ts","../src/spatial/SpatialIndex.ts","../src/rendering/Viewport.ts","../src/rendering/LODLevel.ts","../src/rendering/SpriteAtlas.ts","../src/rendering/CategoryTextureCache.ts","../src/commands/CommandHistory.ts","../src/serialization/index.ts"],"names":["uuidv7","LODLevel"],"mappings":"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","file":"index.js","sourcesContent":["import { v7 as uuidv7 } from \"uuid\";\nimport type { AABB, Section, Seat, SeatStatusDefinition, Vec2, Venue } from \"./types\";\n\nexport const AVAILABLE_STATUS_ID = \"available\";\n\nexport const DEFAULT_SEAT_STATUSES: SeatStatusDefinition[] = [\n { id: AVAILABLE_STATUS_ID, name: \"Available\", color: \"#4caf50\" },\n { id: \"locked\", name: \"Locked\", color: \"#f44336\" },\n { id: \"booked\", name: \"Booked\", color: \"#9e9e9e\" },\n];\n\nconst LEGACY_STATUS_MAP: Record<string, string> = {\n held: \"locked\",\n blocked: \"locked\",\n sold: \"booked\",\n};\n\nfunction normalizeStatusId(rawStatus: string, allowedStatuses: Set<string>): string {\n const mapped = LEGACY_STATUS_MAP[rawStatus] ?? rawStatus;\n if (allowedStatuses.has(mapped)) return mapped;\n return AVAILABLE_STATUS_ID;\n}\n\nexport function seatWorldPosition(section: Section, seat: Seat): Vec2 {\n const cos = Math.cos(section.rotation);\n const sin = Math.sin(section.rotation);\n return {\n x: section.position.x + seat.position.x * cos - seat.position.y * sin,\n y: section.position.y + seat.position.x * sin + seat.position.y * cos,\n };\n}\n\nexport function sectionAABB(section: Section): AABB {\n const allPoints: Vec2[] = [];\n\n if (section.outline.length > 0) {\n const cos = Math.cos(section.rotation);\n const sin = Math.sin(section.rotation);\n for (const p of section.outline) {\n allPoints.push({\n x: section.position.x + p.x * cos - p.y * sin,\n y: section.position.y + p.x * sin + p.y * cos,\n });\n }\n }\n\n const allSeats = section.rows.flatMap((r) => r.seats);\n for (const seat of allSeats) {\n allPoints.push(seatWorldPosition(section, seat));\n }\n\n if (allPoints.length === 0) {\n return {\n minX: section.position.x,\n minY: section.position.y,\n maxX: section.position.x,\n maxY: section.position.y,\n };\n }\n\n const pad = 10;\n return {\n minX: Math.min(...allPoints.map((p) => p.x)) - pad,\n minY: Math.min(...allPoints.map((p) => p.y)) - pad,\n maxX: Math.max(...allPoints.map((p) => p.x)) + pad,\n maxY: Math.max(...allPoints.map((p) => p.y)) + pad,\n };\n}\n\nexport function venueAABB(venue: Venue): AABB {\n if (venue.sections.length === 0) {\n return { minX: 0, minY: 0, maxX: venue.bounds.width, maxY: venue.bounds.height };\n }\n const boxes = venue.sections.map(sectionAABB);\n return {\n minX: Math.min(...boxes.map((b) => b.minX)),\n minY: Math.min(...boxes.map((b) => b.minY)),\n maxX: Math.max(...boxes.map((b) => b.maxX)),\n maxY: Math.max(...boxes.map((b) => b.maxY)),\n };\n}\n\n/** Ray-casting point-in-polygon test. Works with any simple polygon. */\nexport function pointInPolygon(point: Vec2, polygon: Vec2[]): boolean {\n if (polygon.length < 3) return false;\n let inside = false;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const xi = polygon[i].x, yi = polygon[i].y;\n const xj = polygon[j].x, yj = polygon[j].y;\n if ((yi > point.y) !== (yj > point.y) &&\n point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/** Clamp a point to the nearest position inside a polygon (with margin). */\nexport function clampToPolygon(point: Vec2, polygon: Vec2[], margin = 5): Vec2 {\n if (polygon.length < 3 || pointInPolygon(point, polygon)) return point;\n\n // Find the closest point on any polygon edge\n let bestX = point.x, bestY = point.y, bestDist = Infinity;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const ax = polygon[j].x, ay = polygon[j].y;\n const bx = polygon[i].x, by = polygon[i].y;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) continue;\n const t = Math.max(0, Math.min(1, ((point.x - ax) * dx + (point.y - ay) * dy) / len2));\n const cx = ax + t * dx - margin * dy / Math.sqrt(len2);\n const cy = ay + t * dy + margin * dx / Math.sqrt(len2);\n const d = Math.hypot(point.x - cx, point.y - cy);\n if (d < bestDist) { bestDist = d; bestX = cx; bestY = cy; }\n }\n\n // Verify the clamped point is inside; if not just project onto edge without margin\n if (!pointInPolygon({ x: bestX, y: bestY }, polygon)) {\n bestDist = Infinity;\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const ax = polygon[j].x, ay = polygon[j].y;\n const bx = polygon[i].x, by = polygon[i].y;\n const dx = bx - ax, dy = by - ay;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) continue;\n const t = Math.max(0, Math.min(1, ((point.x - ax) * dx + (point.y - ay) * dy) / len2));\n const cx = ax + t * dx, cy = ay + t * dy;\n const d = Math.hypot(point.x - cx, point.y - cy);\n if (d < bestDist) { bestDist = d; bestX = cx; bestY = cy; }\n }\n }\n\n return { x: bestX, y: bestY };\n}\n\nexport function normalizeVenue(venue: Venue): Venue {\n const seatStatuses =\n venue.seatStatuses && venue.seatStatuses.length > 0\n ? venue.seatStatuses\n : DEFAULT_SEAT_STATUSES;\n const clonedStatuses = seatStatuses.map((status) => ({ ...status }));\n const allowedStatuses = new Set(clonedStatuses.map((status) => status.id));\n\n const sections = venue.sections.map((section) => ({\n ...section,\n rows: section.rows.map((row) => ({\n ...row,\n seats: row.seats.map((seat) => ({\n ...seat,\n status: normalizeStatusId(seat.status, allowedStatuses),\n })),\n })),\n }));\n\n const tables = venue.tables.map((table) => ({\n ...table,\n seats: table.seats.map((seat) => ({\n ...seat,\n status: normalizeStatusId(seat.status, allowedStatuses),\n })),\n }));\n\n return {\n ...venue,\n seatStatuses: clonedStatuses,\n sections,\n tables,\n };\n}\n\nexport function generateId(prefix = \"\"): string {\n const id = uuidv7();\n return prefix ? `${prefix}-${id}` : id;\n}\n","import RBush from \"rbush\";\nimport type { AABB, Section, Vec2 } from \"../models/types\";\nimport { seatWorldPosition, sectionAABB } from \"../models/helpers\";\n\nexport interface SpatialItem extends AABB {\n type: \"section\" | \"seat\";\n sectionId: string;\n seatId?: string;\n}\n\nexport class SpatialIndex {\n private tree = new RBush<SpatialItem>();\n private items: SpatialItem[] = [];\n\n buildFromSections(sections: Section[]): void {\n this.items = [];\n\n for (const section of sections) {\n const box = sectionAABB(section);\n this.items.push({\n ...box,\n type: \"section\",\n sectionId: section.id,\n });\n\n for (const row of section.rows) {\n for (const seat of row.seats) {\n const wp = seatWorldPosition(section, seat);\n const r = 8;\n this.items.push({\n minX: wp.x - r,\n minY: wp.y - r,\n maxX: wp.x + r,\n maxY: wp.y + r,\n type: \"seat\",\n sectionId: section.id,\n seatId: seat.id,\n });\n }\n }\n }\n\n this.tree.clear();\n this.tree.load(this.items);\n }\n\n queryViewport(viewport: AABB): SpatialItem[] {\n return this.tree.search(viewport);\n }\n\n queryPoint(point: Vec2, radius = 8): SpatialItem[] {\n return this.tree.search({\n minX: point.x - radius,\n minY: point.y - radius,\n maxX: point.x + radius,\n maxY: point.y + radius,\n });\n }\n\n queryRect(rect: AABB): SpatialItem[] {\n return this.tree.search(rect);\n }\n}\n","import type { AABB, Vec2 } from \"../models/types\";\n\nexport interface ViewportState {\n x: number;\n y: number;\n zoom: number;\n}\n\nconst MIN_ZOOM = 0.05;\nconst MAX_ZOOM = 4;\n\nexport class Viewport {\n x = 0;\n y = 0;\n zoom = 1;\n screenWidth = 0;\n screenHeight = 0;\n\n private listeners = new Set<() => void>();\n\n setScreenSize(width: number, height: number): void {\n this.screenWidth = width;\n this.screenHeight = height;\n this.notify();\n }\n\n pan(dx: number, dy: number): void {\n this.x += dx / this.zoom;\n this.y += dy / this.zoom;\n this.notify();\n }\n\n zoomAt(screenPoint: Vec2, factor: number): void {\n const newZoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, this.zoom * factor));\n\n // 1) World coordinate currently under the cursor\n const wx = screenPoint.x / this.zoom - this.x;\n const wy = screenPoint.y / this.zoom - this.y;\n\n // 2) Solve for the offset that keeps that world point at the same screen position\n // screenPoint = (world + offset) * newZoom → offset = screenPoint / newZoom - world\n this.x = screenPoint.x / newZoom - wx;\n this.y = screenPoint.y / newZoom - wy;\n this.zoom = newZoom;\n this.notify();\n }\n\n setZoom(zoom: number): void {\n this.zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));\n this.notify();\n }\n\n fitBounds(aabb: AABB, padding = 40): void {\n const contentW = aabb.maxX - aabb.minX;\n const contentH = aabb.maxY - aabb.minY;\n if (contentW <= 0 || contentH <= 0) return;\n\n const scaleX = (this.screenWidth - padding * 2) / contentW;\n const scaleY = (this.screenHeight - padding * 2) / contentH;\n this.zoom = Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, Math.min(scaleX, scaleY)));\n\n this.x = -(aabb.minX + contentW / 2) + this.screenWidth / (2 * this.zoom);\n this.y = -(aabb.minY + contentH / 2) + this.screenHeight / (2 * this.zoom);\n this.notify();\n }\n\n screenToWorld(screenX: number, screenY: number): Vec2 {\n return {\n x: screenX / this.zoom - this.x,\n y: screenY / this.zoom - this.y,\n };\n }\n\n worldToScreen(worldX: number, worldY: number): Vec2 {\n return {\n x: (worldX + this.x) * this.zoom,\n y: (worldY + this.y) * this.zoom,\n };\n }\n\n getVisibleAABB(): AABB {\n const topLeft = this.screenToWorld(0, 0);\n const bottomRight = this.screenToWorld(this.screenWidth, this.screenHeight);\n return {\n minX: topLeft.x,\n minY: topLeft.y,\n maxX: bottomRight.x,\n maxY: bottomRight.y,\n };\n }\n\n getState(): ViewportState {\n return { x: this.x, y: this.y, zoom: this.zoom };\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","export enum LODLevel {\n Overview = \"overview\",\n Section = \"section\",\n Detail = \"detail\",\n}\n\nconst SECTION_THRESHOLD = 0.3;\nconst DETAIL_THRESHOLD = 0.7;\n\nexport function getLODLevel(zoom: number): LODLevel {\n if (zoom < SECTION_THRESHOLD) return LODLevel.Overview;\n if (zoom < DETAIL_THRESHOLD) return LODLevel.Section;\n return LODLevel.Detail;\n}\n","import { Graphics, type Texture, type Renderer } from \"pixi.js\";\nimport type { SeatStatusDefinition } from \"../models\";\n\nexport interface SeatTextureSet {\n [statusId: string]: Texture;\n selected: Texture;\n hovered: Texture;\n}\n\nconst UI_TEXTURE_COLORS: Record<string, number> = {\n selected: 0x2196f3,\n hovered: 0x64b5f6,\n};\n\nfunction parseHexColor(color: string): number {\n return parseInt(color.replace(\"#\", \"\"), 16);\n}\n\nexport function createSeatTextures(\n renderer: Renderer,\n seatStatuses: SeatStatusDefinition[],\n radius = 7,\n categoryColor?: number,\n textureResolution?: number,\n): SeatTextureSet {\n const result: Partial<SeatTextureSet> = {};\n const resolution = textureResolution ?? (4 * (typeof window !== \"undefined\" ? window.devicePixelRatio || 1 : 1));\n\n for (const status of seatStatuses) {\n const g = new Graphics();\n const fillColor = status.id === \"available\" && categoryColor != null\n ? categoryColor\n : parseHexColor(status.color);\n g.circle(radius + 4, radius + 4, radius);\n g.fill({ color: fillColor });\n\n const texture = renderer.textureGenerator.generateTexture({\n target: g,\n resolution,\n antialias: true,\n });\n g.destroy();\n\n result[status.id] = texture;\n }\n\n for (const [statusId, color] of Object.entries(UI_TEXTURE_COLORS)) {\n const g = new Graphics();\n g.circle(radius + 4, radius + 4, radius);\n g.fill({ color });\n\n if (statusId === \"selected\") {\n g.circle(radius + 4, radius + 4, radius + 2);\n g.stroke({ color: 0xffffff, width: 2 });\n }\n\n const texture = renderer.textureGenerator.generateTexture({\n target: g,\n resolution,\n antialias: true,\n });\n g.destroy();\n\n result[statusId] = texture;\n }\n\n return result as SeatTextureSet;\n}\n\nexport function destroySeatTextures(textures: SeatTextureSet): void {\n for (const tex of Object.values(textures)) {\n tex.destroy(true);\n }\n}\n","import type { Renderer } from \"pixi.js\";\nimport type { SeatStatusDefinition } from \"../models\";\nimport {\n createSeatTextures,\n destroySeatTextures,\n type SeatTextureSet,\n} from \"./SpriteAtlas\";\n\nexport class CategoryTextureCache {\n private cache = new Map<string, SeatTextureSet>();\n private defaultTextures: SeatTextureSet | null = null;\n\n create(\n renderer: Renderer,\n categories: { id: string; color: string }[],\n seatStatuses: SeatStatusDefinition[],\n seatRadius = 7,\n ): void {\n this.destroy();\n this.defaultTextures = createSeatTextures(renderer, seatStatuses, seatRadius);\n\n for (const cat of categories) {\n const color = parseInt(cat.color.replace(\"#\", \"\"), 16);\n this.cache.set(cat.id, createSeatTextures(renderer, seatStatuses, seatRadius, color));\n }\n }\n\n get(categoryId: string): SeatTextureSet {\n return this.cache.get(categoryId) ?? this.defaultTextures!;\n }\n\n destroy(): void {\n for (const textures of this.cache.values()) {\n destroySeatTextures(textures);\n }\n if (this.defaultTextures) {\n destroySeatTextures(this.defaultTextures);\n }\n this.cache.clear();\n this.defaultTextures = null;\n }\n}\n","export interface Command {\n execute(): void;\n undo(): void;\n description: string;\n}\n\nexport class CommandHistory {\n private undoStack: Command[] = [];\n private redoStack: Command[] = [];\n private listeners = new Set<() => void>();\n\n execute(command: Command): void {\n command.execute();\n this.undoStack.push(command);\n this.redoStack = [];\n this.notify();\n }\n\n undo(): void {\n const command = this.undoStack.pop();\n if (!command) return;\n command.undo();\n this.redoStack.push(command);\n this.notify();\n }\n\n redo(): void {\n const command = this.redoStack.pop();\n if (!command) return;\n command.execute();\n this.undoStack.push(command);\n this.notify();\n }\n\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n clear(): void {\n this.undoStack = [];\n this.redoStack = [];\n this.notify();\n }\n\n subscribe(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private notify(): void {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n","import type { Venue } from \"../models/types\";\nimport { normalizeVenue } from \"../models/helpers\";\n\nexport function serializeVenue(venue: Venue): string {\n return JSON.stringify(venue, null, 2);\n}\n\nexport function deserializeVenue(json: string): Venue {\n return normalizeVenue(JSON.parse(json) as Venue);\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nex125/seatmap-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -28,10 +28,11 @@
28
28
  "devDependencies": {
29
29
  "@types/rbush": "^4.0.0",
30
30
  "pixi.js": "^8",
31
- "tsup": "^8",
32
- "typescript": "^5.7"
31
+ "tsup": "^8.4.0",
32
+ "typescript": "~5.9.3"
33
33
  },
34
34
  "dependencies": {
35
- "rbush": "^4.0.1"
35
+ "rbush": "^4.0.1",
36
+ "uuid": "^13.0.0"
36
37
  }
37
38
  }