@ericchen1990/pano-view 3.4.2 → 3.5.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 +522 -73
- package/README.zh-CN.md +490 -71
- package/dist/data.cjs +903 -0
- package/dist/data.cjs.map +1 -0
- package/dist/data.d.mts +499 -0
- package/dist/data.d.ts +499 -0
- package/dist/data.mjs +880 -0
- package/dist/data.mjs.map +1 -0
- package/dist/index.cjs +8901 -8569
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +600 -458
- package/dist/index.d.ts +600 -458
- package/dist/index.mjs +8980 -8646
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data.ts","../src/data/errors.ts","../../../shared/viewer-config.ts","../src/tile/multires.ts","../src/data/viewer.ts","../src/data/hotspots.ts","../src/data/project.ts"],"sourcesContent":["export { PanoDataError } from \"./data/errors\";\nexport type { PanoDataErrorCode } from \"./data/errors\";\nexport { sceneFromViewerConfig, loadSceneFromJson } from \"./data/viewer\";\nexport type {\n AssetUrlContext,\n AssetUrlResolver,\n JsonRequestOptions,\n SceneFromViewerConfigOptions,\n LoadSceneFromJsonOptions,\n} from \"./data/viewer\";\nexport { parsePanoProject, loadPanoProject } from \"./data/project\";\nexport type {\n PanoProjectDefinition,\n PanoProjectSceneDefinition,\n LoadedPanoProject,\n LoadedProjectScene,\n LoadPanoProjectOptions,\n} from \"./data/project\";\nexport type { ProjectHotspotDefinition } from \"./data/hotspots\";\nexport type {\n ViewerConfig,\n ViewerDocument,\n CubemapViewerConfig,\n SphereViewerConfig,\n} from \"../../../shared/viewer-config\";\n","export type PanoDataErrorCode =\n | \"INVALID_OPTIONS\"\n | \"FETCH_FAILED\"\n | \"HTTP_ERROR\"\n | \"INVALID_JSON\"\n | \"INVALID_CONFIG\"\n | \"UNSUPPORTED_SCHEMA_VERSION\"\n | \"UNSUPPORTED_PROJECTION\"\n | \"INVALID_PROJECT\"\n | \"INVALID_REFERENCE\"\n | \"ABORTED\";\n\nexport class PanoDataError extends Error {\n readonly code: PanoDataErrorCode;\n readonly status?: number;\n readonly sceneId?: string;\n readonly field?: string;\n readonly cause?: unknown;\n constructor(\n code: PanoDataErrorCode,\n message: string,\n details: {\n status?: number;\n sceneId?: string;\n field?: string;\n cause?: unknown;\n } = {}\n ) {\n super(message);\n this.name = \"PanoDataError\";\n this.code = code;\n Object.assign(this, details);\n }\n}\n\nexport function aborted(signal?: AbortSignal | null): void {\n if (signal?.aborted)\n throw new PanoDataError(\"ABORTED\", \"Loading was cancelled\");\n}\n","/** The portable rendering contract shared by the converter and browser viewer. */\nexport type ViewerCubeFace = \"f\" | \"r\" | \"b\" | \"l\" | \"u\" | \"d\";\nexport type CubemapViewerConfig = {\n type: \"tile\";\n multires: { tileSize: number; levels: number[] };\n urlTemplate: string;\n previewUrl: string;\n previewFaceOrder: ViewerCubeFace[];\n};\nexport type SphereViewerConfig = {\n type: \"sphereTile\";\n multires: { tileSize: number; levels: { width: number; height: number }[] };\n urlTemplate: string;\n previewUrl: string;\n indexBase: 0 | 1;\n};\nexport type ViewerConfig = CubemapViewerConfig | SphereViewerConfig;\nexport type ViewerDocument = ViewerConfig & { schemaVersion: 1 };\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function requiredString(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !value.trim())\n throw new Error(`${field}: expected a nonempty string`);\n return value;\n}\n\nfunction positive(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value <= 0)\n throw new Error(`${field}: expected a positive safe integer`);\n return value;\n}\n\nexport function validateViewerConfig(value: unknown): ViewerConfig {\n if (!isRecord(value)) throw new Error(\"viewerConfig: expected an object\");\n if (value.type !== \"tile\" && value.type !== \"sphereTile\")\n throw new Error(\"type: expected tile or sphereTile\");\n if (!isRecord(value.multires))\n throw new Error(\"multires: expected an object\");\n const tileSize = positive(value.multires.tileSize, \"multires.tileSize\");\n if (tileSize > 8192) throw new Error(\"multires.tileSize: maximum is 8192\");\n const input = value.multires.levels;\n if (!Array.isArray(input) || input.length === 0 || input.length > 64)\n throw new Error(\"multires.levels: expected 1 to 64 levels\");\n const urlTemplate = requiredString(value.urlTemplate, \"urlTemplate\");\n const previewUrl = requiredString(value.previewUrl, \"previewUrl\");\n if (/%/.test(urlTemplate.replace(/%s|%l|%0*[hxucvywr]/g, \"\")))\n throw new Error(\"urlTemplate: unsupported placeholder\");\n if (value.type === \"tile\") {\n const levels = input.map((level, i) =>\n positive(level, `multires.levels[${i}]`)\n );\n if (levels.some((level, i) => i > 0 && level <= levels[i - 1]!))\n throw new Error(\"multires.levels: face sizes must increase\");\n const order = value.previewFaceOrder;\n if (\n !Array.isArray(order) ||\n order.length !== 6 ||\n ![\"f\", \"r\", \"b\", \"l\", \"u\", \"d\"].every((face) => order.includes(face))\n )\n throw new Error(\"previewFaceOrder: expected six unique cube faces\");\n return {\n type: \"tile\",\n multires: { tileSize, levels },\n urlTemplate,\n previewUrl,\n previewFaceOrder: [...order] as ViewerCubeFace[],\n };\n }\n if (urlTemplate.includes(\"%s\"))\n throw new Error(\"urlTemplate: sphere has no cube face\");\n if (value.indexBase !== 0 && value.indexBase !== 1)\n throw new Error(\"indexBase: expected 0 or 1\");\n const levels = input.map((level: unknown, i) => {\n if (!isRecord(level))\n throw new Error(`multires.levels[${i}]: expected dimensions`);\n const width = positive(level.width, `multires.levels[${i}].width`);\n const height = positive(level.height, `multires.levels[${i}].height`);\n if (Math.abs(width - 2 * height) > 2)\n throw new Error(`multires.levels[${i}]: expected a full 2:1 panorama`);\n return { width, height };\n });\n if (\n levels.some(\n (level, i) =>\n i > 0 &&\n (level.width <= levels[i - 1]!.width ||\n level.height <= levels[i - 1]!.height)\n )\n )\n throw new Error(\"multires.levels: dimensions must increase\");\n return {\n type: \"sphereTile\",\n multires: { tileSize, levels },\n urlTemplate,\n previewUrl,\n indexBase: value.indexBase,\n };\n}\n","import { resolveAssetUrl } from \"../asset-url\";\nimport type {\n TileAddress,\n TileMultiresConfig,\n} from \"./types\";\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0 || !Number.isInteger(value)) {\n throw new Error(`${name} must be a positive integer, received ${String(value)}`);\n }\n return value;\n}\n\nfunction ascendingLevels(levels: number[]): number[] {\n for (let index = 1; index < levels.length; index += 1) {\n if (levels[index]! <= levels[index - 1]!) {\n throw new Error(\"multires face sizes must be strictly ascending\");\n }\n }\n return levels;\n}\n\nexport function parseMultires(\n multires: string | TileMultiresConfig,\n): TileMultiresConfig {\n if (typeof multires !== \"string\") {\n const tileSize = positiveInteger(multires.tileSize, \"multires.tileSize\");\n if (multires.levels.length === 0) {\n throw new Error(\"multires.levels must contain at least one face size\");\n }\n const levels = ascendingLevels(\n multires.levels.map((level, index) =>\n positiveInteger(level, `multires.levels[${index}]`),\n ),\n );\n return { tileSize, levels };\n }\n\n const values = multires.split(\",\").map((part) => Number(part.trim()));\n\n if (values.length < 2 || values.some((value) => !Number.isFinite(value))) {\n throw new Error(\n \"multires must contain a tile size followed by at least one face size\",\n );\n }\n\n const tileSize = positiveInteger(values[0]!, \"multires tile size\");\n const levels = ascendingLevels(\n values.slice(1).map((level, index) =>\n positiveInteger(level, `multires level ${index + 1}`),\n ),\n );\n return { tileSize, levels };\n}\n\nexport const DEFAULT_TILE_URL_TEMPLATE = \"tiles/%s/l%l/%v/l%l_%s_%h_%v.webp\";\n\nexport function buildDefaultTileUrlTemplate(): string {\n return DEFAULT_TILE_URL_TEMPLATE;\n}\n\nexport function resolveRelativeTileUrl(\n baseUrl: string,\n relativePath: string,\n): string {\n return resolveAssetUrl(baseUrl, relativePath);\n}\n\nexport function resolveTemplateUrl(\n template: string,\n address: Pick<TileAddress, \"face\" | \"level\" | \"row\" | \"col\">,\n): string {\n return template\n .replace(/%s/g, address.face)\n .replace(/%l/g, String(address.level))\n .replace(/%(0*)([hxucvywr])/g, (_match, zeroes: string, placeholder: string) => {\n const value = \"hxuc\".includes(placeholder)\n ? address.col\n : address.row;\n return String(value).padStart(zeroes.length + 1, \"0\");\n });\n}\n","import {\n isRecord,\n validateViewerConfig,\n type ViewerConfig,\n} from \"../../../../shared/viewer-config\";\nimport type { TileScene, SphereTileScene } from \"../scenes\";\nimport type { TileAddress } from \"../tile/types\";\nimport type { SphereTileAddress } from \"../sphere-tile/types\";\nimport { resolveTemplateUrl } from \"../tile/multires\";\nimport { PanoDataError, aborted } from \"./errors\";\n\nexport type AssetUrlContext = {\n defaultUrl: string;\n kind: \"tile\" | \"preview\" | \"hotspot\";\n sceneId: string;\n hotspotId?: string;\n};\nexport type AssetUrlResolver = (\n path: string,\n context: AssetUrlContext\n) => string;\nexport type JsonRequestOptions = {\n requestInit?: Pick<RequestInit, \"headers\" | \"credentials\" | \"signal\">;\n};\nexport type SceneFromViewerConfigOptions = {\n id: string;\n baseUrl: string;\n resolveAssetUrl?: AssetUrlResolver;\n};\nexport type LoadSceneFromJsonOptions = Omit<\n SceneFromViewerConfigOptions,\n \"baseUrl\"\n> &\n JsonRequestOptions & { baseUrl?: string };\n\n/** URL resolution is intentionally independent of React and browser globals on the server. */\nexport function documentUrl(input: string): string {\n try {\n const url = new URL(\n input,\n typeof document === \"undefined\" ? undefined : document.baseURI\n );\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\")\n throw new Error(\"Use HTTP(S)\");\n return url.href;\n } catch (cause) {\n throw new PanoDataError(\n \"INVALID_OPTIONS\",\n \"Expected an HTTP(S) URL; Node.js requires an absolute URL\",\n { cause }\n );\n }\n}\n\nexport function directoryUrl(input: string): string {\n const url = new URL(input);\n url.search = \"\";\n url.hash = \"\";\n if (!url.pathname.endsWith(\"/\")) url.pathname += \"/\";\n return url.href;\n}\n\nexport function resolveResource(baseUrl: string, path: string): string {\n try {\n const url = new URL(path, directoryUrl(baseUrl));\n if (![\"http:\", \"https:\", \"blob:\", \"data:\"].includes(url.protocol))\n throw new Error(\"Unsupported resource URL protocol\");\n return url.href;\n } catch (cause) {\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n `Invalid resource path: ${path}`,\n { cause }\n );\n }\n}\n\nexport function mapResource(\n path: string,\n context: AssetUrlContext,\n resolver?: AssetUrlResolver\n): string {\n let result: string;\n try {\n result = resolver ? resolver(path, context) : context.defaultUrl;\n } catch (cause) {\n throw new PanoDataError(\"INVALID_CONFIG\", \"resolveAssetUrl failed\", {\n sceneId: context.sceneId,\n cause,\n });\n }\n if (typeof result !== \"string\" || !result.trim())\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"resolveAssetUrl must return a nonempty final URL\",\n { sceneId: context.sceneId }\n );\n // A root path is already final; relative callback results are ambiguous and rejected.\n if (!result.startsWith(\"/\") && !/^(https?:|blob:|data:)/i.test(result))\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"resolveAssetUrl must return an absolute URL or a site-root path\",\n { sceneId: context.sceneId }\n );\n return result;\n}\n\nexport function parseConfig(value: unknown): ViewerConfig {\n if (isRecord(value) && value.type !== \"tile\" && value.type !== \"sphereTile\")\n throw new PanoDataError(\n \"UNSUPPORTED_PROJECTION\",\n \"Expected a tile or sphereTile configuration\",\n { field: \"type\" }\n );\n try {\n return validateViewerConfig(value);\n } catch (cause) {\n const message =\n cause instanceof Error ? cause.message : \"Invalid viewer configuration\";\n throw new PanoDataError(\"INVALID_CONFIG\", message, {\n cause,\n field: message.split(\":\")[0],\n });\n }\n}\n\nexport function sceneFromViewerConfig(\n value: unknown,\n options: SceneFromViewerConfigOptions\n): TileScene | SphereTileScene {\n if (\n !options ||\n typeof options.id !== \"string\" ||\n !options.id.trim() ||\n typeof options.baseUrl !== \"string\" ||\n !options.baseUrl.trim()\n )\n throw new PanoDataError(\"INVALID_OPTIONS\", \"id and baseUrl are required\");\n const config = parseConfig(value);\n const baseUrl = directoryUrl(documentUrl(options.baseUrl));\n const resolve = (path: string, kind: \"tile\" | \"preview\") =>\n mapResource(\n path,\n {\n kind,\n sceneId: options.id,\n defaultUrl: resolveResource(baseUrl, path),\n },\n options.resolveAssetUrl\n );\n const previewUrl = resolve(config.previewUrl, \"preview\");\n if (config.type === \"tile\") {\n return {\n ...config,\n id: options.id,\n baseUrl,\n previewUrl,\n ...(options.resolveAssetUrl\n ? {\n resolveTileUrl: (address: TileAddress) =>\n resolve(resolveTemplateUrl(config.urlTemplate, address), \"tile\"),\n }\n : {}),\n };\n }\n return {\n ...config,\n id: options.id,\n baseUrl,\n previewUrl,\n ...(options.resolveAssetUrl\n ? {\n resolveTileUrl: (address: SphereTileAddress) => {\n // Sphere callbacks use logical zero-based addresses; the document controls storage indices.\n const path = resolveTemplateUrl(config.urlTemplate, {\n face: \"f\",\n level: address.level + config.indexBase,\n row: address.row + config.indexBase,\n col: address.col + config.indexBase,\n });\n return resolve(path, \"tile\");\n },\n }\n : {}),\n };\n}\n\nexport async function readJson(\n url: string,\n options: JsonRequestOptions\n): Promise<{ value: unknown; url: string }> {\n const signal = options.requestInit?.signal;\n aborted(signal);\n let response: Response;\n try {\n response = await fetch(url, { ...options.requestInit, method: \"GET\" });\n } catch (cause) {\n aborted(signal);\n throw new PanoDataError(\n \"FETCH_FAILED\",\n \"Could not fetch JSON; check the network and server CORS settings\",\n { cause }\n );\n }\n aborted(signal);\n if (!response.ok)\n throw new PanoDataError(\n \"HTTP_ERROR\",\n `JSON request returned HTTP ${response.status}`,\n { status: response.status }\n );\n try {\n const value: unknown = await response.json();\n aborted(signal);\n return { value, url: response.url || url };\n } catch (cause) {\n aborted(signal);\n throw new PanoDataError(\n \"INVALID_JSON\",\n \"Expected JSON; check for an HTML fallback or login page\",\n { cause }\n );\n }\n}\n\nexport async function loadSceneFromJson(\n url: string,\n options: LoadSceneFromJsonOptions\n): Promise<TileScene | SphereTileScene> {\n if (!options || typeof options.id !== \"string\" || !options.id.trim())\n throw new PanoDataError(\"INVALID_OPTIONS\", \"id is required\");\n const response = await readJson(documentUrl(url), options);\n if (!isRecord(response.value))\n throw new PanoDataError(\n \"INVALID_CONFIG\",\n \"viewer.json must contain an object\"\n );\n if (response.value.schemaVersion !== 1)\n throw new PanoDataError(\n \"UNSUPPORTED_SCHEMA_VERSION\",\n \"Unsupported viewer.json schemaVersion\",\n { field: \"schemaVersion\" }\n );\n return sceneFromViewerConfig(response.value, {\n ...options,\n baseUrl: options.baseUrl ?? new URL(\".\", response.url).href,\n });\n}\n","import { isRecord, requiredString } from \"../../../../shared/viewer-config\";\nimport type { HotspotDefinition } from \"../hotspot/definitions\";\nimport type { HotspotPosition } from \"../hotspot/types\";\nimport { PanoDataError } from \"./errors\";\nimport { mapResource, resolveResource, type AssetUrlResolver } from \"./viewer\";\n\nexport type ProjectHotspotDefinition = HotspotDefinition & {\n action?: { type: \"scene\"; sceneId: string };\n};\n\nconst common = [\n \"label\",\n \"visible\",\n \"interactive\",\n \"pointerEvents\",\n \"cursor\",\n \"renderOrder\",\n \"tooltip\",\n \"tooltipTrigger\",\n \"tooltipPlacement\",\n \"tooltipOffset\",\n \"tooltipAppearance\",\n];\nconst point = [\n \"position\",\n \"width\",\n \"height\",\n \"scale\",\n \"mode\",\n \"distance\",\n \"scaleMode\",\n \"referenceFov\",\n \"rotation\",\n \"opacity\",\n];\nconst fields = {\n image: [\"src\"],\n graphic: [\"graphic\"],\n sequence: [\"src\", \"frameCount\", \"frameDirection\", \"playing\", \"fps\", \"loop\"],\n video: [\n \"src\",\n \"poster\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"volume\",\n \"playsInline\",\n \"preload\",\n \"crossOrigin\",\n ],\n audio: [\n \"src\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"volume\",\n \"pauseWhenHidden\",\n \"range\",\n \"icon\",\n \"playingIcon\",\n \"marker\",\n \"crossOrigin\",\n ],\n text: [\n \"text\",\n \"fontFamily\",\n \"fontSize\",\n \"fontWeight\",\n \"fontStyle\",\n \"color\",\n \"background\",\n \"backgroundOpacity\",\n \"padding\",\n \"align\",\n \"verticalAlign\",\n \"whiteSpace\",\n \"lineHeight\",\n \"borderRadius\",\n \"stroke\",\n \"strokeWidth\",\n ],\n iframe: [\n \"src\",\n \"title\",\n \"sandbox\",\n \"allow\",\n \"referrerPolicy\",\n \"loading\",\n \"pointerPolicy\",\n \"background\",\n ],\n polygon: [\n \"vertices\",\n \"fill\",\n \"fillOpacity\",\n \"stroke\",\n \"strokeWidth\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n ],\n polyline: [\n \"vertices\",\n \"stroke\",\n \"strokeWidth\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n ],\n} satisfies Record<HotspotDefinition[\"type\"], string[]>;\nconst booleanFields = new Set([\n \"visible\",\n \"interactive\",\n \"playing\",\n \"loop\",\n \"muted\",\n \"playsInline\",\n \"pauseWhenHidden\",\n \"marker\",\n]);\nconst numberFields = new Set([\n \"renderOrder\",\n \"tooltipOffset\",\n \"width\",\n \"height\",\n \"scale\",\n \"distance\",\n \"referenceFov\",\n \"rotation\",\n \"opacity\",\n \"frameCount\",\n \"fps\",\n \"volume\",\n \"range\",\n \"fontSize\",\n \"backgroundOpacity\",\n \"padding\",\n \"lineHeight\",\n \"borderRadius\",\n \"strokeWidth\",\n \"fillOpacity\",\n \"strokeOpacity\",\n \"strokeDashSize\",\n \"strokeGapSize\",\n]);\nconst positiveFields = new Set([\n \"width\",\n \"height\",\n \"scale\",\n \"distance\",\n \"referenceFov\",\n \"frameCount\",\n \"fps\",\n \"fontSize\",\n \"lineHeight\",\n]);\nconst enums: Record<string, readonly string[]> = {\n pointerEvents: [\"auto\", \"none\"],\n tooltipTrigger: [\"always\", \"hover\", \"click\"],\n tooltipPlacement: [\"top\", \"bottom\", \"left\", \"right\"],\n mode: [\"surface\", \"billboard\"],\n scaleMode: [\"fov\", \"fixed\"],\n frameDirection: [\"horizontal\", \"vertical\"],\n preload: [\"none\", \"metadata\", \"auto\"],\n crossOrigin: [\"\", \"anonymous\", \"use-credentials\"],\n fontStyle: [\"normal\", \"italic\"],\n align: [\"left\", \"center\", \"right\"],\n verticalAlign: [\"top\", \"middle\", \"bottom\"],\n whiteSpace: [\"normal\", \"nowrap\"],\n loading: [\"eager\", \"lazy\"],\n pointerPolicy: [\"hotspot\", \"content\"],\n referrerPolicy: [\n \"\",\n \"no-referrer\",\n \"no-referrer-when-downgrade\",\n \"origin\",\n \"origin-when-cross-origin\",\n \"same-origin\",\n \"strict-origin\",\n \"strict-origin-when-cross-origin\",\n \"unsafe-url\",\n ],\n};\n\nfunction finite(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n throw new Error(`${field}: expected a finite number`);\n return value;\n}\n\nexport function parsePosition(value: unknown, field: string): HotspotPosition {\n if (!isRecord(value)) throw new Error(`${field}: expected yaw and pitch`);\n const yaw = finite(value.yaw, `${field}.yaw`);\n const pitch = finite(value.pitch, `${field}.pitch`);\n if (Math.abs(pitch) > 90)\n throw new Error(`${field}.pitch: expected -90 to 90`);\n return { yaw, pitch };\n}\n\nfunction parseGraphic(value: unknown): Record<string, unknown> {\n if (!isRecord(value)) throw new Error(\"graphic: expected an object\");\n const kind = requiredString(value.kind, \"graphic.kind\");\n if (\n ![\n \"circle\",\n \"triangle\",\n \"diamond\",\n \"star\",\n \"arrow\",\n \"rectangle\",\n \"ring\",\n \"svg\",\n \"path\",\n ].includes(kind)\n )\n throw new Error(\"graphic.kind: unsupported graphic\");\n const result: Record<string, unknown> = { kind };\n for (const key of [\"fill\", \"stroke\"]) {\n if (value[key] !== undefined)\n result[key] = requiredString(value[key], `graphic.${key}`);\n }\n for (const key of [\"strokeWidth\", \"cornerRadius\", \"innerRadius\"]) {\n if (value[key] !== undefined)\n result[key] = finite(value[key], `graphic.${key}`);\n }\n if (kind === \"svg\") result.src = requiredString(value.src, \"graphic.src\");\n if (kind === \"path\") {\n result.path = requiredString(value.path, \"graphic.path\");\n if (!Array.isArray(value.viewBox) || value.viewBox.length !== 4)\n throw new Error(\"graphic.viewBox: expected four numbers\");\n const viewBox = value.viewBox.map((n, i) =>\n finite(n, `graphic.viewBox[${i}]`)\n );\n if (viewBox[2]! <= 0 || viewBox[3]! <= 0)\n throw new Error(\"graphic.viewBox: width and height must be positive\");\n result.viewBox = viewBox;\n }\n return result;\n}\n\nfunction parseTooltip(value: unknown): unknown {\n if (typeof value === \"string\") return value;\n if (!isRecord(value)) throw new Error(\"tooltip: expected text or an object\");\n const result: Record<string, string> = {};\n for (const key of [\"text\", \"image\", \"imageAlt\"]) {\n if (value[key] !== undefined) {\n if (typeof value[key] !== \"string\")\n throw new Error(`tooltip.${key}: expected a string`);\n result[key] = value[key];\n }\n }\n return result;\n}\n\nfunction parseAppearance(value: unknown): Record<string, string | number> {\n if (!isRecord(value))\n throw new Error(\"tooltipAppearance: expected an object\");\n const result: Record<string, string | number> = {};\n for (const key of [\n \"background\",\n \"color\",\n \"border\",\n \"borderRadius\",\n \"shadow\",\n \"padding\",\n \"fontSize\",\n \"fontFamily\",\n \"lineHeight\",\n \"letterSpacing\",\n ]) {\n const item = value[key];\n if (item === undefined) continue;\n if (\n [\"background\", \"color\", \"border\", \"shadow\", \"fontFamily\"].includes(key) &&\n typeof item !== \"string\"\n )\n throw new Error(`tooltipAppearance.${key}: expected a string`);\n if (\n typeof item !== \"string\" &&\n (typeof item !== \"number\" || !Number.isFinite(item))\n )\n throw new Error(\n `tooltipAppearance.${key}: expected a string or finite number`\n );\n result[key] = item;\n }\n return result;\n}\n\nexport function parseHotspot(\n value: unknown,\n sceneId: string,\n field: string\n): ProjectHotspotDefinition {\n try {\n if (!isRecord(value)) throw new Error(\"expected a hotspot object\");\n const type = requiredString(value.type, \"type\");\n if (!Object.prototype.hasOwnProperty.call(fields, type))\n throw new Error(\"type: unsupported hotspot type\");\n const kind = type as HotspotDefinition[\"type\"];\n const result: Record<string, unknown> = {\n type,\n id: requiredString(value.id, \"id\"),\n };\n const isPath = kind === \"polygon\" || kind === \"polyline\";\n const allowed = [...common, ...(isPath ? [] : point), ...fields[kind]];\n for (const key of allowed) {\n const item = value[key];\n if (item === undefined) continue;\n if (key === \"position\") result[key] = parsePosition(item, key);\n else if (key === \"vertices\") {\n if (!Array.isArray(item) || item.length < (kind === \"polygon\" ? 3 : 2))\n throw new Error(\"vertices: not enough points\");\n result[key] = item.map((p, i) => parsePosition(p, `vertices[${i}]`));\n } else if (key === \"graphic\") result[key] = parseGraphic(item);\n else if (key === \"tooltip\") result[key] = parseTooltip(item);\n else if (key === \"tooltipAppearance\") result[key] = parseAppearance(item);\n else if (booleanFields.has(key)) {\n if (typeof item !== \"boolean\")\n throw new Error(`${key}: expected a boolean`);\n result[key] = item;\n } else if (numberFields.has(key)) {\n const n = finite(item, key);\n if (positiveFields.has(key) && n <= 0)\n throw new Error(`${key}: expected a positive number`);\n if (key === \"frameCount\" && !Number.isSafeInteger(n))\n throw new Error(\"frameCount: expected an integer\");\n if (\n [\n \"opacity\",\n \"fillOpacity\",\n \"strokeOpacity\",\n \"volume\",\n \"backgroundOpacity\",\n ].includes(key) &&\n (n < 0 || n > 1)\n )\n throw new Error(`${key}: expected 0 to 1`);\n result[key] = n;\n } else if (key === \"fontWeight\" && typeof item === \"number\")\n result[key] = finite(item, key);\n else if (key === \"src\" && kind === \"audio\" && Array.isArray(item)) {\n if (!item.length) throw new Error(\"src: expected audio sources\");\n result[key] = item.map((src, i) => requiredString(src, `src[${i}]`));\n } else {\n if (typeof item !== \"string\")\n throw new Error(`${key}: expected a string`);\n if (enums[key] && !enums[key].includes(item))\n throw new Error(`${key}: unsupported value`);\n result[key] = item;\n }\n }\n if (!isPath && !result.position) throw new Error(\"position: required\");\n if (isPath && !result.vertices) throw new Error(\"vertices: required\");\n if (\n [\"image\", \"sequence\", \"video\", \"audio\", \"iframe\"].includes(kind) &&\n !(typeof result.src === \"string\"\n ? result.src.trim()\n : Array.isArray(result.src))\n )\n throw new Error(\"src: required\");\n if (kind === \"graphic\" && !result.graphic)\n throw new Error(\"graphic: required\");\n if (kind === \"text\" && typeof result.text !== \"string\")\n throw new Error(\"text: required\");\n if (kind === \"sequence\" && !result.frameCount)\n throw new Error(\"frameCount: required\");\n if (value.action !== undefined) {\n if (!isRecord(value.action) || value.action.type !== \"scene\")\n throw new Error(\"action: expected a scene action\");\n result.action = {\n type: \"scene\",\n sceneId: requiredString(value.action.sceneId, \"action.sceneId\"),\n };\n }\n return result as ProjectHotspotDefinition;\n } catch (cause) {\n const detail = cause instanceof Error ? cause.message : \"Invalid hotspot\";\n throw new PanoDataError(\"INVALID_PROJECT\", `${field}.${detail}`, {\n sceneId,\n field: `${field}.${detail.split(\":\")[0]}`,\n cause,\n });\n }\n}\n\nexport function resolveHotspotAssets(\n hotspot: ProjectHotspotDefinition,\n baseUrl: string,\n sceneId: string,\n resolver?: AssetUrlResolver\n): ProjectHotspotDefinition {\n const resolve = (path: string) =>\n path\n ? mapResource(\n path,\n {\n kind: \"hotspot\",\n sceneId,\n hotspotId: hotspot.id,\n defaultUrl: resolveResource(baseUrl, path),\n },\n resolver\n )\n : path;\n const result = { ...hotspot };\n if (\"src\" in result)\n result.src = Array.isArray(result.src)\n ? result.src.map(resolve)\n : resolve(result.src);\n if (\"poster\" in result && result.poster)\n result.poster = resolve(result.poster);\n if (result.type === \"audio\") {\n if (result.icon) result.icon = resolve(result.icon);\n if (result.playingIcon) result.playingIcon = resolve(result.playingIcon);\n }\n if (result.type === \"graphic\" && result.graphic.kind === \"svg\")\n result.graphic = { ...result.graphic, src: resolve(result.graphic.src) };\n if (typeof result.tooltip === \"object\")\n result.tooltip = {\n ...result.tooltip,\n ...(result.tooltip.image ? { image: resolve(result.tooltip.image) } : {}),\n };\n return result;\n}\n","import {\n isRecord,\n requiredString,\n type ViewerConfig,\n} from \"../../../../shared/viewer-config\";\nimport type { TileScene, SphereTileScene } from \"../scenes\";\nimport type { PanoViewerState } from \"../types\";\nimport { PanoDataError, aborted } from \"./errors\";\nimport {\n parseHotspot,\n parsePosition,\n resolveHotspotAssets,\n type ProjectHotspotDefinition,\n} from \"./hotspots\";\nimport {\n documentUrl,\n directoryUrl,\n readJson,\n parseConfig,\n resolveResource,\n sceneFromViewerConfig,\n loadSceneFromJson,\n type AssetUrlResolver,\n type JsonRequestOptions,\n} from \"./viewer\";\n\nexport type PanoProjectSceneDefinition = {\n id: string;\n title?: string;\n source: (\n | { viewerUrl: string; viewerConfig?: never }\n | { viewerConfig: ViewerConfig; viewerUrl?: never }\n ) & { baseUrl?: string };\n initialView?: Partial<PanoViewerState>;\n hotspots?: ProjectHotspotDefinition[];\n};\nexport type PanoProjectDefinition = {\n schemaVersion: 1;\n title?: string;\n initialSceneId?: string;\n scenes: PanoProjectSceneDefinition[];\n};\nexport type LoadedProjectScene = {\n scene: TileScene | SphereTileScene;\n title?: string;\n initialView?: PanoViewerState;\n hotspots: ProjectHotspotDefinition[];\n};\nexport type LoadedPanoProject = {\n title?: string;\n initialSceneId: string;\n scenes: LoadedProjectScene[];\n};\nexport type LoadPanoProjectOptions = JsonRequestOptions & {\n /** Directory used for project-relative references. Required for object input. */\n baseUrl?: string;\n resolveAssetUrl?: AssetUrlResolver;\n};\n\nfunction optionalString(\n record: Record<string, unknown>,\n key: string\n): string | undefined {\n return record[key] === undefined\n ? undefined\n : requiredString(record[key], key);\n}\n\nexport function parsePanoProject(value: unknown): PanoProjectDefinition {\n if (!isRecord(value))\n throw new PanoDataError(\"INVALID_PROJECT\", \"Expected a project object\");\n if (value.schemaVersion !== 1)\n throw new PanoDataError(\n \"UNSUPPORTED_SCHEMA_VERSION\",\n \"Unsupported project schemaVersion\",\n { field: \"schemaVersion\" }\n );\n try {\n if (!Array.isArray(value.scenes) || !value.scenes.length)\n throw new Error(\"scenes: expected a nonempty array\");\n const ids = new Set<string>();\n const scenes = value.scenes.map(\n (entry: unknown, index): PanoProjectSceneDefinition => {\n let id: string | undefined;\n const field = `scenes[${index}]`;\n try {\n if (!isRecord(entry)) throw new Error(\"expected a scene object\");\n id = requiredString(entry.id, \"id\");\n if (ids.has(id)) throw new Error(\"id: duplicate scene ID\");\n ids.add(id);\n if (!isRecord(entry.source))\n throw new Error(\"source: expected an object\");\n const src = entry.source;\n if (\n (src.viewerUrl !== undefined) ===\n (src.viewerConfig !== undefined)\n )\n throw new Error(\n \"source: provide exactly one of viewerUrl or viewerConfig\"\n );\n const baseUrl = optionalString(src, \"baseUrl\");\n const source: PanoProjectSceneDefinition[\"source\"] =\n src.viewerUrl !== undefined\n ? {\n viewerUrl: requiredString(src.viewerUrl, \"source.viewerUrl\"),\n baseUrl,\n }\n : { viewerConfig: parseConfig(src.viewerConfig), baseUrl };\n let initialView: Partial<PanoViewerState> | undefined;\n if (entry.initialView !== undefined) {\n if (!isRecord(entry.initialView))\n throw new Error(\"initialView: expected an object\");\n const input = entry.initialView;\n const position = parsePosition(\n { yaw: input.yaw ?? 0, pitch: input.pitch ?? 0 },\n \"initialView\"\n );\n const fov = input.fov ?? 75;\n if (\n typeof fov !== \"number\" ||\n !Number.isFinite(fov) ||\n fov <= 0 ||\n fov >= 180\n )\n throw new Error(\n \"initialView.fov: expected a number between 0 and 180\"\n );\n initialView = { ...position, fov };\n }\n if (entry.hotspots !== undefined && !Array.isArray(entry.hotspots))\n throw new Error(\"hotspots: expected an array\");\n const hotspotIds = new Set<string>();\n const hotspots = ((entry.hotspots ?? []) as unknown[]).map(\n (hotspot, i) => {\n const result = parseHotspot(\n hotspot,\n id!,\n `${field}.hotspots[${i}]`\n );\n if (hotspotIds.has(result.id))\n throw new Error(`hotspots[${i}].id: duplicate hotspot ID`);\n hotspotIds.add(result.id);\n return result;\n }\n );\n return {\n id,\n title: optionalString(entry, \"title\"),\n source,\n initialView,\n hotspots,\n };\n } catch (cause) {\n if (cause instanceof PanoDataError && cause.sceneId) throw cause;\n const detail =\n cause instanceof Error ? cause.message : \"Invalid scene\";\n throw new PanoDataError(\n cause instanceof PanoDataError ? cause.code : \"INVALID_PROJECT\",\n `${field}.${detail}`,\n {\n sceneId: id,\n field: `${field}.${\n cause instanceof PanoDataError\n ? `source.viewerConfig.${cause.field ?? \"\"}`\n : detail.split(\":\")[0]\n }`,\n cause,\n }\n );\n }\n }\n );\n const initialSceneId =\n optionalString(value, \"initialSceneId\") ?? scenes[0]!.id;\n if (!ids.has(initialSceneId))\n throw new PanoDataError(\n \"INVALID_REFERENCE\",\n \"initialSceneId: scene does not exist\",\n { field: \"initialSceneId\" }\n );\n for (const [index, scene] of scenes.entries()) {\n for (const [i, hotspot] of (scene.hotspots ?? []).entries()) {\n if (hotspot.action && !ids.has(hotspot.action.sceneId))\n throw new PanoDataError(\n \"INVALID_REFERENCE\",\n \"Hotspot target scene does not exist\",\n {\n sceneId: scene.id,\n field: `scenes[${index}].hotspots[${i}].action.sceneId`,\n }\n );\n }\n }\n return {\n schemaVersion: 1,\n title: optionalString(value, \"title\"),\n initialSceneId,\n scenes,\n };\n } catch (cause) {\n if (cause instanceof PanoDataError) throw cause;\n const message = cause instanceof Error ? cause.message : \"Invalid project\";\n throw new PanoDataError(\"INVALID_PROJECT\", message, {\n cause,\n field: message.split(\":\")[0],\n });\n }\n}\n\nexport async function loadPanoProject(\n source: string | PanoProjectDefinition,\n options: LoadPanoProjectOptions = {}\n): Promise<LoadedPanoProject> {\n aborted(options.requestInit?.signal);\n let definition: PanoProjectDefinition;\n let baseUrl: string;\n if (typeof source === \"string\") {\n const response = await readJson(documentUrl(source), options);\n definition = parsePanoProject(response.value);\n baseUrl = options.baseUrl ?? new URL(\".\", response.url).href;\n } else {\n if (!options.baseUrl)\n throw new PanoDataError(\n \"INVALID_OPTIONS\",\n \"baseUrl is required for project object input\"\n );\n definition = parsePanoProject(source);\n baseUrl = options.baseUrl;\n }\n const root = directoryUrl(documentUrl(baseUrl));\n const controller = new AbortController();\n const signal = options.requestInit?.signal;\n const cancel = () => controller.abort();\n signal?.addEventListener(\"abort\", cancel, { once: true });\n const scenes: LoadedProjectScene[] = new Array(definition.scenes.length);\n let next = 0;\n let failure: PanoDataError | undefined;\n async function worker() {\n while (next < definition.scenes.length && !controller.signal.aborted) {\n const index = next++;\n const item = definition.scenes[index]!;\n try {\n const sourceBase =\n item.source.baseUrl === undefined\n ? undefined\n : resolveResource(root, item.source.baseUrl);\n const sceneOptions = {\n id: item.id,\n resolveAssetUrl: options.resolveAssetUrl,\n };\n const scene =\n item.source.viewerUrl !== undefined\n ? await loadSceneFromJson(\n resolveResource(root, item.source.viewerUrl),\n {\n ...sceneOptions,\n baseUrl: sourceBase,\n requestInit: {\n ...options.requestInit,\n signal: controller.signal,\n },\n }\n )\n : sceneFromViewerConfig(item.source.viewerConfig, {\n ...sceneOptions,\n baseUrl: sourceBase ?? root,\n });\n aborted(controller.signal);\n scenes[index] = {\n scene,\n title: item.title,\n initialView: item.initialView\n ? { yaw: 0, pitch: 0, fov: 75, ...item.initialView }\n : undefined,\n hotspots: item.hotspots!.map((h) =>\n resolveHotspotAssets(h, root, item.id, options.resolveAssetUrl)\n ),\n };\n } catch (cause) {\n if (!failure) {\n const error =\n cause instanceof PanoDataError\n ? cause\n : new PanoDataError(\n \"INVALID_CONFIG\",\n cause instanceof Error\n ? cause.message\n : \"Could not load scene\",\n { cause }\n );\n const field = `scenes[${index}].${\n error.field ??\n (item.source.viewerUrl !== undefined\n ? \"source.viewerUrl\"\n : \"source.viewerConfig\")\n }`;\n failure = new PanoDataError(\n error.code,\n `Scene ${item.id}: ${error.message}`,\n { status: error.status, sceneId: item.id, field, cause: error }\n );\n }\n controller.abort();\n }\n }\n }\n try {\n aborted(signal);\n await Promise.all(\n Array.from({ length: Math.min(4, scenes.length) }, worker)\n );\n aborted(signal);\n if (failure) throw failure;\n return {\n title: definition.title,\n initialSceneId: definition.initialSceneId!,\n scenes,\n };\n } finally {\n signal?.removeEventListener(\"abort\", cancel);\n }\n}\n"],"mappings":"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","names":["levels"]}
|
package/dist/data.d.mts
ADDED
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
|
|
3
|
+
type PanoDataErrorCode = "INVALID_OPTIONS" | "FETCH_FAILED" | "HTTP_ERROR" | "INVALID_JSON" | "INVALID_CONFIG" | "UNSUPPORTED_SCHEMA_VERSION" | "UNSUPPORTED_PROJECTION" | "INVALID_PROJECT" | "INVALID_REFERENCE" | "ABORTED";
|
|
4
|
+
declare class PanoDataError extends Error {
|
|
5
|
+
readonly code: PanoDataErrorCode;
|
|
6
|
+
readonly status?: number;
|
|
7
|
+
readonly sceneId?: string;
|
|
8
|
+
readonly field?: string;
|
|
9
|
+
readonly cause?: unknown;
|
|
10
|
+
constructor(code: PanoDataErrorCode, message: string, details?: {
|
|
11
|
+
status?: number;
|
|
12
|
+
sceneId?: string;
|
|
13
|
+
field?: string;
|
|
14
|
+
cause?: unknown;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The portable rendering contract shared by the converter and browser viewer. */
|
|
19
|
+
type ViewerCubeFace = "f" | "r" | "b" | "l" | "u" | "d";
|
|
20
|
+
type CubemapViewerConfig = {
|
|
21
|
+
type: "tile";
|
|
22
|
+
multires: {
|
|
23
|
+
tileSize: number;
|
|
24
|
+
levels: number[];
|
|
25
|
+
};
|
|
26
|
+
urlTemplate: string;
|
|
27
|
+
previewUrl: string;
|
|
28
|
+
previewFaceOrder: ViewerCubeFace[];
|
|
29
|
+
};
|
|
30
|
+
type SphereViewerConfig = {
|
|
31
|
+
type: "sphereTile";
|
|
32
|
+
multires: {
|
|
33
|
+
tileSize: number;
|
|
34
|
+
levels: {
|
|
35
|
+
width: number;
|
|
36
|
+
height: number;
|
|
37
|
+
}[];
|
|
38
|
+
};
|
|
39
|
+
urlTemplate: string;
|
|
40
|
+
previewUrl: string;
|
|
41
|
+
indexBase: 0 | 1;
|
|
42
|
+
};
|
|
43
|
+
type ViewerConfig = CubemapViewerConfig | SphereViewerConfig;
|
|
44
|
+
type ViewerDocument = ViewerConfig & {
|
|
45
|
+
schemaVersion: 1;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
type CubeFaceCode = "f" | "r" | "b" | "l" | "u" | "d";
|
|
49
|
+
type TileAddress = {
|
|
50
|
+
face: CubeFaceCode;
|
|
51
|
+
level: number;
|
|
52
|
+
row: number;
|
|
53
|
+
col: number;
|
|
54
|
+
faceSize: number;
|
|
55
|
+
tileSize: number;
|
|
56
|
+
width: number;
|
|
57
|
+
height: number;
|
|
58
|
+
};
|
|
59
|
+
type TileMultiresConfig = {
|
|
60
|
+
tileSize: number;
|
|
61
|
+
/** Ascending face sizes. The first value maps to l1. */
|
|
62
|
+
levels: number[];
|
|
63
|
+
};
|
|
64
|
+
type TileLoadProgress = {
|
|
65
|
+
requested: number;
|
|
66
|
+
loaded: number;
|
|
67
|
+
failed: number;
|
|
68
|
+
active: number;
|
|
69
|
+
queued: number;
|
|
70
|
+
};
|
|
71
|
+
type TileLoadError = {
|
|
72
|
+
address: TileAddress;
|
|
73
|
+
url: string;
|
|
74
|
+
error: unknown;
|
|
75
|
+
};
|
|
76
|
+
type TileProps = {
|
|
77
|
+
baseUrl: string;
|
|
78
|
+
/**
|
|
79
|
+
* Tile size followed by ascending cube-face sizes (`TILESIZE,LEVELSIZE1,...`).
|
|
80
|
+
* For krpano output, copy `image.cube.multires` from the XML.
|
|
81
|
+
*/
|
|
82
|
+
multires: string | TileMultiresConfig;
|
|
83
|
+
/**
|
|
84
|
+
* Preview atlas path. Relative paths resolve against `baseUrl`; root-absolute
|
|
85
|
+
* and `http(s)` / `blob:` / `data:` URLs are used as-is. For krpano output,
|
|
86
|
+
* copy `<preview url>` (often `preview.jpg` at the scene root). This package's
|
|
87
|
+
* common cube atlas path is `previews/cube-vertical.webp`.
|
|
88
|
+
*/
|
|
89
|
+
previewUrl: string;
|
|
90
|
+
/**
|
|
91
|
+
* Face order in the vertical preview atlas, from top to bottom. Defaults to
|
|
92
|
+
* `l/f/r/b/u/d`, matching krpano `preview.striporder` `LFRBUD`.
|
|
93
|
+
*/
|
|
94
|
+
previewFaceOrder?: readonly CubeFaceCode[];
|
|
95
|
+
/**
|
|
96
|
+
* Path relative to `baseUrl`. Defaults to
|
|
97
|
+
* `tiles/%s/l%l/%v/l%l_%s_%h_%v.webp`. For krpano output, copy `<cube url>`
|
|
98
|
+
* from the XML; krpano templates often use `%v_%h` instead of this default
|
|
99
|
+
* `%h_%v`, so omitting `urlTemplate` requests the wrong files. Supports
|
|
100
|
+
* krpano cube-tile `%s` and `%l` placeholders, horizontal `%h`/`%x`/`%u`/`%c`,
|
|
101
|
+
* vertical `%v`/`%y`/`%w`/`%r`, and index padding such as `%0h` or `%00v`.
|
|
102
|
+
*/
|
|
103
|
+
urlTemplate?: string;
|
|
104
|
+
/** Returns a relative path or absolute URL; takes precedence over `urlTemplate`. */
|
|
105
|
+
resolveTileUrl?: (address: TileAddress) => string;
|
|
106
|
+
maxTextureMemoryMb?: number;
|
|
107
|
+
maxConcurrentLoads?: number;
|
|
108
|
+
retryCount?: number;
|
|
109
|
+
/**
|
|
110
|
+
* `preview` loads only the preview atlas; `base` also preloads the visible
|
|
111
|
+
* lowest-resolution tiles before full-resolution loading begins.
|
|
112
|
+
*/
|
|
113
|
+
loadMode?: "full" | "preview" | "base";
|
|
114
|
+
/** Keeps the source mounted for preloading without drawing it. */
|
|
115
|
+
visible?: boolean;
|
|
116
|
+
/** Called when the preview atlas is ready for display. */
|
|
117
|
+
onReady?: () => void;
|
|
118
|
+
/** Called when the preview atlas cannot be loaded. */
|
|
119
|
+
onPreviewError?: (error: unknown) => void;
|
|
120
|
+
onLoadProgress?: (progress: TileLoadProgress) => void;
|
|
121
|
+
onTileError?: (event: TileLoadError) => void;
|
|
122
|
+
onLevelChange?: (level: number) => void;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
type SphereTileLevel = {
|
|
126
|
+
width: number;
|
|
127
|
+
height: number;
|
|
128
|
+
};
|
|
129
|
+
type SphereTileMultiresConfig = {
|
|
130
|
+
tileSize: number;
|
|
131
|
+
/** Ascending image dimensions. The first item maps to level 0. */
|
|
132
|
+
levels: SphereTileLevel[];
|
|
133
|
+
};
|
|
134
|
+
type SphereTileAddress = {
|
|
135
|
+
/** Zero-based logical level, column and row; URL indices add indexBase. */
|
|
136
|
+
level: number;
|
|
137
|
+
col: number;
|
|
138
|
+
row: number;
|
|
139
|
+
imageWidth: number;
|
|
140
|
+
imageHeight: number;
|
|
141
|
+
tileSize: number;
|
|
142
|
+
/** Actual tile dimensions, including partial edge tiles. */
|
|
143
|
+
width: number;
|
|
144
|
+
height: number;
|
|
145
|
+
};
|
|
146
|
+
type SphereTileLoadError = {
|
|
147
|
+
address: SphereTileAddress;
|
|
148
|
+
url: string;
|
|
149
|
+
error: unknown;
|
|
150
|
+
};
|
|
151
|
+
type SphereTileProps = {
|
|
152
|
+
baseUrl: string;
|
|
153
|
+
/** `512,500x250,1000x500,2000x1000` or explicit ascending dimensions. */
|
|
154
|
+
multires: string | SphereTileMultiresConfig;
|
|
155
|
+
/** A 2:1 equirectangular preview, resolved relative to baseUrl. */
|
|
156
|
+
previewUrl: string;
|
|
157
|
+
/** Defaults to `tiles/%l/%h_%v.webp`. No tile overlap. */
|
|
158
|
+
urlTemplate?: string;
|
|
159
|
+
/** URL indices start at 1 for krpano (default), or 0 for raw Sharp Deep Zoom. */
|
|
160
|
+
indexBase?: 0 | 1;
|
|
161
|
+
/** Takes precedence over urlTemplate and indexBase. Receives zero-based addresses. */
|
|
162
|
+
resolveTileUrl?: (address: SphereTileAddress) => string;
|
|
163
|
+
/** Horizontal source rotation in degrees. Defaults to 0. */
|
|
164
|
+
yawOffset?: number;
|
|
165
|
+
/** Tile cache budget in MiB. Defaults to 128. Preview memory is separate. */
|
|
166
|
+
maxTextureMemoryMb?: number;
|
|
167
|
+
/** Defaults to 4. */
|
|
168
|
+
maxConcurrentLoads?: number;
|
|
169
|
+
/** Retries after the initial attempt. Defaults to 1. */
|
|
170
|
+
retryCount?: number;
|
|
171
|
+
loadMode?: "full" | "preview" | "base";
|
|
172
|
+
visible?: boolean;
|
|
173
|
+
/** First paintable preview or tile is ready, even if the preview failed. */
|
|
174
|
+
onReady?: () => void;
|
|
175
|
+
onPreviewError?: (error: unknown) => void;
|
|
176
|
+
onLoadProgress?: (progress: TileLoadProgress) => void;
|
|
177
|
+
onTileError?: (event: SphereTileLoadError) => void;
|
|
178
|
+
/** Zero-based selected level. */
|
|
179
|
+
onLevelChange?: (level: number) => void;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
type TileScene = Omit<TileProps, "loadMode" | "visible" | "onReady" | "onPreviewError" | "onLoadProgress" | "onTileError" | "onLevelChange"> & {
|
|
183
|
+
id: string;
|
|
184
|
+
type: "tile";
|
|
185
|
+
};
|
|
186
|
+
type SphereTileScene = Omit<SphereTileProps, "loadMode" | "visible" | "onReady" | "onPreviewError" | "onLoadProgress" | "onTileError" | "onLevelChange"> & {
|
|
187
|
+
id: string;
|
|
188
|
+
type: "sphereTile";
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
type AssetUrlContext = {
|
|
192
|
+
defaultUrl: string;
|
|
193
|
+
kind: "tile" | "preview" | "hotspot";
|
|
194
|
+
sceneId: string;
|
|
195
|
+
hotspotId?: string;
|
|
196
|
+
};
|
|
197
|
+
type AssetUrlResolver = (path: string, context: AssetUrlContext) => string;
|
|
198
|
+
type JsonRequestOptions = {
|
|
199
|
+
requestInit?: Pick<RequestInit, "headers" | "credentials" | "signal">;
|
|
200
|
+
};
|
|
201
|
+
type SceneFromViewerConfigOptions = {
|
|
202
|
+
id: string;
|
|
203
|
+
baseUrl: string;
|
|
204
|
+
resolveAssetUrl?: AssetUrlResolver;
|
|
205
|
+
};
|
|
206
|
+
type LoadSceneFromJsonOptions = Omit<SceneFromViewerConfigOptions, "baseUrl"> & JsonRequestOptions & {
|
|
207
|
+
baseUrl?: string;
|
|
208
|
+
};
|
|
209
|
+
declare function sceneFromViewerConfig(value: unknown, options: SceneFromViewerConfigOptions): TileScene | SphereTileScene;
|
|
210
|
+
declare function loadSceneFromJson(url: string, options: LoadSceneFromJsonOptions): Promise<TileScene | SphereTileScene>;
|
|
211
|
+
|
|
212
|
+
type HotspotPosition = {
|
|
213
|
+
/** Horizontal panorama angle in degrees. Positive values look right. */
|
|
214
|
+
yaw: number;
|
|
215
|
+
/** Vertical panorama angle in degrees. Positive values look up. */
|
|
216
|
+
pitch: number;
|
|
217
|
+
};
|
|
218
|
+
/**
|
|
219
|
+
* A safe point-hotspot rendering mode.
|
|
220
|
+
*
|
|
221
|
+
* `surface` attaches the visual to the panorama shell. `billboard` floats it
|
|
222
|
+
* in front of the shell and keeps it facing the camera.
|
|
223
|
+
*/
|
|
224
|
+
type HotspotMode = "surface" | "billboard";
|
|
225
|
+
/** Whether a hotspot grows with panorama zoom or preserves its screen size. */
|
|
226
|
+
type HotspotScaleMode = "fov" | "fixed";
|
|
227
|
+
/** When a hotspot tooltip is shown. Defaults to `"always"`. */
|
|
228
|
+
type HotspotTooltipTrigger = "always" | "hover" | "click";
|
|
229
|
+
/**
|
|
230
|
+
* Pointer hit-testing for a hotspot. `"none"` ignores mouse, touch, and pen
|
|
231
|
+
* so events pass through to the panorama. Defaults to `"auto"`.
|
|
232
|
+
*/
|
|
233
|
+
type HotspotPointerEvents = "auto" | "none";
|
|
234
|
+
/** Where the tooltip sits relative to the hotspot. Defaults to `"top"`. */
|
|
235
|
+
type HotspotTooltipPlacement = "top" | "bottom" | "left" | "right";
|
|
236
|
+
/** Plain-text and/or image content for a hotspot tooltip. */
|
|
237
|
+
type HotspotTooltipContent = {
|
|
238
|
+
text?: string;
|
|
239
|
+
image?: string;
|
|
240
|
+
imageAlt?: string;
|
|
241
|
+
};
|
|
242
|
+
/** Visual styling for a hotspot tooltip bubble. */
|
|
243
|
+
type HotspotTooltipAppearance = {
|
|
244
|
+
background?: string;
|
|
245
|
+
color?: string;
|
|
246
|
+
border?: string;
|
|
247
|
+
borderRadius?: number | string;
|
|
248
|
+
shadow?: string;
|
|
249
|
+
padding?: number | string;
|
|
250
|
+
fontSize?: number | string;
|
|
251
|
+
fontFamily?: CSSProperties["fontFamily"];
|
|
252
|
+
/** Unitless line-height, or a CSS length. */
|
|
253
|
+
lineHeight?: CSSProperties["lineHeight"];
|
|
254
|
+
/** Numbers are CSS pixels. */
|
|
255
|
+
letterSpacing?: CSSProperties["letterSpacing"];
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
type PanoViewerState = {
|
|
259
|
+
/** Horizontal look angle in degrees. Positive values look right. */
|
|
260
|
+
yaw: number;
|
|
261
|
+
/** Vertical look angle in degrees. Positive values look up. */
|
|
262
|
+
pitch: number;
|
|
263
|
+
/** Vertical perspective field of view in degrees. */
|
|
264
|
+
fov: number;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
type GraphicPaint = {
|
|
268
|
+
fill?: string;
|
|
269
|
+
stroke?: string;
|
|
270
|
+
strokeWidth?: number;
|
|
271
|
+
};
|
|
272
|
+
type CircleGraphic = GraphicPaint & {
|
|
273
|
+
kind: "circle";
|
|
274
|
+
};
|
|
275
|
+
type TriangleGraphic = GraphicPaint & {
|
|
276
|
+
kind: "triangle";
|
|
277
|
+
};
|
|
278
|
+
type DiamondGraphic = GraphicPaint & {
|
|
279
|
+
kind: "diamond";
|
|
280
|
+
};
|
|
281
|
+
type StarGraphic = GraphicPaint & {
|
|
282
|
+
kind: "star";
|
|
283
|
+
};
|
|
284
|
+
type ArrowGraphic = GraphicPaint & {
|
|
285
|
+
kind: "arrow";
|
|
286
|
+
};
|
|
287
|
+
type RectangleGraphic = GraphicPaint & {
|
|
288
|
+
kind: "rectangle";
|
|
289
|
+
/** Relative radius from 0 (square corners) to 0.5 (maximum rounded corners). */
|
|
290
|
+
cornerRadius?: number;
|
|
291
|
+
};
|
|
292
|
+
type RingGraphic = GraphicPaint & {
|
|
293
|
+
kind: "ring";
|
|
294
|
+
innerRadius?: number;
|
|
295
|
+
};
|
|
296
|
+
type SvgGraphic = {
|
|
297
|
+
kind: "svg";
|
|
298
|
+
src: string;
|
|
299
|
+
};
|
|
300
|
+
type SvgPathGraphic = GraphicPaint & {
|
|
301
|
+
kind: "path";
|
|
302
|
+
path: string;
|
|
303
|
+
viewBox: [x: number, y: number, width: number, height: number];
|
|
304
|
+
};
|
|
305
|
+
type GraphicDefinition = CircleGraphic | TriangleGraphic | DiamondGraphic | StarGraphic | ArrowGraphic | RectangleGraphic | RingGraphic | SvgGraphic | SvgPathGraphic;
|
|
306
|
+
|
|
307
|
+
type IframePointerPolicy = "hotspot" | "content";
|
|
308
|
+
|
|
309
|
+
type TextHotspotAlign = "left" | "center" | "right";
|
|
310
|
+
type TextHotspotVerticalAlign = "top" | "middle" | "bottom";
|
|
311
|
+
type TextHotspotWhiteSpace = "normal" | "nowrap";
|
|
312
|
+
type TextHotspotFontStyle = "normal" | "italic";
|
|
313
|
+
/** Serializable typography and panel paint for a text hotspot. */
|
|
314
|
+
type TextHotspotStyle = {
|
|
315
|
+
fontFamily?: string;
|
|
316
|
+
/** Canvas pixels. Defaults to 96. */
|
|
317
|
+
fontSize?: number;
|
|
318
|
+
/** CSS font-weight. Defaults to 600. */
|
|
319
|
+
fontWeight?: number | string;
|
|
320
|
+
/** CSS font-style. Defaults to `"normal"`. */
|
|
321
|
+
fontStyle?: TextHotspotFontStyle;
|
|
322
|
+
color?: string;
|
|
323
|
+
/** CSS color. An empty string skips the panel fill. */
|
|
324
|
+
background?: string;
|
|
325
|
+
backgroundOpacity?: number;
|
|
326
|
+
/** Fraction of the texture's shorter side. */
|
|
327
|
+
padding?: number;
|
|
328
|
+
align?: TextHotspotAlign;
|
|
329
|
+
verticalAlign?: TextHotspotVerticalAlign;
|
|
330
|
+
lineHeight?: number;
|
|
331
|
+
whiteSpace?: TextHotspotWhiteSpace;
|
|
332
|
+
/** Fraction of the texture's shorter side, from 0 to 0.5. */
|
|
333
|
+
borderRadius?: number;
|
|
334
|
+
stroke?: string;
|
|
335
|
+
strokeWidth?: number;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
/** Shared serializable fields for every saved hotspot definition. */
|
|
339
|
+
type HotspotDefinitionBase = {
|
|
340
|
+
id: string;
|
|
341
|
+
/** Human-readable label; use it as the source for the rendered ariaLabel. */
|
|
342
|
+
label?: string;
|
|
343
|
+
visible?: boolean;
|
|
344
|
+
interactive?: boolean;
|
|
345
|
+
/** Pointer hit-testing. `"none"` ignores mouse, touch, and pen. */
|
|
346
|
+
pointerEvents?: HotspotPointerEvents;
|
|
347
|
+
/** Canvas cursor while this hotspot is hovered. */
|
|
348
|
+
cursor?: CSSProperties["cursor"];
|
|
349
|
+
renderOrder?: number;
|
|
350
|
+
tooltip?: string | HotspotTooltipContent;
|
|
351
|
+
tooltipTrigger?: HotspotTooltipTrigger;
|
|
352
|
+
tooltipPlacement?: HotspotTooltipPlacement;
|
|
353
|
+
tooltipOffset?: number;
|
|
354
|
+
tooltipAppearance?: HotspotTooltipAppearance;
|
|
355
|
+
};
|
|
356
|
+
/** Shared serializable fields for a hotspot anchored at one yaw/pitch point. */
|
|
357
|
+
type PointHotspotDefinitionBase = HotspotDefinitionBase & {
|
|
358
|
+
position: HotspotPosition;
|
|
359
|
+
width?: number;
|
|
360
|
+
height?: number;
|
|
361
|
+
scale?: number;
|
|
362
|
+
mode?: HotspotMode;
|
|
363
|
+
distance?: number;
|
|
364
|
+
scaleMode?: HotspotScaleMode;
|
|
365
|
+
referenceFov?: number;
|
|
366
|
+
rotation?: number;
|
|
367
|
+
opacity?: number;
|
|
368
|
+
};
|
|
369
|
+
type ImageHotspotDefinition = PointHotspotDefinitionBase & {
|
|
370
|
+
type: "image";
|
|
371
|
+
src: string;
|
|
372
|
+
};
|
|
373
|
+
type GraphicHotspotDefinition = PointHotspotDefinitionBase & {
|
|
374
|
+
type: "graphic";
|
|
375
|
+
graphic: GraphicDefinition;
|
|
376
|
+
};
|
|
377
|
+
type SequenceHotspotDefinition = PointHotspotDefinitionBase & {
|
|
378
|
+
type: "sequence";
|
|
379
|
+
src: string;
|
|
380
|
+
frameCount: number;
|
|
381
|
+
frameDirection?: "horizontal" | "vertical";
|
|
382
|
+
playing?: boolean;
|
|
383
|
+
fps?: number;
|
|
384
|
+
loop?: boolean;
|
|
385
|
+
};
|
|
386
|
+
type VideoHotspotDefinition = PointHotspotDefinitionBase & {
|
|
387
|
+
type: "video";
|
|
388
|
+
src: string;
|
|
389
|
+
poster?: string;
|
|
390
|
+
playing?: boolean;
|
|
391
|
+
loop?: boolean;
|
|
392
|
+
muted?: boolean;
|
|
393
|
+
volume?: number;
|
|
394
|
+
playsInline?: boolean;
|
|
395
|
+
preload?: "none" | "metadata" | "auto";
|
|
396
|
+
crossOrigin?: "" | "anonymous" | "use-credentials";
|
|
397
|
+
};
|
|
398
|
+
type AudioHotspotDefinition = PointHotspotDefinitionBase & {
|
|
399
|
+
type: "audio";
|
|
400
|
+
src: string | string[];
|
|
401
|
+
playing?: boolean;
|
|
402
|
+
loop?: boolean;
|
|
403
|
+
muted?: boolean;
|
|
404
|
+
volume?: number;
|
|
405
|
+
pauseWhenHidden?: boolean;
|
|
406
|
+
range?: number;
|
|
407
|
+
icon?: string;
|
|
408
|
+
playingIcon?: string;
|
|
409
|
+
marker?: boolean;
|
|
410
|
+
crossOrigin?: "" | "anonymous" | "use-credentials";
|
|
411
|
+
};
|
|
412
|
+
type TextHotspotDefinition = PointHotspotDefinitionBase & TextHotspotStyle & {
|
|
413
|
+
type: "text";
|
|
414
|
+
text: string;
|
|
415
|
+
};
|
|
416
|
+
type IframeHotspotDefinition = PointHotspotDefinitionBase & {
|
|
417
|
+
type: "iframe";
|
|
418
|
+
src: string;
|
|
419
|
+
title?: string;
|
|
420
|
+
sandbox?: string;
|
|
421
|
+
allow?: string;
|
|
422
|
+
referrerPolicy?: string;
|
|
423
|
+
loading?: "eager" | "lazy";
|
|
424
|
+
pointerPolicy?: IframePointerPolicy;
|
|
425
|
+
background?: string;
|
|
426
|
+
};
|
|
427
|
+
type PolygonHotspotDefinition = HotspotDefinitionBase & {
|
|
428
|
+
type: "polygon";
|
|
429
|
+
vertices: HotspotPosition[];
|
|
430
|
+
fill?: string;
|
|
431
|
+
fillOpacity?: number;
|
|
432
|
+
stroke?: string;
|
|
433
|
+
strokeWidth?: number;
|
|
434
|
+
strokeOpacity?: number;
|
|
435
|
+
strokeDashSize?: number;
|
|
436
|
+
strokeGapSize?: number;
|
|
437
|
+
};
|
|
438
|
+
/** An open path. This extends the original point and polygon hotspot categories. */
|
|
439
|
+
type PolylineHotspotDefinition = HotspotDefinitionBase & {
|
|
440
|
+
type: "polyline";
|
|
441
|
+
vertices: HotspotPosition[];
|
|
442
|
+
stroke?: string;
|
|
443
|
+
strokeWidth?: number;
|
|
444
|
+
strokeOpacity?: number;
|
|
445
|
+
strokeDashSize?: number;
|
|
446
|
+
strokeGapSize?: number;
|
|
447
|
+
};
|
|
448
|
+
type PointHotspotDefinition = ImageHotspotDefinition | GraphicHotspotDefinition | SequenceHotspotDefinition | VideoHotspotDefinition | AudioHotspotDefinition | TextHotspotDefinition | IframeHotspotDefinition;
|
|
449
|
+
/** A serializable, discriminated hotspot collection item. */
|
|
450
|
+
type HotspotDefinition = PointHotspotDefinition | PolygonHotspotDefinition | PolylineHotspotDefinition;
|
|
451
|
+
|
|
452
|
+
type ProjectHotspotDefinition = HotspotDefinition & {
|
|
453
|
+
action?: {
|
|
454
|
+
type: "scene";
|
|
455
|
+
sceneId: string;
|
|
456
|
+
};
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
type PanoProjectSceneDefinition = {
|
|
460
|
+
id: string;
|
|
461
|
+
title?: string;
|
|
462
|
+
source: ({
|
|
463
|
+
viewerUrl: string;
|
|
464
|
+
viewerConfig?: never;
|
|
465
|
+
} | {
|
|
466
|
+
viewerConfig: ViewerConfig;
|
|
467
|
+
viewerUrl?: never;
|
|
468
|
+
}) & {
|
|
469
|
+
baseUrl?: string;
|
|
470
|
+
};
|
|
471
|
+
initialView?: Partial<PanoViewerState>;
|
|
472
|
+
hotspots?: ProjectHotspotDefinition[];
|
|
473
|
+
};
|
|
474
|
+
type PanoProjectDefinition = {
|
|
475
|
+
schemaVersion: 1;
|
|
476
|
+
title?: string;
|
|
477
|
+
initialSceneId?: string;
|
|
478
|
+
scenes: PanoProjectSceneDefinition[];
|
|
479
|
+
};
|
|
480
|
+
type LoadedProjectScene = {
|
|
481
|
+
scene: TileScene | SphereTileScene;
|
|
482
|
+
title?: string;
|
|
483
|
+
initialView?: PanoViewerState;
|
|
484
|
+
hotspots: ProjectHotspotDefinition[];
|
|
485
|
+
};
|
|
486
|
+
type LoadedPanoProject = {
|
|
487
|
+
title?: string;
|
|
488
|
+
initialSceneId: string;
|
|
489
|
+
scenes: LoadedProjectScene[];
|
|
490
|
+
};
|
|
491
|
+
type LoadPanoProjectOptions = JsonRequestOptions & {
|
|
492
|
+
/** Directory used for project-relative references. Required for object input. */
|
|
493
|
+
baseUrl?: string;
|
|
494
|
+
resolveAssetUrl?: AssetUrlResolver;
|
|
495
|
+
};
|
|
496
|
+
declare function parsePanoProject(value: unknown): PanoProjectDefinition;
|
|
497
|
+
declare function loadPanoProject(source: string | PanoProjectDefinition, options?: LoadPanoProjectOptions): Promise<LoadedPanoProject>;
|
|
498
|
+
|
|
499
|
+
export { type AssetUrlContext, type AssetUrlResolver, type CubemapViewerConfig, type JsonRequestOptions, type LoadPanoProjectOptions, type LoadSceneFromJsonOptions, type LoadedPanoProject, type LoadedProjectScene, PanoDataError, type PanoDataErrorCode, type PanoProjectDefinition, type PanoProjectSceneDefinition, type ProjectHotspotDefinition, type SceneFromViewerConfigOptions, type SphereViewerConfig, type ViewerConfig, type ViewerDocument, loadPanoProject, loadSceneFromJson, parsePanoProject, sceneFromViewerConfig };
|