@mmmmzxe/react-360-view 1.0.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/LICENSE +21 -0
- package/README.md +154 -0
- package/dist/index.d.ts +379 -0
- package/dist/index.js +4716 -0
- package/dist/styles.css +5 -0
- package/package.json +85 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 maryemmostafa24
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# @mmmmzxe/react-360-viewer
|
|
2
|
+
|
|
3
|
+
A standalone, configurable 360° image viewer for React with drag rotation, zoom, hotspots, and auto-rotate support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
* Drag-to-rotate frame navigation
|
|
8
|
+
* Zoom with mouse wheel and toolbar controls
|
|
9
|
+
* Pan when zoomed
|
|
10
|
+
* Optional auto-rotate
|
|
11
|
+
* Interactive hotspots with tooltips
|
|
12
|
+
* Hotspot add mode
|
|
13
|
+
* TypeScript support
|
|
14
|
+
* Tailwind + shadcn compatible
|
|
15
|
+
* Headless hook support
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @mmmmzxe/react-360-viewer
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Peer Dependencies
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install react react-dom lucide-react
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Styles
|
|
30
|
+
|
|
31
|
+
Import the stylesheet once in your app (e.g. in your root layout or entry file):
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import '@mmmmzxe/react-360-viewer/styles.css';
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Styles are scoped to `[data-viewer-360]` via CSS `@scope` and will not override your app's global theme or Tailwind classes. Requires a **client component** in Next.js App Router (`'use client'`).
|
|
38
|
+
|
|
39
|
+
Wrap the viewer in a sized container if needed:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
<div className="w-full max-w-3xl">
|
|
43
|
+
<Viewer360 frames={frames} />
|
|
44
|
+
</div>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
If styles don't appear after updating, delete `.next` and restart the dev server.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
'use client';
|
|
55
|
+
|
|
56
|
+
import '@mmmmzxe/react-360-viewer/styles.css';
|
|
57
|
+
import { useState } from "react";
|
|
58
|
+
import {
|
|
59
|
+
Viewer360,
|
|
60
|
+
type Viewer360Frame,
|
|
61
|
+
} from "@mmmmzxe/react-360-viewer";
|
|
62
|
+
|
|
63
|
+
const frames: Viewer360Frame[] = [
|
|
64
|
+
{ id: "1", src: "/images/frame-01.jpg", label: "Front" },
|
|
65
|
+
{ id: "2", src: "/images/frame-02.jpg", label: "Side" },
|
|
66
|
+
{ id: "3", src: "/images/frame-03.jpg", label: "Rear" },
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
export default function ProductViewer() {
|
|
70
|
+
const [frameIndex, setFrameIndex] = useState(0);
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<Viewer360
|
|
74
|
+
frames={frames}
|
|
75
|
+
currentFrameIndex={frameIndex}
|
|
76
|
+
onFrameChange={setFrameIndex}
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Hotspots
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
<Viewer360
|
|
86
|
+
frames={frames}
|
|
87
|
+
hotspots={[
|
|
88
|
+
{
|
|
89
|
+
id: "1",
|
|
90
|
+
frameIndex: 0,
|
|
91
|
+
positionX: 50,
|
|
92
|
+
positionY: 40,
|
|
93
|
+
data: {
|
|
94
|
+
title: "Scratch",
|
|
95
|
+
description: "Front bumper",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
]}
|
|
99
|
+
/>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Add Hotspots
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<Viewer360
|
|
106
|
+
frames={frames}
|
|
107
|
+
hotspots={hotspots}
|
|
108
|
+
showHotspotModeControl
|
|
109
|
+
onHotspotAdd={(position) => {
|
|
110
|
+
console.log(position);
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Configuration
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
<Viewer360
|
|
119
|
+
config={{
|
|
120
|
+
minZoom: 1,
|
|
121
|
+
maxZoom: 4,
|
|
122
|
+
zoomStep: 0.2,
|
|
123
|
+
dragSensitivity: 8,
|
|
124
|
+
autoRotate: true,
|
|
125
|
+
autoRotateIntervalMs: 150,
|
|
126
|
+
}}
|
|
127
|
+
/>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Main Props
|
|
131
|
+
|
|
132
|
+
| Prop | Type | Description |
|
|
133
|
+
| ---------------------- | ------------------ | ------------------------- |
|
|
134
|
+
| frames | Viewer360Frame[] | Required image frames |
|
|
135
|
+
| hotspots | Viewer360Hotspot[] | Hotspots to display |
|
|
136
|
+
| currentFrameIndex | number | Controlled frame |
|
|
137
|
+
| onFrameChange | function | Frame change callback |
|
|
138
|
+
| config | Viewer360Config | Viewer settings |
|
|
139
|
+
| showFrameIndicator | boolean | Show frame counter |
|
|
140
|
+
| showHotspotModeControl | boolean | Enable add hotspot button |
|
|
141
|
+
| onHotspotAdd | function | Add hotspot callback |
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npm install
|
|
147
|
+
npm run build
|
|
148
|
+
npm run dev
|
|
149
|
+
npm run test-run
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import * as React$1 from 'react';
|
|
2
|
+
import { ReactNode, MouseEvent, CSSProperties, JSX, RefObject, PointerEvent, WheelEvent } from 'react';
|
|
3
|
+
import { ClassValue } from 'clsx';
|
|
4
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
5
|
+
import { VariantProps } from 'class-variance-authority';
|
|
6
|
+
|
|
7
|
+
declare const defaultViewer360Config: {
|
|
8
|
+
minZoom: number;
|
|
9
|
+
maxZoom: number;
|
|
10
|
+
zoomStep: number;
|
|
11
|
+
dragSensitivity: number;
|
|
12
|
+
autoRotate: boolean;
|
|
13
|
+
autoRotateIntervalMs: number;
|
|
14
|
+
autoRotateDirection: "forward";
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type Viewer360Frame = {
|
|
18
|
+
id: string;
|
|
19
|
+
src: string;
|
|
20
|
+
label?: string;
|
|
21
|
+
};
|
|
22
|
+
type Viewer360PanOffset = {
|
|
23
|
+
panX: number;
|
|
24
|
+
panY: number;
|
|
25
|
+
};
|
|
26
|
+
type Viewer360Config = {
|
|
27
|
+
minZoom?: number;
|
|
28
|
+
maxZoom?: number;
|
|
29
|
+
zoomStep?: number;
|
|
30
|
+
dragSensitivity?: number;
|
|
31
|
+
autoRotate?: boolean;
|
|
32
|
+
autoRotateIntervalMs?: number;
|
|
33
|
+
autoRotateDirection?: 'forward' | 'backward';
|
|
34
|
+
};
|
|
35
|
+
type Viewer360Hotspot<TData = unknown> = {
|
|
36
|
+
id: string;
|
|
37
|
+
frameIndex: number;
|
|
38
|
+
positionX: number;
|
|
39
|
+
positionY: number;
|
|
40
|
+
data?: TData;
|
|
41
|
+
};
|
|
42
|
+
type Viewer360HotspotPosition = {
|
|
43
|
+
frameIndex: number;
|
|
44
|
+
frameId: string;
|
|
45
|
+
positionX: number;
|
|
46
|
+
positionY: number;
|
|
47
|
+
};
|
|
48
|
+
type Viewer360HotspotRenderProps<TData = unknown> = {
|
|
49
|
+
hotspot: Viewer360Hotspot<TData>;
|
|
50
|
+
leftPercent: number;
|
|
51
|
+
topPercent: number;
|
|
52
|
+
};
|
|
53
|
+
type Viewer360OverlayRenderProps = {
|
|
54
|
+
currentFrameIndex: number;
|
|
55
|
+
frameCount: number;
|
|
56
|
+
frameLabel?: string;
|
|
57
|
+
isHotspotMode: boolean;
|
|
58
|
+
labels: Required<Viewer360Labels>;
|
|
59
|
+
frameIndicatorClassName: string;
|
|
60
|
+
};
|
|
61
|
+
type Viewer360ToolbarRenderProps = {
|
|
62
|
+
zoom: number;
|
|
63
|
+
minZoom: number;
|
|
64
|
+
maxZoom: number;
|
|
65
|
+
isResetDisabled: boolean;
|
|
66
|
+
isHotspotMode: boolean;
|
|
67
|
+
showHotspotModeControl: boolean;
|
|
68
|
+
showZoomControls: boolean;
|
|
69
|
+
showResetControl: boolean;
|
|
70
|
+
showDragHint: boolean;
|
|
71
|
+
labels: Required<Viewer360Labels>;
|
|
72
|
+
onZoomIn: () => void;
|
|
73
|
+
onZoomOut: () => void;
|
|
74
|
+
onResetView: () => void;
|
|
75
|
+
onHotspotModeChange: (active: boolean) => void;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
type Viewer360Marker = {
|
|
79
|
+
id: string;
|
|
80
|
+
title: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
};
|
|
83
|
+
type Viewer360MarkerPinClassNames = {
|
|
84
|
+
root?: string;
|
|
85
|
+
ping?: string;
|
|
86
|
+
dot?: string;
|
|
87
|
+
tooltip?: string;
|
|
88
|
+
tooltipHeader?: string;
|
|
89
|
+
tooltipBody?: string;
|
|
90
|
+
tooltipTitle?: string;
|
|
91
|
+
tooltipDescription?: string;
|
|
92
|
+
deleteButton?: string;
|
|
93
|
+
};
|
|
94
|
+
type Viewer360MarkerPinLabels = {
|
|
95
|
+
delete?: string;
|
|
96
|
+
};
|
|
97
|
+
type Viewer360MarkerPinRenderProps<TData = unknown> = {
|
|
98
|
+
marker: Viewer360Marker;
|
|
99
|
+
hotspot?: Viewer360Hotspot<TData>;
|
|
100
|
+
};
|
|
101
|
+
type Viewer360MarkerPinProps<TData = unknown> = {
|
|
102
|
+
marker: Viewer360Marker;
|
|
103
|
+
hotspot?: Viewer360Hotspot<TData>;
|
|
104
|
+
leftPercent: number;
|
|
105
|
+
topPercent: number;
|
|
106
|
+
onDelete?: (id: string) => void;
|
|
107
|
+
isDeletePending?: boolean;
|
|
108
|
+
onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
|
|
109
|
+
renderTag?: (props: Viewer360MarkerPinRenderProps<TData>) => ReactNode;
|
|
110
|
+
classNames?: Viewer360MarkerPinClassNames;
|
|
111
|
+
labels?: Viewer360MarkerPinLabels;
|
|
112
|
+
};
|
|
113
|
+
type Viewer360HotspotPinOptions<TData = unknown> = {
|
|
114
|
+
onDelete?: (id: string) => void;
|
|
115
|
+
deletingMarkerId?: string | null;
|
|
116
|
+
getMarker?: (hotspot: Viewer360Hotspot<TData>) => Viewer360Marker;
|
|
117
|
+
renderTag?: (props: Viewer360MarkerPinRenderProps<TData>) => ReactNode;
|
|
118
|
+
classNames?: Viewer360MarkerPinClassNames;
|
|
119
|
+
labels?: Viewer360MarkerPinLabels;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
type Viewer360ClassNames = {
|
|
123
|
+
root?: string;
|
|
124
|
+
viewport?: string;
|
|
125
|
+
canvas?: string;
|
|
126
|
+
overlay?: string;
|
|
127
|
+
loading?: string;
|
|
128
|
+
loadingText?: string;
|
|
129
|
+
frameIndicator?: string;
|
|
130
|
+
hotspotModeBanner?: string;
|
|
131
|
+
toolbar?: string;
|
|
132
|
+
dragHint?: string;
|
|
133
|
+
controls?: string;
|
|
134
|
+
controlButton?: string;
|
|
135
|
+
controlButtonActive?: string;
|
|
136
|
+
controlButtonDisabled?: string;
|
|
137
|
+
zoomDisplay?: string;
|
|
138
|
+
divider?: string;
|
|
139
|
+
};
|
|
140
|
+
type Viewer360Labels = {
|
|
141
|
+
loading?: string;
|
|
142
|
+
dragHint?: string;
|
|
143
|
+
frameIndicator?: (params: {
|
|
144
|
+
current: number;
|
|
145
|
+
total: number;
|
|
146
|
+
label?: string;
|
|
147
|
+
}) => string;
|
|
148
|
+
zoom?: (percent: number) => string;
|
|
149
|
+
hotspotModeActive?: string;
|
|
150
|
+
addHotspot?: string;
|
|
151
|
+
zoomIn?: string;
|
|
152
|
+
zoomOut?: string;
|
|
153
|
+
resetView?: string;
|
|
154
|
+
deleteMarker?: string;
|
|
155
|
+
};
|
|
156
|
+
type Viewer360Theme = {
|
|
157
|
+
'--viewer-bg'?: string;
|
|
158
|
+
'--viewer-border'?: string;
|
|
159
|
+
'--viewer-text'?: string;
|
|
160
|
+
'--viewer-muted'?: string;
|
|
161
|
+
'--viewer-accent'?: string;
|
|
162
|
+
'--viewer-accent-foreground'?: string;
|
|
163
|
+
'--viewer-control-bg'?: string;
|
|
164
|
+
'--viewer-control-border'?: string;
|
|
165
|
+
'--viewer-hotspot-banner-bg'?: string;
|
|
166
|
+
'--viewer-hotspot-banner-border'?: string;
|
|
167
|
+
'--viewer-hotspot-banner-text'?: string;
|
|
168
|
+
};
|
|
169
|
+
type Viewer360Props<TData = unknown> = {
|
|
170
|
+
frames: Viewer360Frame[];
|
|
171
|
+
currentFrameIndex?: number;
|
|
172
|
+
defaultFrameIndex?: number;
|
|
173
|
+
onFrameChange?: (index: number) => void;
|
|
174
|
+
config?: Viewer360Config;
|
|
175
|
+
className?: string;
|
|
176
|
+
classNames?: Viewer360ClassNames;
|
|
177
|
+
style?: CSSProperties;
|
|
178
|
+
theme?: Viewer360Theme;
|
|
179
|
+
labels?: Viewer360Labels;
|
|
180
|
+
aspectRatio?: string;
|
|
181
|
+
showZoomControls?: boolean;
|
|
182
|
+
showResetControl?: boolean;
|
|
183
|
+
showFrameIndicator?: boolean;
|
|
184
|
+
showDragHint?: boolean;
|
|
185
|
+
showHotspotModeControl?: boolean;
|
|
186
|
+
hotspotPin?: Viewer360HotspotPinOptions<TData>;
|
|
187
|
+
hotspots?: Viewer360Hotspot<TData>[];
|
|
188
|
+
renderHotspot?: (props: Viewer360HotspotRenderProps<TData>) => ReactNode;
|
|
189
|
+
renderLoading?: () => ReactNode;
|
|
190
|
+
renderFrameIndicator?: (props: Viewer360OverlayRenderProps) => ReactNode;
|
|
191
|
+
renderHotspotModeBanner?: (props: Pick<Viewer360OverlayRenderProps, 'labels'>) => ReactNode;
|
|
192
|
+
renderToolbar?: (props: Viewer360ToolbarRenderProps) => ReactNode;
|
|
193
|
+
onHotspotClick?: (hotspot: Viewer360Hotspot<TData>, event: MouseEvent<HTMLDivElement>) => void;
|
|
194
|
+
hotspotMode?: boolean;
|
|
195
|
+
defaultHotspotMode?: boolean;
|
|
196
|
+
onHotspotModeChange?: (active: boolean) => void;
|
|
197
|
+
onHotspotAdd?: (position: Viewer360HotspotPosition) => void;
|
|
198
|
+
children?: ReactNode;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
declare const defaultViewer360Labels: Required<Viewer360Labels>;
|
|
202
|
+
|
|
203
|
+
declare const defaultViewer360MarkerPinLabels: {
|
|
204
|
+
readonly delete: "Remove marker";
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
declare const viewer360ClassNames: Required<Viewer360ClassNames>;
|
|
208
|
+
declare const viewer360MarkerPinClassNames: Required<Viewer360MarkerPinClassNames>;
|
|
209
|
+
/** @deprecated Use `viewer360ClassNames` */
|
|
210
|
+
declare const defaultViewer360ClassNames: Required<Viewer360ClassNames>;
|
|
211
|
+
/** @deprecated Use `viewer360MarkerPinClassNames` */
|
|
212
|
+
declare const defaultViewer360MarkerPinClassNames: Required<Viewer360MarkerPinClassNames>;
|
|
213
|
+
|
|
214
|
+
declare function Viewer360<TData = unknown>({ frames, currentFrameIndex: controlledFrameIndex, defaultFrameIndex, onFrameChange, config, className, classNames, style, theme, labels, aspectRatio, showZoomControls, showResetControl, showFrameIndicator, showDragHint, showHotspotModeControl, hotspotPin, hotspots, renderHotspot, renderLoading, renderFrameIndicator, renderHotspotModeBanner, renderToolbar, onHotspotClick, hotspotMode: controlledHotspotMode, defaultHotspotMode, onHotspotModeChange, onHotspotAdd, children, }: Viewer360Props<TData>): JSX.Element;
|
|
215
|
+
|
|
216
|
+
type Viewer360AddModeBannerProps = {
|
|
217
|
+
className?: string;
|
|
218
|
+
label: string;
|
|
219
|
+
};
|
|
220
|
+
declare function Viewer360AddModeBanner({ className, label }: Viewer360AddModeBannerProps): JSX.Element;
|
|
221
|
+
|
|
222
|
+
type Viewer360FrameIndicatorProps = {
|
|
223
|
+
className?: string;
|
|
224
|
+
label: string;
|
|
225
|
+
};
|
|
226
|
+
declare function Viewer360FrameIndicator({ className, label }: Viewer360FrameIndicatorProps): JSX.Element;
|
|
227
|
+
|
|
228
|
+
type Viewer360LoadingOverlayProps = {
|
|
229
|
+
className?: string;
|
|
230
|
+
textClassName?: string;
|
|
231
|
+
label: string;
|
|
232
|
+
};
|
|
233
|
+
declare function Viewer360LoadingOverlay({ className, textClassName, label }: Viewer360LoadingOverlayProps): JSX.Element;
|
|
234
|
+
|
|
235
|
+
declare function Viewer360MarkerPin<TData = unknown>({ marker, hotspot, leftPercent, topPercent, onDelete, isDeletePending, onClick, renderTag, classNames, labels, }: Viewer360MarkerPinProps<TData>): JSX.Element;
|
|
236
|
+
|
|
237
|
+
type Viewer360ToolbarProps = Viewer360ToolbarRenderProps;
|
|
238
|
+
declare function Viewer360Toolbar({ showDragHint, showHotspotModeControl, showZoomControls, showResetControl, labels, isHotspotMode, zoom, minZoom, maxZoom, isResetDisabled, onHotspotModeChange, onZoomIn, onZoomOut, onResetView, }: Viewer360ToolbarProps): JSX.Element;
|
|
239
|
+
|
|
240
|
+
type ViewerImageLayout = {
|
|
241
|
+
width: number;
|
|
242
|
+
height: number;
|
|
243
|
+
centerX: number;
|
|
244
|
+
centerY: number;
|
|
245
|
+
drawWidth: number;
|
|
246
|
+
drawHeight: number;
|
|
247
|
+
offsetX: number;
|
|
248
|
+
offsetY: number;
|
|
249
|
+
};
|
|
250
|
+
type PanOffset = {
|
|
251
|
+
panX: number;
|
|
252
|
+
panY: number;
|
|
253
|
+
};
|
|
254
|
+
type ComputeViewerImageLayoutParams = {
|
|
255
|
+
containerWidth: number;
|
|
256
|
+
containerHeight: number;
|
|
257
|
+
imageWidth: number;
|
|
258
|
+
imageHeight: number;
|
|
259
|
+
pan?: PanOffset;
|
|
260
|
+
};
|
|
261
|
+
declare function computeViewerImageLayout({ containerWidth, containerHeight, imageWidth, imageHeight, pan, }: ComputeViewerImageLayoutParams): ViewerImageLayout;
|
|
262
|
+
declare function computeHotspotScreenPosition(hotspotX: number, hotspotY: number, layout: ViewerImageLayout, zoom: number): {
|
|
263
|
+
leftPercent: number;
|
|
264
|
+
topPercent: number;
|
|
265
|
+
};
|
|
266
|
+
declare function computeHotspotPositionFromClick(clientX: number, clientY: number, containerRect: DOMRect, layout: ViewerImageLayout, zoom: number): {
|
|
267
|
+
positionX: number;
|
|
268
|
+
positionY: number;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
type UseViewer360Params<TData> = {
|
|
272
|
+
frames: Viewer360Frame[];
|
|
273
|
+
currentFrameIndex: number;
|
|
274
|
+
onFrameChange: (index: number) => void;
|
|
275
|
+
hotspots?: Viewer360Hotspot<TData>[];
|
|
276
|
+
config?: Viewer360Config;
|
|
277
|
+
hotspotMode?: boolean;
|
|
278
|
+
onHotspotAdd?: (position: Viewer360HotspotPosition) => void;
|
|
279
|
+
};
|
|
280
|
+
type UseViewer360Return<TData> = {
|
|
281
|
+
canvasRef: RefObject<HTMLCanvasElement | null>;
|
|
282
|
+
containerRef: RefObject<HTMLDivElement | null>;
|
|
283
|
+
currentFrame: Viewer360Frame | undefined;
|
|
284
|
+
currentFrameHotspots: Viewer360Hotspot<TData>[];
|
|
285
|
+
imagesLoaded: boolean;
|
|
286
|
+
isHotspotMode: boolean;
|
|
287
|
+
isResetDisabled: boolean;
|
|
288
|
+
maxZoom: number;
|
|
289
|
+
minZoom: number;
|
|
290
|
+
viewerCursorClass: string;
|
|
291
|
+
zoom: number;
|
|
292
|
+
getCurrentImageLayout: () => ViewerImageLayout | null;
|
|
293
|
+
getHotspotScreenPosition: (hotspot: Viewer360Hotspot<TData>) => {
|
|
294
|
+
leftPercent: number;
|
|
295
|
+
topPercent: number;
|
|
296
|
+
};
|
|
297
|
+
handleCanvasClick: (event: React.MouseEvent<HTMLDivElement>) => void;
|
|
298
|
+
handlePointerDown: (event: PointerEvent<HTMLDivElement>) => void;
|
|
299
|
+
handlePointerMove: (event: PointerEvent<HTMLDivElement>) => void;
|
|
300
|
+
handlePointerUp: (event: PointerEvent<HTMLDivElement>) => void;
|
|
301
|
+
handleResetView: () => void;
|
|
302
|
+
handleWheel: (event: WheelEvent<HTMLDivElement>) => void;
|
|
303
|
+
handleZoomIn: () => void;
|
|
304
|
+
handleZoomOut: () => void;
|
|
305
|
+
};
|
|
306
|
+
declare function useViewer360<TData = unknown>({ frames, hotspots, currentFrameIndex, onFrameChange, config, hotspotMode: hotspotModeProp, onHotspotAdd, }: UseViewer360Params<TData>): UseViewer360Return<TData>;
|
|
307
|
+
|
|
308
|
+
type ResolvedViewer360Config = Required<Viewer360Config>;
|
|
309
|
+
declare function resolveViewer360Config(config?: Viewer360Config): ResolvedViewer360Config;
|
|
310
|
+
declare function clampZoom(zoom: number, config: ResolvedViewer360Config): number;
|
|
311
|
+
declare function applyWheelZoom(currentZoom: number, deltaY: number, currentPan: PanOffset, config: ResolvedViewer360Config): {
|
|
312
|
+
zoom: number;
|
|
313
|
+
pan: PanOffset;
|
|
314
|
+
};
|
|
315
|
+
declare function stepZoomIn(currentZoom: number, config: ResolvedViewer360Config): number;
|
|
316
|
+
declare function stepZoomOut(currentZoom: number, currentPan: PanOffset, config: ResolvedViewer360Config): {
|
|
317
|
+
zoom: number;
|
|
318
|
+
pan: PanOffset;
|
|
319
|
+
};
|
|
320
|
+
declare function isResetDisabled(zoom: number, pan: PanOffset, config: ResolvedViewer360Config): boolean;
|
|
321
|
+
declare function getViewerCursorClass(isHotspotMode: boolean, zoom: number, isDragging: boolean, minZoom: number): string;
|
|
322
|
+
|
|
323
|
+
declare function clampFrameIndex(index: number, frameCount: number): number;
|
|
324
|
+
type DragStart = {
|
|
325
|
+
pointerX: number;
|
|
326
|
+
frameIndex: number;
|
|
327
|
+
};
|
|
328
|
+
declare function computeDragFrameIndex(dragStart: DragStart, clientX: number, frameCount: number, dragSensitivity: number): number | null;
|
|
329
|
+
|
|
330
|
+
type PanStart = {
|
|
331
|
+
pointerX: number;
|
|
332
|
+
pointerY: number;
|
|
333
|
+
panX: number;
|
|
334
|
+
panY: number;
|
|
335
|
+
};
|
|
336
|
+
declare function computeViewerPanOffset(panStart: PanStart, clientX: number, clientY: number): PanOffset;
|
|
337
|
+
|
|
338
|
+
declare function hotspotToViewer360Marker<TData>(hotspot: Viewer360Hotspot<TData>): Viewer360Marker;
|
|
339
|
+
declare function toViewer360Hotspots<TData extends Viewer360Marker>(markers: Array<Viewer360Marker & {
|
|
340
|
+
frameIndex: number;
|
|
341
|
+
positionX: number;
|
|
342
|
+
positionY: number;
|
|
343
|
+
}>, mapData?: (marker: Viewer360Marker & {
|
|
344
|
+
frameIndex: number;
|
|
345
|
+
positionX: number;
|
|
346
|
+
positionY: number;
|
|
347
|
+
}) => TData): Viewer360Hotspot<TData>[];
|
|
348
|
+
|
|
349
|
+
type DrawFrameOnCanvasParams = {
|
|
350
|
+
canvas: HTMLCanvasElement;
|
|
351
|
+
container: HTMLDivElement;
|
|
352
|
+
image: HTMLImageElement;
|
|
353
|
+
zoom: number;
|
|
354
|
+
pan: PanOffset;
|
|
355
|
+
};
|
|
356
|
+
declare function drawFrameOnCanvas({ canvas, container, image, zoom, pan }: DrawFrameOnCanvasParams): void;
|
|
357
|
+
declare function getFramesSignature(frames: Viewer360Frame[]): string;
|
|
358
|
+
declare function preloadFrameImage(frame: Viewer360Frame): Promise<HTMLImageElement>;
|
|
359
|
+
declare function preloadViewerFrames(frames: Viewer360Frame[]): Promise<HTMLImageElement[]>;
|
|
360
|
+
declare function hasLoadedViewerFrame(images: HTMLImageElement[]): boolean;
|
|
361
|
+
declare function filterHotspotsByFrame<TData>(hotspots: Array<{
|
|
362
|
+
frameIndex: number;
|
|
363
|
+
data?: TData;
|
|
364
|
+
}>, frameIndex: number): Array<{
|
|
365
|
+
frameIndex: number;
|
|
366
|
+
data?: TData;
|
|
367
|
+
}>;
|
|
368
|
+
|
|
369
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
370
|
+
|
|
371
|
+
declare const buttonVariants: (props?: ({
|
|
372
|
+
variant?: "default" | "link" | "secondary" | "destructive" | "outline" | "ghost" | null | undefined;
|
|
373
|
+
size?: "default" | "icon" | "sm" | "xs" | "lg" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
|
|
374
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
375
|
+
declare function Button({ className, variant, size, asChild, ...props }: React$1.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
|
|
376
|
+
asChild?: boolean;
|
|
377
|
+
}): JSX.Element;
|
|
378
|
+
|
|
379
|
+
export { Button, Viewer360, Viewer360AddModeBanner, type Viewer360ClassNames, type Viewer360Config, type Viewer360Frame, Viewer360FrameIndicator, type Viewer360Hotspot, type Viewer360HotspotPinOptions, type Viewer360HotspotPosition, type Viewer360HotspotRenderProps, type Viewer360Labels, Viewer360LoadingOverlay, type Viewer360Marker, Viewer360MarkerPin, type Viewer360MarkerPinClassNames, type Viewer360MarkerPinLabels, type Viewer360MarkerPinProps, type Viewer360MarkerPinRenderProps, type Viewer360OverlayRenderProps, type Viewer360PanOffset, type Viewer360Props, type Viewer360Theme, Viewer360Toolbar, type Viewer360ToolbarRenderProps, type ViewerImageLayout, applyWheelZoom, buttonVariants, clampFrameIndex, clampZoom, cn, computeDragFrameIndex, computeHotspotPositionFromClick, computeHotspotScreenPosition, computeViewerImageLayout, computeViewerPanOffset, defaultViewer360ClassNames, defaultViewer360Config, defaultViewer360Labels, defaultViewer360MarkerPinClassNames, defaultViewer360MarkerPinLabels, drawFrameOnCanvas, filterHotspotsByFrame, getFramesSignature, getViewerCursorClass, hasLoadedViewerFrame, hotspotToViewer360Marker, isResetDisabled, preloadFrameImage, preloadViewerFrames, resolveViewer360Config, stepZoomIn, stepZoomOut, toViewer360Hotspots, useViewer360, viewer360ClassNames, viewer360MarkerPinClassNames };
|