|
1 |
| -import { PushpinOutlined, ReloadOutlined } from "@ant-design/icons"; |
2 |
| -import { Space } from "antd"; |
3 |
| -import FastTooltip from "components/fast_tooltip"; |
4 |
| -import { V3 } from "libs/mjs"; |
5 |
| -import Toast from "libs/toast"; |
6 |
| -import { Vector3Input } from "libs/vector_input"; |
7 |
| -import message from "messages"; |
8 |
| -import type React from "react"; |
9 |
| -import { PureComponent } from "react"; |
10 |
| -import { connect } from "react-redux"; |
11 |
| -import type { APIDataset } from "types/api_types"; |
12 |
| -import type { Vector3, ViewMode } from "viewer/constants"; |
| 1 | +import { useWkSelector } from "libs/react_hooks"; |
13 | 2 | import constants from "viewer/constants";
|
14 |
| -import { getDatasetExtentInVoxel } from "viewer/model/accessors/dataset_accessor"; |
15 |
| -import { getPosition, getRotation } from "viewer/model/accessors/flycam_accessor"; |
16 |
| -import { setPositionAction, setRotationAction } from "viewer/model/actions/flycam_actions"; |
17 |
| -import type { Flycam, Task, WebknossosState } from "viewer/store"; |
18 |
| -import Store from "viewer/store"; |
19 |
| -import { ShareButton } from "viewer/view/action-bar/share_modal_view"; |
20 |
| -import ButtonComponent from "viewer/view/components/button_component"; |
21 |
| - |
22 |
| -type Props = { |
23 |
| - flycam: Flycam; |
24 |
| - viewMode: ViewMode; |
25 |
| - dataset: APIDataset; |
26 |
| - task: Task | null | undefined; |
27 |
| -}; |
28 |
| -const positionIconStyle: React.CSSProperties = { |
29 |
| - transform: "rotate(-45deg)", |
30 |
| - marginRight: 0, |
31 |
| -}; |
32 |
| -const warningColors: React.CSSProperties = { |
33 |
| - color: "rgb(255, 155, 85)", |
34 |
| - borderColor: "rgb(241, 122, 39)", |
35 |
| -}; |
36 |
| -const iconErrorStyle: React.CSSProperties = { ...warningColors }; |
37 |
| -const positionInputDefaultStyle: React.CSSProperties = { |
38 |
| - textAlign: "center", |
39 |
| -}; |
40 |
| -const positionInputErrorStyle: React.CSSProperties = { |
41 |
| - ...positionInputDefaultStyle, |
42 |
| - ...warningColors, |
43 |
| -}; |
44 |
| - |
45 |
| -class DatasetPositionView extends PureComponent<Props> { |
46 |
| - copyPositionToClipboard = async () => { |
47 |
| - const position = V3.floor(getPosition(this.props.flycam)).join(", "); |
48 |
| - await navigator.clipboard.writeText(position); |
49 |
| - Toast.success("Position copied to clipboard"); |
50 |
| - }; |
51 |
| - |
52 |
| - copyRotationToClipboard = async () => { |
53 |
| - const rotation = V3.round(getRotation(this.props.flycam)).join(", "); |
54 |
| - await navigator.clipboard.writeText(rotation); |
55 |
| - Toast.success("Rotation copied to clipboard"); |
56 |
| - }; |
57 |
| - |
58 |
| - handleChangePosition = (position: Vector3) => { |
59 |
| - Store.dispatch(setPositionAction(position)); |
60 |
| - }; |
61 |
| - |
62 |
| - handleChangeRotation = (rotation: Vector3) => { |
63 |
| - Store.dispatch(setRotationAction(rotation)); |
64 |
| - }; |
65 |
| - |
66 |
| - isPositionOutOfBounds = (position: Vector3) => { |
67 |
| - const { dataset, task } = this.props; |
68 |
| - const { min: datasetMin, max: datasetMax } = getDatasetExtentInVoxel(dataset); |
69 |
| - |
70 |
| - const isPositionOutOfBounds = (min: Vector3, max: Vector3) => |
71 |
| - position[0] < min[0] || |
72 |
| - position[1] < min[1] || |
73 |
| - position[2] < min[2] || |
74 |
| - position[0] >= max[0] || |
75 |
| - position[1] >= max[1] || |
76 |
| - position[2] >= max[2]; |
77 |
| - |
78 |
| - const isOutOfDatasetBounds = isPositionOutOfBounds(datasetMin, datasetMax); |
79 |
| - let isOutOfTaskBounds = false; |
80 |
| - |
81 |
| - if (task?.boundingBox) { |
82 |
| - const bbox = task.boundingBox; |
83 |
| - const bboxMax = [ |
84 |
| - bbox.topLeft[0] + bbox.width, |
85 |
| - bbox.topLeft[1] + bbox.height, |
86 |
| - bbox.topLeft[2] + bbox.depth, |
87 |
| - ]; |
88 |
| - // @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'number[]' is not assignable to p... Remove this comment to see the full error message |
89 |
| - isOutOfTaskBounds = isPositionOutOfBounds(bbox.topLeft, bboxMax); |
90 |
| - } |
91 |
| - |
92 |
| - return { |
93 |
| - isOutOfDatasetBounds, |
94 |
| - isOutOfTaskBounds, |
95 |
| - }; |
96 |
| - }; |
97 |
| - |
98 |
| - render() { |
99 |
| - const position = V3.floor(getPosition(this.props.flycam)); |
100 |
| - const { isOutOfDatasetBounds, isOutOfTaskBounds } = this.isPositionOutOfBounds(position); |
101 |
| - const iconColoringStyle = isOutOfDatasetBounds || isOutOfTaskBounds ? iconErrorStyle : {}; |
102 |
| - const positionInputStyle = |
103 |
| - isOutOfDatasetBounds || isOutOfTaskBounds |
104 |
| - ? positionInputErrorStyle |
105 |
| - : positionInputDefaultStyle; |
106 |
| - let maybeErrorMessage = null; |
107 |
| - |
108 |
| - if (isOutOfDatasetBounds) { |
109 |
| - maybeErrorMessage = message["tracing.out_of_dataset_bounds"]; |
110 |
| - } else if (!maybeErrorMessage && isOutOfTaskBounds) { |
111 |
| - maybeErrorMessage = message["tracing.out_of_task_bounds"]; |
112 |
| - } |
113 |
| - |
114 |
| - const rotation = V3.round(getRotation(this.props.flycam)); |
115 |
| - const isArbitraryMode = constants.MODES_ARBITRARY.includes(this.props.viewMode); |
116 |
| - const positionView = ( |
117 |
| - <div |
118 |
| - style={{ |
119 |
| - display: "flex", |
120 |
| - }} |
121 |
| - > |
122 |
| - <Space.Compact |
123 |
| - style={{ |
124 |
| - whiteSpace: "nowrap", |
125 |
| - }} |
126 |
| - > |
127 |
| - <FastTooltip title={message["tracing.copy_position"]} placement="bottom-start"> |
128 |
| - <ButtonComponent |
129 |
| - onClick={this.copyPositionToClipboard} |
130 |
| - style={{ padding: "0 10px", ...iconColoringStyle }} |
131 |
| - className="hide-on-small-screen" |
132 |
| - > |
133 |
| - <PushpinOutlined style={positionIconStyle} /> |
134 |
| - </ButtonComponent> |
135 |
| - </FastTooltip> |
136 |
| - <Vector3Input |
137 |
| - value={position} |
138 |
| - onChange={this.handleChangePosition} |
139 |
| - autoSize |
140 |
| - style={positionInputStyle} |
141 |
| - allowDecimals |
142 |
| - /> |
143 |
| - <ShareButton dataset={this.props.dataset} style={iconColoringStyle} /> |
144 |
| - </Space.Compact> |
145 |
| - {isArbitraryMode ? ( |
146 |
| - <Space.Compact |
147 |
| - style={{ |
148 |
| - whiteSpace: "nowrap", |
149 |
| - marginLeft: 10, |
150 |
| - }} |
151 |
| - > |
152 |
| - <FastTooltip title={message["tracing.copy_rotation"]} placement="bottom-start"> |
153 |
| - <ButtonComponent |
154 |
| - onClick={this.copyRotationToClipboard} |
155 |
| - style={{ |
156 |
| - padding: "0 10px", |
157 |
| - }} |
158 |
| - className="hide-on-small-screen" |
159 |
| - > |
160 |
| - <ReloadOutlined /> |
161 |
| - </ButtonComponent> |
162 |
| - </FastTooltip> |
163 |
| - <Vector3Input |
164 |
| - value={rotation} |
165 |
| - onChange={this.handleChangeRotation} |
166 |
| - style={{ |
167 |
| - textAlign: "center", |
168 |
| - width: 120, |
169 |
| - }} |
170 |
| - allowDecimals |
171 |
| - /> |
172 |
| - </Space.Compact> |
173 |
| - ) : null} |
174 |
| - </div> |
175 |
| - ); |
176 |
| - return ( |
177 |
| - <FastTooltip title={maybeErrorMessage || null} wrapper="div"> |
178 |
| - {positionView} |
179 |
| - </FastTooltip> |
180 |
| - ); |
181 |
| - } |
182 |
| -} |
183 |
| - |
184 |
| -function mapStateToProps(state: WebknossosState): Props { |
185 |
| - return { |
186 |
| - flycam: state.flycam, |
187 |
| - viewMode: state.temporaryConfiguration.viewMode, |
188 |
| - dataset: state.dataset, |
189 |
| - task: state.task, |
190 |
| - }; |
| 3 | +import PositionView from "./position_view"; |
| 4 | +import RotationView from "./rotation_view"; |
| 5 | + |
| 6 | +function DatasetPositionView() { |
| 7 | + const viewMode = useWkSelector((state) => state.temporaryConfiguration.viewMode); |
| 8 | + const isArbitraryMode = constants.MODES_ARBITRARY.includes(viewMode); |
| 9 | + |
| 10 | + return ( |
| 11 | + <div |
| 12 | + style={{ |
| 13 | + display: "flex", |
| 14 | + }} |
| 15 | + > |
| 16 | + <PositionView /> |
| 17 | + {isArbitraryMode ? <RotationView /> : null} |
| 18 | + </div> |
| 19 | + ); |
191 | 20 | }
|
192 | 21 |
|
193 |
| -const connector = connect(mapStateToProps); |
194 |
| -export default connector(DatasetPositionView); |
| 22 | +export default DatasetPositionView; |
0 commit comments