@realsee/dnalogel 0.1.7 → 2.0.0-alpha.11

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.
Files changed (731) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +24 -68
  3. package/{plugins → dist}/CSS3DRenderPlugin/index.d.ts +1 -1
  4. package/dist/CSS3DRenderPlugin/index.js +231 -0
  5. package/dist/CSS3DRenderPlugin/utils/createResizeObserver.d.ts +7 -0
  6. package/{plugins → dist}/CameraMovementPlugin/index.d.ts +0 -0
  7. package/dist/CameraMovementPlugin/index.js +302 -0
  8. package/{plugins → dist}/CameraMovementPlugin/typing.d.ts +0 -0
  9. package/{plugins → dist}/ModelChassisCompassPlugin/index.d.ts +1 -1
  10. package/dist/ModelChassisCompassPlugin/index.js +142 -0
  11. package/{plugins → dist}/ModelEntryDoorGuidePlugin/index.d.ts +6 -2
  12. package/dist/ModelEntryDoorGuidePlugin/index.js +196 -0
  13. package/dist/ModelRoomLabelPlugin/Assets/roomLabelBg.d.ts +1 -0
  14. package/{plugins → dist}/ModelRoomLabelPlugin/Controller.d.ts +3 -2
  15. package/dist/ModelRoomLabelPlugin/index.d.ts +12 -0
  16. package/dist/ModelRoomLabelPlugin/index.js +463 -0
  17. package/{plugins → dist}/ModelRoomLabelPlugin/typings.d.ts +2 -2
  18. package/{plugins → dist}/ModelRoomLabelPlugin/utils/parseData.d.ts +0 -0
  19. package/{plugins → dist}/ModelViewPlugin/index.d.ts +0 -0
  20. package/dist/ModelViewPlugin/index.js +187 -0
  21. package/dist/PanoCompassPlugin/Assets/roomInfoIcon.d.ts +1 -0
  22. package/dist/PanoCompassPlugin/getRoomInfoInstance.d.ts +8 -0
  23. package/dist/PanoCompassPlugin/index.d.ts +51 -0
  24. package/dist/PanoCompassPlugin/index.js +521 -0
  25. package/{plugins → dist}/PanoCursorRaycasterPlugin/index.d.ts +2 -3
  26. package/dist/PanoCursorRaycasterPlugin/index.js +88 -0
  27. package/dist/PanoMeasurePlugin/Controller/BaseController.d.ts +36 -0
  28. package/dist/PanoMeasurePlugin/Controller/EditController.d.ts +52 -0
  29. package/dist/PanoMeasurePlugin/Controller/ShortcutKeyController.d.ts +12 -0
  30. package/dist/PanoMeasurePlugin/Controller/WatchController.d.ts +25 -0
  31. package/dist/PanoMeasurePlugin/Controller/index.d.ts +61 -0
  32. package/dist/PanoMeasurePlugin/Model/index.d.ts +38 -0
  33. package/dist/PanoMeasurePlugin/Model/line.d.ts +30 -0
  34. package/dist/PanoMeasurePlugin/Model/point.d.ts +16 -0
  35. package/dist/PanoMeasurePlugin/Model/polyline.d.ts +16 -0
  36. package/dist/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete.svg.d.ts +2 -0
  37. package/dist/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_bg.png.d.ts +2 -0
  38. package/dist/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_hover_bg.png.d.ts +2 -0
  39. package/dist/PanoMeasurePlugin/Modules/DeleteDom/index.d.ts +22 -0
  40. package/dist/PanoMeasurePlugin/Modules/FiveHelper.d.ts +11 -0
  41. package/dist/PanoMeasurePlugin/Modules/GuideController.d.ts +18 -0
  42. package/dist/PanoMeasurePlugin/Modules/Magnifier.d.ts +24 -0
  43. package/dist/PanoMeasurePlugin/Modules/UIController/HTML.d.ts +6 -0
  44. package/dist/PanoMeasurePlugin/Modules/UIController/MainBtnController.d.ts +18 -0
  45. package/dist/PanoMeasurePlugin/Modules/UIController/Revoke/index.d.ts +12 -0
  46. package/dist/PanoMeasurePlugin/Modules/UIController/index.d.ts +16 -0
  47. package/dist/PanoMeasurePlugin/Modules/UIController/style.d.ts +17 -0
  48. package/dist/PanoMeasurePlugin/index.d.ts +7 -0
  49. package/dist/PanoMeasurePlugin/index.js +4789 -0
  50. package/dist/PanoMeasurePlugin/typings/data.d.ts +28 -0
  51. package/dist/PanoMeasurePlugin/typings/event.type.d.ts +28 -0
  52. package/dist/PanoMeasurePlugin/typings/utils.type.d.ts +1 -0
  53. package/dist/PanoMeasurePlugin/utils/clearGroup.d.ts +2 -0
  54. package/dist/PanoMeasurePlugin/utils/constants.d.ts +4 -0
  55. package/dist/PanoMeasurePlugin/utils/distanceDom.d.ts +28 -0
  56. package/dist/PanoMeasurePlugin/utils/findAssociatedLines.d.ts +2 -0
  57. package/dist/PanoMeasurePlugin/utils/findClosestPoint.d.ts +10 -0
  58. package/dist/PanoMeasurePlugin/utils/getIntersectionFromEvent.d.ts +4 -0
  59. package/dist/PanoMeasurePlugin/utils/getPointFromHammerEvent.d.ts +10 -0
  60. package/dist/PanoMeasurePlugin/utils/ironbox.d.ts +1 -0
  61. package/dist/PanoMeasurePlugin/utils/isNDCPointInScreen.d.ts +2 -0
  62. package/dist/PanoMeasurePlugin/utils/line.d.ts +17 -0
  63. package/dist/PanoMeasurePlugin/utils/math.d.ts +17 -0
  64. package/dist/PanoMeasurePlugin/utils/mouseGroup.d.ts +2 -0
  65. package/dist/PanoMeasurePlugin/utils/ndc2Screen.d.ts +5 -0
  66. package/{plugins → dist}/PanoRulerPlugin/index.d.ts +9 -5
  67. package/dist/PanoRulerPlugin/index.js +610 -0
  68. package/dist/PanoRulerPlugin/style.d.ts +2 -0
  69. package/{plugins → dist}/PanoRulerPlugin/typings.d.ts +0 -0
  70. package/dist/PanoSpatialTagPlugin/index.d.ts +33 -0
  71. package/dist/PanoSpatialTagPlugin/index.js +1259 -0
  72. package/dist/PanoSpatialTagPlugin/store.d.ts +1 -0
  73. package/{plugins/floorplan/TopviewFloorplanPlugin → dist/PanoSpatialTagPlugin}/style.d.ts +0 -0
  74. package/dist/PanoSpatialTagPlugin/typings.d.ts +40 -0
  75. package/dist/floorplan/Assets/camera.d.ts +1 -0
  76. package/dist/floorplan/Assets/floorplanExtraObject.d.ts +1 -0
  77. package/dist/floorplan/ModelFloorplanPlugin/Assets/compass.d.ts +1 -0
  78. package/{plugins → dist}/floorplan/ModelFloorplanPlugin/Controller.d.ts +19 -14
  79. package/{plugins → dist}/floorplan/ModelFloorplanPlugin/index.d.ts +1 -1
  80. package/dist/floorplan/ModelFloorplanPlugin/index.js +3842 -0
  81. package/{plugins → dist}/floorplan/ModelFloorplanPlugin/typings/events.type.d.ts +0 -0
  82. package/{plugins → dist}/floorplan/ModelFloorplanPlugin/utils/constant.d.ts +1 -1
  83. package/{plugins → dist}/floorplan/ModelFloorplanPlugin/utils/correctFiveState.d.ts +0 -0
  84. package/{plugins → dist}/floorplan/PanoFloorplanRadarPlugin/Controller.d.ts +6 -11
  85. package/{plugins → dist}/floorplan/PanoFloorplanRadarPlugin/index.d.ts +0 -0
  86. package/dist/floorplan/PanoFloorplanRadarPlugin/index.js +1673 -0
  87. package/{plugins → dist}/floorplan/TopviewFloorplanPlugin/Controller.d.ts +18 -11
  88. package/{plugins → dist}/floorplan/TopviewFloorplanPlugin/index.d.ts +0 -0
  89. package/dist/floorplan/TopviewFloorplanPlugin/index.js +3481 -0
  90. package/{plugins/floorplan/ModelFloorplanPlugin/controller.style.d.ts → dist/floorplan/TopviewFloorplanPlugin/style.d.ts} +0 -0
  91. package/dist/floorplan/constant.d.ts +5 -0
  92. package/{plugins → dist}/floorplan/typings/floorplanData.d.ts +6 -0
  93. package/{plugins → dist}/floorplan/typings/floorplanServerData.d.ts +8 -2
  94. package/dist/floorplan/typings/utility.d.ts +2 -0
  95. package/{plugins → dist}/floorplan/utils/formatData.d.ts +3 -3
  96. package/{plugins → dist}/floorplan/utils/formatPosition.d.ts +3 -4
  97. package/dist/index.d.ts +26 -0
  98. package/dist/index.es.js +12928 -0
  99. package/dist/index.js +12967 -0
  100. package/dist/index.umd.js +12961 -0
  101. package/{shared-utils → dist/shared-utils}/Preloader.d.ts +0 -0
  102. package/{shared-utils → dist/shared-utils}/Subscribe.d.ts +3 -3
  103. package/{shared-utils → dist/shared-utils}/animationFrame/BetterTween.d.ts +0 -0
  104. package/{shared-utils → dist/shared-utils}/animationFrame/calculateProgress.d.ts +0 -0
  105. package/{shared-utils → dist/shared-utils}/animationFrame/formatRad.d.ts +0 -0
  106. package/{shared-utils → dist/shared-utils}/animationFrame/index.d.ts +0 -0
  107. package/{shared-utils → dist/shared-utils}/animationFrame/tween.d.ts +0 -0
  108. package/dist/shared-utils/changeModelCanvasOpacity.d.ts +2 -0
  109. package/{shared-utils → dist/shared-utils}/createCanvasTextTexture.d.ts +0 -0
  110. package/{shared-utils → dist/shared-utils}/createLine/index.d.ts +1 -1
  111. package/{shared-utils → dist/shared-utils}/debounce.d.ts +1 -1
  112. package/{shared-utils → dist/shared-utils}/equal.d.ts +0 -0
  113. package/{shared-utils → dist/shared-utils}/filter.d.ts +0 -0
  114. package/{shared-utils → dist/shared-utils}/five/changeMode.d.ts +0 -0
  115. package/{shared-utils → dist/shared-utils}/five/useFivePlugin.d.ts +0 -0
  116. package/{shared-utils → dist/shared-utils}/formatRad.d.ts +0 -0
  117. package/dist/shared-utils/getPxmm.d.ts +11 -0
  118. package/{shared-utils → dist/shared-utils}/getRandomColor.d.ts +0 -0
  119. package/{shared-utils → dist/shared-utils}/isNil.d.ts +0 -0
  120. package/{shared-utils → dist/shared-utils}/isTruelyObject.d.ts +0 -0
  121. package/dist/shared-utils/math/evenNumber.d.ts +3 -0
  122. package/{shared-utils → dist/shared-utils}/math/planimetry.d.ts +4 -4
  123. package/{shared-utils → dist/shared-utils}/math/rad2Deg.d.ts +0 -0
  124. package/{shared-utils → dist/shared-utils}/nearlyEqual.d.ts +0 -0
  125. package/{shared-utils → dist/shared-utils}/nextFrame.d.ts +0 -0
  126. package/{shared-utils → dist/shared-utils}/noop.d.ts +0 -0
  127. package/{shared-utils → dist/shared-utils}/object3d2LocalMatrix.d.ts +0 -0
  128. package/{shared-utils → dist/shared-utils}/px2rem.d.ts +0 -0
  129. package/dist/shared-utils/removeArrayItem.d.ts +7 -0
  130. package/{shared-utils → dist/shared-utils}/tap.d.ts +0 -0
  131. package/{shared-utils → dist/shared-utils}/three/centerPoint.d.ts +0 -0
  132. package/{shared-utils → dist/shared-utils}/three/getExtraModelLoader.d.ts +0 -0
  133. package/{shared-utils → dist/shared-utils}/three/getNormal.d.ts +0 -0
  134. package/{shared-utils → dist/shared-utils}/three/getTextureLoader.d.ts +0 -0
  135. package/{shared-utils → dist/shared-utils}/three/loadFbxObj.d.ts +0 -0
  136. package/dist/shared-utils/three/loadTexture.d.ts +2 -0
  137. package/{shared-utils → dist/shared-utils}/three/transformPositionToVector3.d.ts +0 -0
  138. package/{shared-utils → dist/shared-utils}/three/transfromToMeshBasicMaterial.d.ts +0 -0
  139. package/{shared-utils → dist/shared-utils}/throttle.d.ts +1 -1
  140. package/dist/shared-utils/tinyEJSrender.d.ts +5 -0
  141. package/{shared-utils → dist/shared-utils}/to.d.ts +0 -0
  142. package/{shared-utils → dist/shared-utils}/useDebounce.d.ts +0 -0
  143. package/{shared-utils → dist/shared-utils}/useThrottle.d.ts +0 -0
  144. package/{libs/gltf-viewer → dist/shared-utils}/uuid.d.ts +0 -0
  145. package/{shared-utils → dist/shared-utils}/vectorTocoordinates.d.ts +0 -0
  146. package/{typings → dist/typings}/math.type.d.ts +0 -0
  147. package/{typings → dist/typings}/utils.type.d.ts +0 -0
  148. package/docs/.nojekyll +1 -0
  149. package/docs/assets/highlight.css +78 -0
  150. package/docs/assets/icons.css +1043 -0
  151. package/docs/assets/icons.png +0 -0
  152. package/docs/assets/icons@2x.png +0 -0
  153. package/docs/assets/main.js +52 -0
  154. package/docs/assets/search.js +1 -0
  155. package/docs/assets/style.css +1413 -0
  156. package/docs/assets/widgets.png +0 -0
  157. package/docs/assets/widgets@2x.png +0 -0
  158. package/docs/classes/ModelRoomLabelController.html +20 -0
  159. package/docs/enums/FLOOR_PLAN_ATTACHED_TO.html +1 -0
  160. package/docs/enums/ModelFloorplanErrorType.html +1 -0
  161. package/docs/index.html +43 -0
  162. package/docs/interfaces/LineJson.html +1 -0
  163. package/docs/interfaces/ModelChassisCompassPluginData.html +1 -0
  164. package/docs/interfaces/ModelChassisCompassPluginExportType.html +1 -0
  165. package/docs/interfaces/ModelChassisCompassPluginParameterType.html +1 -0
  166. package/docs/interfaces/ModelEntryDoorGuidePluginData.html +1 -0
  167. package/docs/interfaces/ModelEntryDoorGuidePluginExportType.html +1 -0
  168. package/docs/interfaces/ModelFloorplanParameterType.html +1 -0
  169. package/docs/interfaces/ModelFloorplanViewEvent.html +5 -0
  170. package/docs/interfaces/ModelRoomLabelPluginData.html +1 -0
  171. package/docs/interfaces/PanoCompassPluginData.html +1 -0
  172. package/docs/interfaces/PanoCompassPluginParameterType.html +1 -0
  173. package/docs/interfaces/PanoCursorRaycasterPluginExportType.html +11 -0
  174. package/docs/interfaces/PanoRulerPluginExportType.html +1 -0
  175. package/docs/interfaces/PanoRulerPluginOptions.html +1 -0
  176. package/docs/interfaces/PanoRulerPluginParameterType.html +1 -0
  177. package/docs/interfaces/PanoSpatialTagPluginData.html +1 -0
  178. package/docs/interfaces/PanoSpatialTagPluginExportType.html +1 -0
  179. package/docs/interfaces/PanoSpatialTagPluginParameterType.html +1 -0
  180. package/docs/interfaces/PointJson.html +1 -0
  181. package/docs/interfaces/RoomLabel.html +13 -0
  182. package/docs/interfaces/TopviewFloorplanPluginParameterType.html +1 -0
  183. package/docs/modules.html +28 -0
  184. package/libs/CSS3DRenderPlugin/index.d.ts +49 -0
  185. package/libs/CSS3DRenderPlugin/index.js +179 -0
  186. package/libs/CSS3DRenderPlugin/utils/createResizeObserver.d.ts +7 -0
  187. package/libs/CSS3DRenderPlugin/utils/createResizeObserver.js +18 -0
  188. package/libs/CameraMovementPlugin/index.d.ts +7 -0
  189. package/libs/CameraMovementPlugin/index.js +159 -0
  190. package/libs/CameraMovementPlugin/typing.d.ts +68 -0
  191. package/libs/CameraMovementPlugin/typing.js +17 -0
  192. package/libs/ModelChassisCompassPlugin/index.d.ts +19 -0
  193. package/libs/ModelChassisCompassPlugin/index.js +75 -0
  194. package/libs/ModelEntryDoorGuidePlugin/index.d.ts +26 -0
  195. package/libs/ModelEntryDoorGuidePlugin/index.js +137 -0
  196. package/libs/ModelRoomLabelPlugin/Assets/roomLabelBg.d.ts +1 -0
  197. package/libs/ModelRoomLabelPlugin/Assets/roomLabelBg.js +1 -0
  198. package/libs/ModelRoomLabelPlugin/Controller.d.ts +36 -0
  199. package/libs/ModelRoomLabelPlugin/Controller.js +100 -0
  200. package/libs/ModelRoomLabelPlugin/RoomLabelItem.js +121 -0
  201. package/libs/ModelRoomLabelPlugin/RoomLabelItems.js +255 -0
  202. package/libs/ModelRoomLabelPlugin/index.d.ts +12 -0
  203. package/libs/ModelRoomLabelPlugin/index.js +9 -0
  204. package/libs/ModelRoomLabelPlugin/typings.d.ts +35 -0
  205. package/libs/ModelRoomLabelPlugin/typings.js +1 -0
  206. package/libs/ModelRoomLabelPlugin/utils/parseData.d.ts +3 -0
  207. package/libs/ModelRoomLabelPlugin/utils/parseData.js +14 -0
  208. package/libs/ModelViewPlugin/index.d.ts +17 -0
  209. package/libs/ModelViewPlugin/index.js +160 -0
  210. package/libs/PanoCompassPlugin/Assets/roomInfoIcon.d.ts +1 -0
  211. package/libs/PanoCompassPlugin/Assets/roomInfoIcon.js +1 -0
  212. package/libs/PanoCompassPlugin/getRoomInfoInstance.d.ts +8 -0
  213. package/libs/PanoCompassPlugin/getRoomInfoInstance.js +48 -0
  214. package/libs/PanoCompassPlugin/index.d.ts +51 -0
  215. package/libs/PanoCompassPlugin/index.js +171 -0
  216. package/libs/PanoCursorRaycasterPlugin/index.d.ts +48 -0
  217. package/libs/PanoCursorRaycasterPlugin/index.js +74 -0
  218. package/libs/PanoMeasurePlugin/Controller/BaseController.d.ts +36 -0
  219. package/libs/PanoMeasurePlugin/Controller/BaseController.js +69 -0
  220. package/libs/PanoMeasurePlugin/Controller/EditController.d.ts +52 -0
  221. package/libs/PanoMeasurePlugin/Controller/EditController.js +216 -0
  222. package/libs/PanoMeasurePlugin/Controller/ShortcutKeyController.d.ts +12 -0
  223. package/libs/PanoMeasurePlugin/Controller/ShortcutKeyController.js +44 -0
  224. package/libs/PanoMeasurePlugin/Controller/WatchController.d.ts +25 -0
  225. package/libs/PanoMeasurePlugin/Controller/WatchController.js +223 -0
  226. package/libs/PanoMeasurePlugin/Controller/index.d.ts +61 -0
  227. package/libs/PanoMeasurePlugin/Controller/index.js +176 -0
  228. package/libs/PanoMeasurePlugin/Model/index.d.ts +38 -0
  229. package/libs/PanoMeasurePlugin/Model/index.js +114 -0
  230. package/libs/PanoMeasurePlugin/Model/line.d.ts +30 -0
  231. package/libs/PanoMeasurePlugin/Model/line.js +64 -0
  232. package/libs/PanoMeasurePlugin/Model/point.d.ts +16 -0
  233. package/libs/PanoMeasurePlugin/Model/point.js +28 -0
  234. package/libs/PanoMeasurePlugin/Model/polyline.d.ts +16 -0
  235. package/libs/PanoMeasurePlugin/Model/polyline.js +48 -0
  236. package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete.svg.d.ts +2 -0
  237. package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete.svg.js +15 -0
  238. package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_bg.png.d.ts +2 -0
  239. package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_bg.png.js +2 -0
  240. package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_hover_bg.png.d.ts +2 -0
  241. package/libs/PanoMeasurePlugin/Modules/DeleteDom/_Assets/delete_hover_bg.png.js +2 -0
  242. package/libs/PanoMeasurePlugin/Modules/DeleteDom/index.d.ts +22 -0
  243. package/libs/PanoMeasurePlugin/Modules/DeleteDom/index.js +108 -0
  244. package/libs/PanoMeasurePlugin/Modules/FiveHelper.d.ts +11 -0
  245. package/libs/PanoMeasurePlugin/Modules/FiveHelper.js +33 -0
  246. package/libs/PanoMeasurePlugin/Modules/GuideController.d.ts +18 -0
  247. package/libs/PanoMeasurePlugin/Modules/GuideController.js +75 -0
  248. package/libs/PanoMeasurePlugin/Modules/Magnifier.d.ts +24 -0
  249. package/libs/PanoMeasurePlugin/Modules/Magnifier.js +103 -0
  250. package/libs/PanoMeasurePlugin/Modules/UIController/HTML.d.ts +6 -0
  251. package/libs/PanoMeasurePlugin/Modules/UIController/HTML.js +117 -0
  252. package/libs/PanoMeasurePlugin/Modules/UIController/MainBtnController.d.ts +18 -0
  253. package/libs/PanoMeasurePlugin/Modules/UIController/MainBtnController.js +102 -0
  254. package/libs/PanoMeasurePlugin/Modules/UIController/Revoke/index.d.ts +12 -0
  255. package/libs/PanoMeasurePlugin/Modules/UIController/Revoke/index.js +35 -0
  256. package/libs/PanoMeasurePlugin/Modules/UIController/index.d.ts +16 -0
  257. package/libs/PanoMeasurePlugin/Modules/UIController/index.js +69 -0
  258. package/libs/PanoMeasurePlugin/Modules/UIController/style.d.ts +17 -0
  259. package/libs/PanoMeasurePlugin/Modules/UIController/style.js +78 -0
  260. package/libs/PanoMeasurePlugin/index.d.ts +7 -0
  261. package/libs/PanoMeasurePlugin/index.js +5 -0
  262. package/libs/PanoMeasurePlugin/typings/data.d.ts +28 -0
  263. package/libs/PanoMeasurePlugin/typings/data.js +1 -0
  264. package/libs/PanoMeasurePlugin/typings/event.type.d.ts +28 -0
  265. package/libs/PanoMeasurePlugin/typings/event.type.js +1 -0
  266. package/libs/PanoMeasurePlugin/typings/utils.type.d.ts +1 -0
  267. package/libs/PanoMeasurePlugin/typings/utils.type.js +1 -0
  268. package/libs/PanoMeasurePlugin/utils/clearGroup.d.ts +2 -0
  269. package/libs/PanoMeasurePlugin/utils/clearGroup.js +3 -0
  270. package/libs/PanoMeasurePlugin/utils/constants.d.ts +4 -0
  271. package/libs/PanoMeasurePlugin/utils/constants.js +31 -0
  272. package/libs/PanoMeasurePlugin/utils/distanceDom.d.ts +28 -0
  273. package/libs/PanoMeasurePlugin/utils/distanceDom.js +114 -0
  274. package/libs/PanoMeasurePlugin/utils/findAssociatedLines.d.ts +2 -0
  275. package/libs/PanoMeasurePlugin/utils/findAssociatedLines.js +21 -0
  276. package/libs/PanoMeasurePlugin/utils/findClosestPoint.d.ts +10 -0
  277. package/libs/PanoMeasurePlugin/utils/findClosestPoint.js +27 -0
  278. package/libs/PanoMeasurePlugin/utils/getIntersectionFromEvent.d.ts +4 -0
  279. package/libs/PanoMeasurePlugin/utils/getIntersectionFromEvent.js +9 -0
  280. package/libs/PanoMeasurePlugin/utils/getPointFromHammerEvent.d.ts +10 -0
  281. package/libs/PanoMeasurePlugin/utils/getPointFromHammerEvent.js +14 -0
  282. package/libs/PanoMeasurePlugin/utils/ironbox.d.ts +1 -0
  283. package/libs/PanoMeasurePlugin/utils/ironbox.js +1 -0
  284. package/libs/PanoMeasurePlugin/utils/isNDCPointInScreen.d.ts +2 -0
  285. package/libs/PanoMeasurePlugin/utils/isNDCPointInScreen.js +6 -0
  286. package/libs/PanoMeasurePlugin/utils/line.d.ts +17 -0
  287. package/libs/PanoMeasurePlugin/utils/line.js +32 -0
  288. package/libs/PanoMeasurePlugin/utils/math.d.ts +17 -0
  289. package/libs/PanoMeasurePlugin/utils/math.js +44 -0
  290. package/libs/PanoMeasurePlugin/utils/mouseGroup.d.ts +2 -0
  291. package/libs/PanoMeasurePlugin/utils/mouseGroup.js +21 -0
  292. package/libs/PanoMeasurePlugin/utils/ndc2Screen.d.ts +5 -0
  293. package/libs/PanoMeasurePlugin/utils/ndc2Screen.js +6 -0
  294. package/libs/PanoRulerPlugin/index.d.ts +31 -0
  295. package/libs/PanoRulerPlugin/index.js +398 -0
  296. package/libs/PanoRulerPlugin/style.d.ts +2 -0
  297. package/libs/PanoRulerPlugin/style.js +88 -0
  298. package/libs/PanoRulerPlugin/typings.d.ts +21 -0
  299. package/libs/PanoRulerPlugin/typings.js +1 -0
  300. package/libs/PanoSpatialTagPlugin/Components/origins.js +168 -0
  301. package/libs/PanoSpatialTagPlugin/Components/tag.js +302 -0
  302. package/libs/PanoSpatialTagPlugin/index.d.ts +33 -0
  303. package/libs/PanoSpatialTagPlugin/index.js +411 -0
  304. package/libs/PanoSpatialTagPlugin/store.d.ts +1 -0
  305. package/libs/PanoSpatialTagPlugin/store.js +2 -0
  306. package/libs/PanoSpatialTagPlugin/style.d.ts +1 -0
  307. package/libs/PanoSpatialTagPlugin/style.js +8 -0
  308. package/libs/PanoSpatialTagPlugin/typings.d.ts +40 -0
  309. package/libs/PanoSpatialTagPlugin/typings.js +1 -0
  310. package/libs/floorplan/Assets/camera.d.ts +1 -0
  311. package/libs/floorplan/Assets/camera.js +1 -0
  312. package/libs/floorplan/Assets/floorplanExtraObject.d.ts +1 -0
  313. package/libs/floorplan/Assets/floorplanExtraObject.js +1 -0
  314. package/libs/floorplan/Components/BaseImage.js +217 -0
  315. package/libs/floorplan/Components/Normalmage.js +63 -0
  316. package/libs/floorplan/Components/RoomHighlight/Room.js +70 -0
  317. package/libs/floorplan/Components/RoomHighlight/RoomHighlight.js +289 -0
  318. package/libs/floorplan/Components/RoomMaterials/RoomMaterial.js +328 -0
  319. package/libs/floorplan/Components/RoomMaterials/RoomMaterial_0.js +64 -0
  320. package/libs/floorplan/Components/RoomMaterials/RoomMaterial_1.js +103 -0
  321. package/libs/floorplan/Components/RoomMaterials/RoomMaterial_2.js +140 -0
  322. package/libs/floorplan/Components/SvgImage.js +83 -0
  323. package/libs/floorplan/ModelFloorplanPlugin/Assets/compass.d.ts +1 -0
  324. package/libs/floorplan/ModelFloorplanPlugin/Assets/compass.js +1 -0
  325. package/libs/floorplan/ModelFloorplanPlugin/Components/Camera.js +120 -0
  326. package/libs/floorplan/ModelFloorplanPlugin/Components/Compass.js +114 -0
  327. package/libs/floorplan/ModelFloorplanPlugin/Components/CurrentFloor/CurrentFloor.js +463 -0
  328. package/libs/floorplan/ModelFloorplanPlugin/Components/Main.js +383 -0
  329. package/libs/floorplan/ModelFloorplanPlugin/Components/RoomLabels/RoomLabel.js +171 -0
  330. package/libs/floorplan/ModelFloorplanPlugin/Components/RoomLabels/RoomLabels.js +265 -0
  331. package/libs/floorplan/ModelFloorplanPlugin/Components/RuleLabels/RuleItem.js +301 -0
  332. package/libs/floorplan/ModelFloorplanPlugin/Components/RuleLabels/RuleLabels.js +219 -0
  333. package/libs/floorplan/ModelFloorplanPlugin/Controller.d.ts +105 -0
  334. package/libs/floorplan/ModelFloorplanPlugin/Controller.js +359 -0
  335. package/libs/floorplan/ModelFloorplanPlugin/index.d.ts +9 -0
  336. package/libs/floorplan/ModelFloorplanPlugin/index.js +5 -0
  337. package/libs/floorplan/ModelFloorplanPlugin/typings/events.type.d.ts +23 -0
  338. package/libs/floorplan/ModelFloorplanPlugin/typings/events.type.js +1 -0
  339. package/libs/floorplan/ModelFloorplanPlugin/utils/constant.d.ts +15 -0
  340. package/libs/floorplan/ModelFloorplanPlugin/utils/constant.js +16 -0
  341. package/libs/floorplan/ModelFloorplanPlugin/utils/correctFiveState.d.ts +14 -0
  342. package/libs/floorplan/ModelFloorplanPlugin/utils/correctFiveState.js +46 -0
  343. package/libs/floorplan/PanoFloorplanRadarPlugin/Components/Camera.js +152 -0
  344. package/libs/floorplan/PanoFloorplanRadarPlugin/Components/CurrentFloor/CurrentFloor.js +248 -0
  345. package/libs/floorplan/PanoFloorplanRadarPlugin/Components/CurrentFloor/ExtraObjects.js +154 -0
  346. package/libs/floorplan/PanoFloorplanRadarPlugin/Components/Main.js +312 -0
  347. package/libs/floorplan/PanoFloorplanRadarPlugin/Controller.d.ts +28 -0
  348. package/libs/floorplan/PanoFloorplanRadarPlugin/Controller.js +88 -0
  349. package/libs/floorplan/PanoFloorplanRadarPlugin/index.d.ts +8 -0
  350. package/libs/floorplan/PanoFloorplanRadarPlugin/index.js +5 -0
  351. package/libs/floorplan/TopviewFloorplanPlugin/Controller.d.ts +62 -0
  352. package/libs/floorplan/TopviewFloorplanPlugin/Controller.js +191 -0
  353. package/libs/floorplan/TopviewFloorplanPlugin/index.d.ts +5 -0
  354. package/libs/floorplan/TopviewFloorplanPlugin/index.js +5 -0
  355. package/libs/floorplan/TopviewFloorplanPlugin/style.d.ts +1 -0
  356. package/libs/floorplan/TopviewFloorplanPlugin/style.js +8 -0
  357. package/libs/floorplan/constant.d.ts +5 -0
  358. package/libs/floorplan/constant.js +6 -0
  359. package/libs/floorplan/typings/floorplanData.d.ts +137 -0
  360. package/libs/floorplan/typings/floorplanData.js +6 -0
  361. package/libs/floorplan/typings/floorplanServerData.d.ts +131 -0
  362. package/libs/floorplan/typings/floorplanServerData.js +101 -0
  363. package/libs/floorplan/typings/utility.d.ts +2 -0
  364. package/libs/floorplan/typings/utility.js +1 -0
  365. package/libs/floorplan/utils/formatData.d.ts +5 -0
  366. package/libs/floorplan/utils/formatData.js +94 -0
  367. package/libs/floorplan/utils/formatPosition.d.ts +36 -0
  368. package/libs/floorplan/utils/formatPosition.js +50 -0
  369. package/libs/index.d.ts +26 -0
  370. package/libs/index.js +16 -0
  371. package/libs/shared-utils/Preloader.d.ts +6 -0
  372. package/libs/shared-utils/Preloader.js +38 -0
  373. package/libs/shared-utils/Subscribe.d.ts +45 -0
  374. package/libs/shared-utils/Subscribe.js +101 -0
  375. package/libs/shared-utils/animationFrame/BetterTween.d.ts +11 -0
  376. package/libs/shared-utils/animationFrame/BetterTween.js +30 -0
  377. package/libs/shared-utils/animationFrame/calculateProgress.d.ts +8 -0
  378. package/libs/shared-utils/animationFrame/calculateProgress.js +23 -0
  379. package/libs/shared-utils/animationFrame/formatRad.d.ts +15 -0
  380. package/libs/shared-utils/animationFrame/formatRad.js +20 -0
  381. package/libs/shared-utils/animationFrame/index.d.ts +15 -0
  382. package/libs/shared-utils/animationFrame/index.js +48 -0
  383. package/libs/shared-utils/animationFrame/tween.d.ts +75 -0
  384. package/libs/shared-utils/animationFrame/tween.js +44 -0
  385. package/libs/shared-utils/changeModelCanvasOpacity.d.ts +2 -0
  386. package/libs/shared-utils/changeModelCanvasOpacity.js +15 -0
  387. package/libs/shared-utils/createCanvasTextTexture.d.ts +8 -0
  388. package/libs/shared-utils/createCanvasTextTexture.js +19 -0
  389. package/libs/shared-utils/createLine/index.d.ts +3 -0
  390. package/libs/shared-utils/createLine/index.js +8 -0
  391. package/libs/shared-utils/debounce.d.ts +6 -0
  392. package/libs/shared-utils/debounce.js +14 -0
  393. package/libs/shared-utils/equal.d.ts +11 -0
  394. package/libs/shared-utils/equal.js +84 -0
  395. package/libs/shared-utils/filter.d.ts +27 -0
  396. package/libs/shared-utils/filter.js +53 -0
  397. package/libs/shared-utils/five/changeMode.d.ts +2 -0
  398. package/libs/shared-utils/five/changeMode.js +15 -0
  399. package/libs/shared-utils/five/useFivePlugin.d.ts +1 -0
  400. package/libs/shared-utils/five/useFivePlugin.js +8 -0
  401. package/libs/shared-utils/formatRad.d.ts +7 -0
  402. package/libs/shared-utils/formatRad.js +10 -0
  403. package/libs/shared-utils/getPxmm.d.ts +11 -0
  404. package/libs/shared-utils/getPxmm.js +34 -0
  405. package/libs/shared-utils/getRandomColor.d.ts +1 -0
  406. package/libs/shared-utils/getRandomColor.js +10 -0
  407. package/libs/shared-utils/isNil.d.ts +10 -0
  408. package/libs/shared-utils/isNil.js +14 -0
  409. package/libs/shared-utils/isTruelyObject.d.ts +18 -0
  410. package/libs/shared-utils/isTruelyObject.js +20 -0
  411. package/libs/shared-utils/math/evenNumber.d.ts +3 -0
  412. package/libs/shared-utils/math/evenNumber.js +4 -0
  413. package/libs/shared-utils/math/planimetry.d.ts +116 -0
  414. package/libs/shared-utils/math/planimetry.js +288 -0
  415. package/libs/shared-utils/math/rad2Deg.d.ts +1 -0
  416. package/libs/shared-utils/math/rad2Deg.js +3 -0
  417. package/libs/shared-utils/nearlyEqual.d.ts +7 -0
  418. package/libs/shared-utils/nearlyEqual.js +9 -0
  419. package/libs/shared-utils/nextFrame.d.ts +1 -0
  420. package/libs/shared-utils/nextFrame.js +6 -0
  421. package/libs/shared-utils/noop.d.ts +5 -0
  422. package/libs/shared-utils/noop.js +7 -0
  423. package/libs/shared-utils/object3d2LocalMatrix.d.ts +12 -0
  424. package/libs/shared-utils/object3d2LocalMatrix.js +29 -0
  425. package/libs/shared-utils/px2rem.d.ts +1 -0
  426. package/libs/shared-utils/px2rem.js +4 -0
  427. package/libs/shared-utils/removeArrayItem.d.ts +7 -0
  428. package/libs/shared-utils/removeArrayItem.js +12 -0
  429. package/libs/shared-utils/tap.d.ts +8 -0
  430. package/{shared-utils → libs/shared-utils}/tap.js +4 -13
  431. package/libs/shared-utils/three/centerPoint.d.ts +2 -0
  432. package/libs/shared-utils/three/centerPoint.js +4 -0
  433. package/libs/shared-utils/three/getExtraModelLoader.d.ts +6 -0
  434. package/libs/shared-utils/three/getExtraModelLoader.js +18 -0
  435. package/libs/shared-utils/three/getNormal.d.ts +2 -0
  436. package/libs/shared-utils/three/getNormal.js +6 -0
  437. package/libs/shared-utils/three/getTextureLoader.d.ts +6 -0
  438. package/libs/shared-utils/three/getTextureLoader.js +17 -0
  439. package/libs/shared-utils/three/loadFbxObj.d.ts +2 -0
  440. package/libs/shared-utils/three/loadFbxObj.js +13 -0
  441. package/libs/shared-utils/three/loadTexture.d.ts +2 -0
  442. package/libs/shared-utils/three/loadTexture.js +10 -0
  443. package/libs/shared-utils/three/transformPositionToVector3.d.ts +7 -0
  444. package/libs/shared-utils/three/transformPositionToVector3.js +3 -0
  445. package/libs/shared-utils/three/transfromToMeshBasicMaterial.d.ts +2 -0
  446. package/libs/shared-utils/three/transfromToMeshBasicMaterial.js +14 -0
  447. package/libs/shared-utils/throttle.d.ts +7 -0
  448. package/libs/shared-utils/throttle.js +18 -0
  449. package/libs/shared-utils/tinyEJSrender.d.ts +5 -0
  450. package/libs/shared-utils/tinyEJSrender.js +180 -0
  451. package/libs/shared-utils/to.d.ts +8 -0
  452. package/libs/shared-utils/to.js +18 -0
  453. package/libs/shared-utils/useDebounce.d.ts +8 -0
  454. package/libs/shared-utils/useDebounce.js +22 -0
  455. package/libs/shared-utils/useThrottle.d.ts +8 -0
  456. package/libs/shared-utils/useThrottle.js +25 -0
  457. package/{shared-utils → libs/shared-utils}/uuid.d.ts +0 -0
  458. package/libs/shared-utils/uuid.js +11 -0
  459. package/libs/shared-utils/vectorTocoordinates.d.ts +7 -0
  460. package/libs/shared-utils/vectorTocoordinates.js +9 -0
  461. package/libs/typings/math.type.d.ts +44 -0
  462. package/libs/typings/math.type.js +1 -0
  463. package/libs/typings/utils.type.d.ts +2 -0
  464. package/libs/typings/utils.type.js +1 -0
  465. package/package.json +55 -17
  466. package/components/ARVideoFigure/ARVideoFigureMesh.d.ts +0 -44
  467. package/components/ARVideoFigure/ARVideoFigureMesh.js +0 -371
  468. package/components/ARVideoFigure/ARVideoFigureScene.d.ts +0 -11
  469. package/components/ARVideoFigure/ARVideoFigureScene.js +0 -85
  470. package/components/ARVideoFigure/ImgBgTransparent.d.ts +0 -16
  471. package/components/ARVideoFigure/ImgBgTransparent.js +0 -65
  472. package/components/ARVideoFigure/ImgBgTransparentMesh.d.ts +0 -30
  473. package/components/ARVideoFigure/ImgBgTransparentMesh.js +0 -183
  474. package/components/ARVideoFigure/fragmentShader.d.ts +0 -5
  475. package/components/ARVideoFigure/fragmentShader.js +0 -18
  476. package/components/ARVideoFigure/index.d.ts +0 -15
  477. package/components/ARVideoFigure/index.js +0 -80
  478. package/components/ARVideoFigure/vertexShader.d.ts +0 -1
  479. package/components/ARVideoFigure/vertexShader.js +0 -10
  480. package/components/GLTFView/index.d.ts +0 -72
  481. package/components/GLTFView/index.js +0 -149
  482. package/components/GlassFilters/index.d.ts +0 -32
  483. package/components/GlassFilters/index.js +0 -78
  484. package/components/ModelView/ModelViewController.d.ts +0 -18
  485. package/components/ModelView/ModelViewController.js +0 -157
  486. package/components/ModelView/index.d.ts +0 -10
  487. package/components/ModelView/index.js +0 -24
  488. package/components/PaintBrush/index.d.ts +0 -16
  489. package/components/PaintBrush/index.js +0 -47
  490. package/components/PanoTag/index.d.ts +0 -4
  491. package/components/PanoTag/index.js +0 -13
  492. package/custom.d.js +0 -3
  493. package/data/1aGKl9JmrlXMXx8d.d.ts +0 -104
  494. package/data/1aGKl9JmrlXMXx8d.js +0 -537
  495. package/data/54djM0oR6ky3Ey8e.d.ts +0 -55
  496. package/data/54djM0oR6ky3Ey8e.js +0 -350
  497. package/data/6gyq3v1verxD7JO1.d.ts +0 -104
  498. package/data/6gyq3v1verxD7JO1.js +0 -462
  499. package/data/8054djM0oR6ky3Ey8e.d.ts +0 -55
  500. package/data/8054djM0oR6ky3Ey8e.js +0 -350
  501. package/data/KpokNd82rwjhackhQTBEoYKHg8zGbPXe.d.ts +0 -84
  502. package/data/KpokNd82rwjhackhQTBEoYKHg8zGbPXe.js +0 -600
  503. package/data/PrXel3aqGbp34JQn.d.ts +0 -389
  504. package/data/PrXel3aqGbp34JQn.js +0 -4649
  505. package/data/XJ6NMLWnkAY3Rdx8.d.ts +0 -843
  506. package/data/XJ6NMLWnkAY3Rdx8.js +0 -7989
  507. package/data/YdoNP9K4rwQDwjJr.d.ts +0 -83
  508. package/data/YdoNP9K4rwQDwjJr.js +0 -1453
  509. package/data/ZLvK29zj4L29Jowd.d.ts +0 -55
  510. package/data/ZLvK29zj4L29Jowd.js +0 -372
  511. package/data/auto3d-njL5J99VwCmnjtQElOmXQr.d.ts +0 -86
  512. package/data/auto3d-njL5J99VwCmnjtQElOmXQr.js +0 -711
  513. package/data/extrude-walls/ZLvK29zj4L29Jowd.d.ts +0 -5
  514. package/data/extrude-walls/ZLvK29zj4L29Jowd.js +0 -14
  515. package/data/extrude-walls/lo024DEgzanMj5BE.d.ts +0 -5
  516. package/data/extrude-walls/lo024DEgzanMj5BE.js +0 -14
  517. package/data/jd6oMOzPxnQ3BvxY_B7yw51J9rXlhYhjhGTOgRVqu6WeEqjNX.d.ts +0 -85
  518. package/data/jd6oMOzPxnQ3BvxY_B7yw51J9rXlhYhjhGTOgRVqu6WeEqjNX.js +0 -511
  519. package/data/lo024DEgzanMj5BE.d.ts +0 -55
  520. package/data/lo024DEgzanMj5BE.js +0 -966
  521. package/data/oPzy3ApbjjpD8YdR.d.ts +0 -83
  522. package/data/oPzy3ApbjjpD8YdR.js +0 -283
  523. package/data/qjAxMG4XbPn96wKG.d.ts +0 -104
  524. package/data/qjAxMG4XbPn96wKG.js +0 -637
  525. package/data/rXel3aPQRRBD4JQn.d.ts +0 -86
  526. package/data/rXel3aPQRRBD4JQn.js +0 -622
  527. package/data/vLykj3NWrllMrG06.d.ts +0 -91
  528. package/data/vLykj3NWrllMrG06.js +0 -2729
  529. package/data/wz0QV9KA4ugyo9ME.d.ts +0 -39
  530. package/data/wz0QV9KA4ugyo9ME.js +0 -136
  531. package/data/zxMawr9raSg8LYjG.d.ts +0 -53
  532. package/data/zxMawr9raSg8LYjG.js +0 -590
  533. package/examples/FiveStateController/index.js +0 -134
  534. package/examples/VRHouse/Mobile.js +0 -36
  535. package/examples/VRHouse/PC.js +0 -36
  536. package/examples/VRHouse/index.js +0 -36
  537. package/index.d.ts +0 -15
  538. package/index.js +0 -45
  539. package/libs/gltf-viewer/Subscribe.d.ts +0 -76
  540. package/libs/gltf-viewer/Subscribe.js +0 -231
  541. package/libs/gltf-viewer/coordsMoveByOffset.d.ts +0 -13
  542. package/libs/gltf-viewer/coordsMoveByOffset.js +0 -22
  543. package/libs/gltf-viewer/coordsToDirection.d.ts +0 -5
  544. package/libs/gltf-viewer/coordsToDirection.js +0 -41
  545. package/libs/gltf-viewer/formatRad.d.ts +0 -1
  546. package/libs/gltf-viewer/formatRad.js +0 -13
  547. package/libs/gltf-viewer/getFrameTime.d.ts +0 -1
  548. package/libs/gltf-viewer/getFrameTime.js +0 -28
  549. package/libs/gltf-viewer/index.d.ts +0 -55
  550. package/libs/gltf-viewer/index.js +0 -650
  551. package/libs/gltf-viewer/mouseWheel.d.ts +0 -2
  552. package/libs/gltf-viewer/mouseWheel.js +0 -59
  553. package/libs/gltf-viewer/requestAnimationFrame.d.ts +0 -1
  554. package/libs/gltf-viewer/requestAnimationFrame.js +0 -18
  555. package/libs/gltf-viewer/requestAnimationFrameInterval.d.ts +0 -1
  556. package/libs/gltf-viewer/requestAnimationFrameInterval.js +0 -31
  557. package/libs/gltf-viewer/uuid.js +0 -28
  558. package/plugins/AutoPreloadPlugin/index.d.ts +0 -23
  559. package/plugins/AutoPreloadPlugin/index.js +0 -111
  560. package/plugins/CSS3DRenderPlugin/components/Marker/index.d.ts +0 -12
  561. package/plugins/CSS3DRenderPlugin/components/Marker/index.js +0 -121
  562. package/plugins/CSS3DRenderPlugin/index.js +0 -298
  563. package/plugins/CameraMovementPlugin/index.js +0 -362
  564. package/plugins/CameraMovementPlugin/typing.js +0 -37
  565. package/plugins/ModelChassisCompassPlugin/index.js +0 -157
  566. package/plugins/ModelEntryDoorGuidePlugin/index.js +0 -247
  567. package/plugins/ModelExtrudeWallsPlugin/index.d.ts +0 -16
  568. package/plugins/ModelExtrudeWallsPlugin/index.js +0 -252
  569. package/plugins/ModelRoomLabelPlugin/Controller.js +0 -153
  570. package/plugins/ModelRoomLabelPlugin/RoomLabelItem.d.ts +0 -8
  571. package/plugins/ModelRoomLabelPlugin/RoomLabelItem.js +0 -66
  572. package/plugins/ModelRoomLabelPlugin/RoomLabelItems.d.ts +0 -7
  573. package/plugins/ModelRoomLabelPlugin/RoomLabelItems.js +0 -159
  574. package/plugins/ModelRoomLabelPlugin/index.d.ts +0 -8
  575. package/plugins/ModelRoomLabelPlugin/index.js +0 -18
  576. package/plugins/ModelRoomLabelPlugin/typings.js +0 -7
  577. package/plugins/ModelRoomLabelPlugin/utils/parseData.js +0 -35
  578. package/plugins/ModelTVVideoPlugin/index.d.ts +0 -21
  579. package/plugins/ModelTVVideoPlugin/index.js +0 -397
  580. package/plugins/ModelViewPlugin/index.js +0 -223
  581. package/plugins/PanoCursorRaycasterPlugin/PanoCursorRaycasterPluginUsage.d.ts +0 -48
  582. package/plugins/PanoCursorRaycasterPlugin/components/MovePointTowardsCamera.d.ts +0 -9
  583. package/plugins/PanoCursorRaycasterPlugin/components/MovePointTowardsCamera.js +0 -117
  584. package/plugins/PanoCursorRaycasterPlugin/components/PointAxesHelper.d.ts +0 -11
  585. package/plugins/PanoCursorRaycasterPlugin/components/PointAxesHelper.js +0 -39
  586. package/plugins/PanoCursorRaycasterPlugin/index.js +0 -126
  587. package/plugins/PanoCursorRaycasterPlugin/utils/addLineToFive.d.ts +0 -5
  588. package/plugins/PanoCursorRaycasterPlugin/utils/addLineToFive.js +0 -27
  589. package/plugins/PanoCursorRaycasterPlugin/utils/createLine.d.ts +0 -3
  590. package/plugins/PanoCursorRaycasterPlugin/utils/createLine.js +0 -48
  591. package/plugins/PanoDoorLabelPlugin/index.d.ts +0 -4
  592. package/plugins/PanoDoorLabelPlugin/index.js +0 -14
  593. package/plugins/PanoIRobotPlugin/index.d.ts +0 -10
  594. package/plugins/PanoIRobotPlugin/index.js +0 -18
  595. package/plugins/PanoMaskSelectorPlugin/compare.d.ts +0 -1
  596. package/plugins/PanoMaskSelectorPlugin/compare.js +0 -17
  597. package/plugins/PanoMaskSelectorPlugin/createBox.d.ts +0 -7
  598. package/plugins/PanoMaskSelectorPlugin/createBox.js +0 -79
  599. package/plugins/PanoMaskSelectorPlugin/createTextures.d.ts +0 -3
  600. package/plugins/PanoMaskSelectorPlugin/createTextures.js +0 -45
  601. package/plugins/PanoMaskSelectorPlugin/fragmentShader.d.ts +0 -1
  602. package/plugins/PanoMaskSelectorPlugin/fragmentShader.js +0 -10
  603. package/plugins/PanoMaskSelectorPlugin/index.d.ts +0 -49
  604. package/plugins/PanoMaskSelectorPlugin/index.js +0 -348
  605. package/plugins/PanoMaskSelectorPlugin/vertexShader.d.ts +0 -1
  606. package/plugins/PanoMaskSelectorPlugin/vertexShader.js +0 -10
  607. package/plugins/PanoRulerPlugin/data/roomInfo.d.ts +0 -3
  608. package/plugins/PanoRulerPlugin/data/roomInfo.js +0 -51
  609. package/plugins/PanoRulerPlugin/data/roomRules.d.ts +0 -3
  610. package/plugins/PanoRulerPlugin/data/roomRules.js +0 -235
  611. package/plugins/PanoRulerPlugin/index.js +0 -637
  612. package/plugins/PanoRulerPlugin/typings.js +0 -7
  613. package/plugins/PanoTVVideoPlugin/index.d.ts +0 -26
  614. package/plugins/PanoTVVideoPlugin/index.js +0 -433
  615. package/plugins/TreasurePlugin/Controller.d.ts +0 -73
  616. package/plugins/TreasurePlugin/Controller.js +0 -250
  617. package/plugins/TreasurePlugin/TreasureFaceAnime.d.ts +0 -25
  618. package/plugins/TreasurePlugin/TreasureFaceAnime.js +0 -143
  619. package/plugins/TreasurePlugin/TreasureObject.d.ts +0 -53
  620. package/plugins/TreasurePlugin/TreasureObject.js +0 -406
  621. package/plugins/TreasurePlugin/TreasureOpenAnime.d.ts +0 -25
  622. package/plugins/TreasurePlugin/TreasureOpenAnime.js +0 -127
  623. package/plugins/TreasurePlugin/constants.d.ts +0 -33
  624. package/plugins/TreasurePlugin/constants.js +0 -67
  625. package/plugins/TreasurePlugin/index.d.ts +0 -11
  626. package/plugins/TreasurePlugin/index.js +0 -26
  627. package/plugins/TreasurePlugin/typings.d.ts +0 -2
  628. package/plugins/TreasurePlugin/typings.js +0 -7
  629. package/plugins/floorplan/Assets/floorplanExtraObject.d.ts +0 -1
  630. package/plugins/floorplan/Assets/floorplanExtraObject.js +0 -10
  631. package/plugins/floorplan/ModelFloorplanPlugin/Controller.js +0 -626
  632. package/plugins/floorplan/ModelFloorplanPlugin/components/Camera.d.ts +0 -13
  633. package/plugins/floorplan/ModelFloorplanPlugin/components/Camera.js +0 -78
  634. package/plugins/floorplan/ModelFloorplanPlugin/components/Compass.d.ts +0 -5
  635. package/plugins/floorplan/ModelFloorplanPlugin/components/Compass.js +0 -84
  636. package/plugins/floorplan/ModelFloorplanPlugin/components/NowFloor/RoomHighlight.d.ts +0 -10
  637. package/plugins/floorplan/ModelFloorplanPlugin/components/NowFloor/RoomHighlight.js +0 -129
  638. package/plugins/floorplan/ModelFloorplanPlugin/components/NowFloor/RoomLabels.d.ts +0 -13
  639. package/plugins/floorplan/ModelFloorplanPlugin/components/NowFloor/RoomLabels.js +0 -118
  640. package/plugins/floorplan/ModelFloorplanPlugin/components/NowFloor/index.d.ts +0 -13
  641. package/plugins/floorplan/ModelFloorplanPlugin/components/NowFloor/index.js +0 -62
  642. package/plugins/floorplan/ModelFloorplanPlugin/components/index.d.ts +0 -20
  643. package/plugins/floorplan/ModelFloorplanPlugin/components/index.js +0 -88
  644. package/plugins/floorplan/ModelFloorplanPlugin/controller.style.js +0 -16
  645. package/plugins/floorplan/ModelFloorplanPlugin/index.js +0 -20
  646. package/plugins/floorplan/ModelFloorplanPlugin/typings/events.type.js +0 -7
  647. package/plugins/floorplan/ModelFloorplanPlugin/utils/constant.js +0 -33
  648. package/plugins/floorplan/ModelFloorplanPlugin/utils/correctFiveState.js +0 -154
  649. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/Camera.d.ts +0 -13
  650. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/Camera.js +0 -113
  651. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/Camera.style.d.ts +0 -3
  652. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/Camera.style.js +0 -39
  653. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/NowFloor/ExtraObjects.d.ts +0 -5
  654. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/NowFloor/ExtraObjects.js +0 -66
  655. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/NowFloor/RoomHighlight.d.ts +0 -9
  656. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/NowFloor/RoomHighlight.js +0 -126
  657. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/NowFloor/index.d.ts +0 -11
  658. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/NowFloor/index.js +0 -58
  659. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/index.d.ts +0 -17
  660. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/index.js +0 -85
  661. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/index.style.d.ts +0 -2
  662. package/plugins/floorplan/PanoFloorplanRadarPlugin/Content/index.style.js +0 -15
  663. package/plugins/floorplan/PanoFloorplanRadarPlugin/Controller.js +0 -211
  664. package/plugins/floorplan/PanoFloorplanRadarPlugin/index.js +0 -20
  665. package/plugins/floorplan/TopviewFloorplanPlugin/Controller.js +0 -262
  666. package/plugins/floorplan/TopviewFloorplanPlugin/index.js +0 -18
  667. package/plugins/floorplan/TopviewFloorplanPlugin/style.js +0 -16
  668. package/plugins/floorplan/components/FloorplanImage.d.ts +0 -7
  669. package/plugins/floorplan/components/FloorplanImage.js +0 -90
  670. package/plugins/floorplan/typings/floorplanData.js +0 -7
  671. package/plugins/floorplan/typings/floorplanServerData.js +0 -382
  672. package/plugins/floorplan/utils/formatData.js +0 -217
  673. package/plugins/floorplan/utils/formatPosition.js +0 -89
  674. package/shared-utils/Preloader.js +0 -57
  675. package/shared-utils/Subscribe.js +0 -230
  676. package/shared-utils/animationFrame/BetterTween.js +0 -103
  677. package/shared-utils/animationFrame/calculateProgress.js +0 -40
  678. package/shared-utils/animationFrame/formatRad.js +0 -36
  679. package/shared-utils/animationFrame/index.js +0 -81
  680. package/shared-utils/animationFrame/tween.js +0 -92
  681. package/shared-utils/changeModelCanvansOpacity.d.ts +0 -2
  682. package/shared-utils/changeModelCanvansOpacity.js +0 -38
  683. package/shared-utils/createCanvasTextTexture.js +0 -31
  684. package/shared-utils/createFiveContainer.d.ts +0 -10
  685. package/shared-utils/createFiveContainer.js +0 -171
  686. package/shared-utils/createLine/index.js +0 -43
  687. package/shared-utils/debounce.js +0 -30
  688. package/shared-utils/equal.js +0 -107
  689. package/shared-utils/filter.js +0 -127
  690. package/shared-utils/five/changeMode.js +0 -82
  691. package/shared-utils/five/useFivePlugin.js +0 -17
  692. package/shared-utils/formatRad.js +0 -18
  693. package/shared-utils/getPxmm.d.ts +0 -6
  694. package/shared-utils/getPxmm.js +0 -51
  695. package/shared-utils/getRandomColor.js +0 -23
  696. package/shared-utils/isNil.js +0 -26
  697. package/shared-utils/isTruelyObject.js +0 -31
  698. package/shared-utils/math/evenNumber.d.ts +0 -1
  699. package/shared-utils/math/evenNumber.js +0 -13
  700. package/shared-utils/math/planimetry.js +0 -352
  701. package/shared-utils/math/rad2Deg.js +0 -12
  702. package/shared-utils/nearlyEqual.js +0 -19
  703. package/shared-utils/nextFrame.js +0 -15
  704. package/shared-utils/noop.js +0 -19
  705. package/shared-utils/object3d2LocalMatrix.js +0 -79
  706. package/shared-utils/px2rem.js +0 -22
  707. package/shared-utils/three/centerPoint.js +0 -14
  708. package/shared-utils/three/getExtraModelLoader.js +0 -45
  709. package/shared-utils/three/getNormal.js +0 -17
  710. package/shared-utils/three/getTextureLoader.js +0 -50
  711. package/shared-utils/three/loadFbxObj.js +0 -54
  712. package/shared-utils/three/loadTexture.d.ts +0 -2
  713. package/shared-utils/three/loadTexture.js +0 -46
  714. package/shared-utils/three/transformPositionToVector3.js +0 -20
  715. package/shared-utils/three/transfromToMeshBasicMaterial.js +0 -33
  716. package/shared-utils/throttle.js +0 -29
  717. package/shared-utils/to.js +0 -67
  718. package/shared-utils/useDebounce.js +0 -49
  719. package/shared-utils/useThrottle.js +0 -47
  720. package/shared-utils/uuid.js +0 -28
  721. package/shared-utils/vectorTocoordinates.js +0 -18
  722. package/typedoc/components.d.ts +0 -6
  723. package/typedoc/components.js +0 -7
  724. package/typedoc/plugins.d.ts +0 -19
  725. package/typedoc/plugins.js +0 -165
  726. package/typedoc/shared-utils.d.ts +0 -3
  727. package/typedoc/shared-utils.js +0 -7
  728. package/typedoc/typings.d.ts +0 -3
  729. package/typedoc/typings.js +0 -7
  730. package/typings/math.type.js +0 -7
  731. package/typings/utils.type.js +0 -7
@@ -0,0 +1,4789 @@
1
+ 'use strict';
2
+
3
+ var three = require('three');
4
+ var line = require('@realsee/five/line');
5
+ var five = require('@realsee/five');
6
+ var TWEEN = require('@tweenjs/tween.js');
7
+
8
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
9
+
10
+ function _mergeNamespaces(n, m) {
11
+ m.forEach(function (e) {
12
+ e && typeof e !== 'string' && !Array.isArray(e) && Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default' && !(k in n)) {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ });
22
+ return Object.freeze(n);
23
+ }
24
+
25
+ var TWEEN__default = /*#__PURE__*/_interopDefaultLegacy(TWEEN);
26
+
27
+ /** 交换数组元素 */
28
+ function exchange(array, index1, index2) {
29
+ const value = array[index1];
30
+ array[index1] = array[index2];
31
+ array[index2] = value;
32
+ }
33
+ class Magnifier {
34
+ five;
35
+ scale;
36
+ width;
37
+ height;
38
+ pixelRatio;
39
+ originWidth;
40
+ originHeight;
41
+ context;
42
+ canvas = document.createElement('canvas');
43
+ container;
44
+ constructor(five, options) {
45
+ if (!five.renderer)
46
+ throw new Error('Five Render 未初始化');
47
+ this.five = five;
48
+ const scale = options.scale;
49
+ const pixelRatio = five.renderer.getPixelRatio();
50
+ const originWidth = options.width;
51
+ const originHeight = options.height;
52
+ const width = originWidth * pixelRatio;
53
+ const height = originHeight * pixelRatio;
54
+ const magnifier = this.canvas;
55
+ const context = this.canvas.getContext('2d');
56
+ if (!context)
57
+ throw new Error('CANNOT CREATE CONTEXT2D');
58
+ this.scale = scale;
59
+ this.context = context;
60
+ this.width = width;
61
+ this.height = height;
62
+ this.originWidth = originWidth;
63
+ this.originHeight = originHeight;
64
+ this.pixelRatio = pixelRatio;
65
+ magnifier.classList.add('plugin-measure-magnifier');
66
+ magnifier.style.position = 'absolute';
67
+ magnifier.style.pointerEvents = 'none';
68
+ magnifier.style.borderRadius = '50%';
69
+ magnifier.style.left = -width / 2 + 'px';
70
+ magnifier.style.top = -height - 90 + 'px';
71
+ magnifier.setAttribute('width', width.toString());
72
+ magnifier.setAttribute('height', height.toString());
73
+ this.canvas.style.width = originWidth + 'px';
74
+ this.canvas.style.height = originHeight + 'px';
75
+ }
76
+ dispose() {
77
+ this.clear();
78
+ this.canvas.remove();
79
+ }
80
+ clear() {
81
+ this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
82
+ }
83
+ appendTo(element) {
84
+ this.container = element;
85
+ element.append(this.canvas);
86
+ }
87
+ updateWithPoint(point) {
88
+ if (!this.five.renderer || !this.container)
89
+ return;
90
+ const { scale, pixelRatio, context, originWidth, originHeight, width, height } = this;
91
+ const position2d = point.clone().project(this.five.camera);
92
+ const left = ((position2d.x + 1) / 2) * this.container.clientWidth;
93
+ const right = (-(position2d.x - 1) / 2) * this.container.clientWidth;
94
+ const top = (-(position2d.y - 1) / 2) * this.container.clientHeight;
95
+ if (left < 183) {
96
+ this.canvas.style.top = -originHeight / 2 + 'px';
97
+ this.canvas.style.left = 90 + 'px';
98
+ }
99
+ else if (top < 183) {
100
+ this.canvas.style.top = 90 + 'px';
101
+ this.canvas.style.left = -originWidth / 2 + 'px';
102
+ }
103
+ else if (right < 183) {
104
+ this.canvas.style.top = -originHeight / 2 + 'px';
105
+ this.canvas.style.left = -originWidth - 90 + 'px';
106
+ }
107
+ else {
108
+ this.canvas.style.left = -originWidth / 2 + 'px';
109
+ this.canvas.style.top = -originHeight - 90 + 'px';
110
+ }
111
+ this.canvas.style.transform = `translate3d(${left}px, ${top}px, 10px)`;
112
+ const renderSize = this.five.renderer.getSize(new three.Vector2());
113
+ const x = ((position2d.x + 1) / 2) * renderSize.x;
114
+ const y = ((position2d.y + 1) / 2) * renderSize.y;
115
+ const pixels = this.five.getPixels(x - originWidth / scale / 2, y - originHeight / scale / 2, originWidth / scale, originHeight / scale, pixelRatio * scale);
116
+ const length = (width * height) / 2;
117
+ for (let index = 0; index < length; index++) {
118
+ const targetIndex = (height - Math.floor(index / width) - 1) * width + (index % width);
119
+ exchange(pixels, index * 4 + 0, targetIndex * 4 + 0);
120
+ exchange(pixels, index * 4 + 1, targetIndex * 4 + 1);
121
+ exchange(pixels, index * 4 + 2, targetIndex * 4 + 2);
122
+ exchange(pixels, index * 4 + 3, targetIndex * 4 + 3);
123
+ }
124
+ const imageData = context.createImageData(width, height);
125
+ imageData.data.set(pixels);
126
+ context.putImageData(imageData, 0, 0);
127
+ }
128
+ }
129
+
130
+ class FiveHelper {
131
+ edges = [];
132
+ five;
133
+ constructor(five) {
134
+ this.five = five;
135
+ this.five.model.loaded ? this.onModelLoaded() : this.five.on('modelLoaded', this.onModelLoaded);
136
+ }
137
+ dispose() { }
138
+ getAdsorbentPoint(intersection) {
139
+ if (this.edges.length === 0)
140
+ return null;
141
+ let distance = Infinity;
142
+ let closestPoint;
143
+ this.edges.forEach((line) => {
144
+ const _closestPoint = line.closestPointToPoint(intersection.point, true, new three.Vector3());
145
+ const _distance = _closestPoint.distanceTo(intersection.point);
146
+ if (_distance < distance) {
147
+ closestPoint = _closestPoint;
148
+ distance = _distance;
149
+ }
150
+ });
151
+ if (distance > 0.1)
152
+ return null;
153
+ return closestPoint || null;
154
+ }
155
+ /** 模型加载后获取折线 */
156
+ onModelLoaded = () => {
157
+ if (!this.five.model)
158
+ return;
159
+ this.edges = this.five.model.getEdges();
160
+ };
161
+ }
162
+
163
+ var hammer = {exports: {}};
164
+
165
+ /*! Hammer.JS - v2.0.7 - 2016-04-22
166
+ * http://hammerjs.github.io/
167
+ *
168
+ * Copyright (c) 2016 Jorik Tangelder;
169
+ * Licensed under the MIT license */
170
+
171
+ (function (module) {
172
+ (function(window, document, exportName, undefined$1) {
173
+
174
+ var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
175
+ var TEST_ELEMENT = document.createElement('div');
176
+
177
+ var TYPE_FUNCTION = 'function';
178
+
179
+ var round = Math.round;
180
+ var abs = Math.abs;
181
+ var now = Date.now;
182
+
183
+ /**
184
+ * set a timeout with a given scope
185
+ * @param {Function} fn
186
+ * @param {Number} timeout
187
+ * @param {Object} context
188
+ * @returns {number}
189
+ */
190
+ function setTimeoutContext(fn, timeout, context) {
191
+ return setTimeout(bindFn(fn, context), timeout);
192
+ }
193
+
194
+ /**
195
+ * if the argument is an array, we want to execute the fn on each entry
196
+ * if it aint an array we don't want to do a thing.
197
+ * this is used by all the methods that accept a single and array argument.
198
+ * @param {*|Array} arg
199
+ * @param {String} fn
200
+ * @param {Object} [context]
201
+ * @returns {Boolean}
202
+ */
203
+ function invokeArrayArg(arg, fn, context) {
204
+ if (Array.isArray(arg)) {
205
+ each(arg, context[fn], context);
206
+ return true;
207
+ }
208
+ return false;
209
+ }
210
+
211
+ /**
212
+ * walk objects and arrays
213
+ * @param {Object} obj
214
+ * @param {Function} iterator
215
+ * @param {Object} context
216
+ */
217
+ function each(obj, iterator, context) {
218
+ var i;
219
+
220
+ if (!obj) {
221
+ return;
222
+ }
223
+
224
+ if (obj.forEach) {
225
+ obj.forEach(iterator, context);
226
+ } else if (obj.length !== undefined$1) {
227
+ i = 0;
228
+ while (i < obj.length) {
229
+ iterator.call(context, obj[i], i, obj);
230
+ i++;
231
+ }
232
+ } else {
233
+ for (i in obj) {
234
+ obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
235
+ }
236
+ }
237
+ }
238
+
239
+ /**
240
+ * wrap a method with a deprecation warning and stack trace
241
+ * @param {Function} method
242
+ * @param {String} name
243
+ * @param {String} message
244
+ * @returns {Function} A new function wrapping the supplied method.
245
+ */
246
+ function deprecate(method, name, message) {
247
+ var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n';
248
+ return function() {
249
+ var e = new Error('get-stack-trace');
250
+ var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '')
251
+ .replace(/^\s+at\s+/gm, '')
252
+ .replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
253
+
254
+ var log = window.console && (window.console.warn || window.console.log);
255
+ if (log) {
256
+ log.call(window.console, deprecationMessage, stack);
257
+ }
258
+ return method.apply(this, arguments);
259
+ };
260
+ }
261
+
262
+ /**
263
+ * extend object.
264
+ * means that properties in dest will be overwritten by the ones in src.
265
+ * @param {Object} target
266
+ * @param {...Object} objects_to_assign
267
+ * @returns {Object} target
268
+ */
269
+ var assign;
270
+ if (typeof Object.assign !== 'function') {
271
+ assign = function assign(target) {
272
+ if (target === undefined$1 || target === null) {
273
+ throw new TypeError('Cannot convert undefined or null to object');
274
+ }
275
+
276
+ var output = Object(target);
277
+ for (var index = 1; index < arguments.length; index++) {
278
+ var source = arguments[index];
279
+ if (source !== undefined$1 && source !== null) {
280
+ for (var nextKey in source) {
281
+ if (source.hasOwnProperty(nextKey)) {
282
+ output[nextKey] = source[nextKey];
283
+ }
284
+ }
285
+ }
286
+ }
287
+ return output;
288
+ };
289
+ } else {
290
+ assign = Object.assign;
291
+ }
292
+
293
+ /**
294
+ * extend object.
295
+ * means that properties in dest will be overwritten by the ones in src.
296
+ * @param {Object} dest
297
+ * @param {Object} src
298
+ * @param {Boolean} [merge=false]
299
+ * @returns {Object} dest
300
+ */
301
+ var extend = deprecate(function extend(dest, src, merge) {
302
+ var keys = Object.keys(src);
303
+ var i = 0;
304
+ while (i < keys.length) {
305
+ if (!merge || (merge && dest[keys[i]] === undefined$1)) {
306
+ dest[keys[i]] = src[keys[i]];
307
+ }
308
+ i++;
309
+ }
310
+ return dest;
311
+ }, 'extend', 'Use `assign`.');
312
+
313
+ /**
314
+ * merge the values from src in the dest.
315
+ * means that properties that exist in dest will not be overwritten by src
316
+ * @param {Object} dest
317
+ * @param {Object} src
318
+ * @returns {Object} dest
319
+ */
320
+ var merge = deprecate(function merge(dest, src) {
321
+ return extend(dest, src, true);
322
+ }, 'merge', 'Use `assign`.');
323
+
324
+ /**
325
+ * simple class inheritance
326
+ * @param {Function} child
327
+ * @param {Function} base
328
+ * @param {Object} [properties]
329
+ */
330
+ function inherit(child, base, properties) {
331
+ var baseP = base.prototype,
332
+ childP;
333
+
334
+ childP = child.prototype = Object.create(baseP);
335
+ childP.constructor = child;
336
+ childP._super = baseP;
337
+
338
+ if (properties) {
339
+ assign(childP, properties);
340
+ }
341
+ }
342
+
343
+ /**
344
+ * simple function bind
345
+ * @param {Function} fn
346
+ * @param {Object} context
347
+ * @returns {Function}
348
+ */
349
+ function bindFn(fn, context) {
350
+ return function boundFn() {
351
+ return fn.apply(context, arguments);
352
+ };
353
+ }
354
+
355
+ /**
356
+ * let a boolean value also be a function that must return a boolean
357
+ * this first item in args will be used as the context
358
+ * @param {Boolean|Function} val
359
+ * @param {Array} [args]
360
+ * @returns {Boolean}
361
+ */
362
+ function boolOrFn(val, args) {
363
+ if (typeof val == TYPE_FUNCTION) {
364
+ return val.apply(args ? args[0] || undefined$1 : undefined$1, args);
365
+ }
366
+ return val;
367
+ }
368
+
369
+ /**
370
+ * use the val2 when val1 is undefined
371
+ * @param {*} val1
372
+ * @param {*} val2
373
+ * @returns {*}
374
+ */
375
+ function ifUndefined(val1, val2) {
376
+ return (val1 === undefined$1) ? val2 : val1;
377
+ }
378
+
379
+ /**
380
+ * addEventListener with multiple events at once
381
+ * @param {EventTarget} target
382
+ * @param {String} types
383
+ * @param {Function} handler
384
+ */
385
+ function addEventListeners(target, types, handler) {
386
+ each(splitStr(types), function(type) {
387
+ target.addEventListener(type, handler, false);
388
+ });
389
+ }
390
+
391
+ /**
392
+ * removeEventListener with multiple events at once
393
+ * @param {EventTarget} target
394
+ * @param {String} types
395
+ * @param {Function} handler
396
+ */
397
+ function removeEventListeners(target, types, handler) {
398
+ each(splitStr(types), function(type) {
399
+ target.removeEventListener(type, handler, false);
400
+ });
401
+ }
402
+
403
+ /**
404
+ * find if a node is in the given parent
405
+ * @method hasParent
406
+ * @param {HTMLElement} node
407
+ * @param {HTMLElement} parent
408
+ * @return {Boolean} found
409
+ */
410
+ function hasParent(node, parent) {
411
+ while (node) {
412
+ if (node == parent) {
413
+ return true;
414
+ }
415
+ node = node.parentNode;
416
+ }
417
+ return false;
418
+ }
419
+
420
+ /**
421
+ * small indexOf wrapper
422
+ * @param {String} str
423
+ * @param {String} find
424
+ * @returns {Boolean} found
425
+ */
426
+ function inStr(str, find) {
427
+ return str.indexOf(find) > -1;
428
+ }
429
+
430
+ /**
431
+ * split string on whitespace
432
+ * @param {String} str
433
+ * @returns {Array} words
434
+ */
435
+ function splitStr(str) {
436
+ return str.trim().split(/\s+/g);
437
+ }
438
+
439
+ /**
440
+ * find if a array contains the object using indexOf or a simple polyFill
441
+ * @param {Array} src
442
+ * @param {String} find
443
+ * @param {String} [findByKey]
444
+ * @return {Boolean|Number} false when not found, or the index
445
+ */
446
+ function inArray(src, find, findByKey) {
447
+ if (src.indexOf && !findByKey) {
448
+ return src.indexOf(find);
449
+ } else {
450
+ var i = 0;
451
+ while (i < src.length) {
452
+ if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
453
+ return i;
454
+ }
455
+ i++;
456
+ }
457
+ return -1;
458
+ }
459
+ }
460
+
461
+ /**
462
+ * convert array-like objects to real arrays
463
+ * @param {Object} obj
464
+ * @returns {Array}
465
+ */
466
+ function toArray(obj) {
467
+ return Array.prototype.slice.call(obj, 0);
468
+ }
469
+
470
+ /**
471
+ * unique array with objects based on a key (like 'id') or just by the array's value
472
+ * @param {Array} src [{id:1},{id:2},{id:1}]
473
+ * @param {String} [key]
474
+ * @param {Boolean} [sort=False]
475
+ * @returns {Array} [{id:1},{id:2}]
476
+ */
477
+ function uniqueArray(src, key, sort) {
478
+ var results = [];
479
+ var values = [];
480
+ var i = 0;
481
+
482
+ while (i < src.length) {
483
+ var val = key ? src[i][key] : src[i];
484
+ if (inArray(values, val) < 0) {
485
+ results.push(src[i]);
486
+ }
487
+ values[i] = val;
488
+ i++;
489
+ }
490
+
491
+ if (sort) {
492
+ if (!key) {
493
+ results = results.sort();
494
+ } else {
495
+ results = results.sort(function sortUniqueArray(a, b) {
496
+ return a[key] > b[key];
497
+ });
498
+ }
499
+ }
500
+
501
+ return results;
502
+ }
503
+
504
+ /**
505
+ * get the prefixed property
506
+ * @param {Object} obj
507
+ * @param {String} property
508
+ * @returns {String|Undefined} prefixed
509
+ */
510
+ function prefixed(obj, property) {
511
+ var prefix, prop;
512
+ var camelProp = property[0].toUpperCase() + property.slice(1);
513
+
514
+ var i = 0;
515
+ while (i < VENDOR_PREFIXES.length) {
516
+ prefix = VENDOR_PREFIXES[i];
517
+ prop = (prefix) ? prefix + camelProp : property;
518
+
519
+ if (prop in obj) {
520
+ return prop;
521
+ }
522
+ i++;
523
+ }
524
+ return undefined$1;
525
+ }
526
+
527
+ /**
528
+ * get a unique id
529
+ * @returns {number} uniqueId
530
+ */
531
+ var _uniqueId = 1;
532
+ function uniqueId() {
533
+ return _uniqueId++;
534
+ }
535
+
536
+ /**
537
+ * get the window object of an element
538
+ * @param {HTMLElement} element
539
+ * @returns {DocumentView|Window}
540
+ */
541
+ function getWindowForElement(element) {
542
+ var doc = element.ownerDocument || element;
543
+ return (doc.defaultView || doc.parentWindow || window);
544
+ }
545
+
546
+ var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
547
+
548
+ var SUPPORT_TOUCH = ('ontouchstart' in window);
549
+ var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined$1;
550
+ var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
551
+
552
+ var INPUT_TYPE_TOUCH = 'touch';
553
+ var INPUT_TYPE_PEN = 'pen';
554
+ var INPUT_TYPE_MOUSE = 'mouse';
555
+ var INPUT_TYPE_KINECT = 'kinect';
556
+
557
+ var COMPUTE_INTERVAL = 25;
558
+
559
+ var INPUT_START = 1;
560
+ var INPUT_MOVE = 2;
561
+ var INPUT_END = 4;
562
+ var INPUT_CANCEL = 8;
563
+
564
+ var DIRECTION_NONE = 1;
565
+ var DIRECTION_LEFT = 2;
566
+ var DIRECTION_RIGHT = 4;
567
+ var DIRECTION_UP = 8;
568
+ var DIRECTION_DOWN = 16;
569
+
570
+ var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
571
+ var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
572
+ var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
573
+
574
+ var PROPS_XY = ['x', 'y'];
575
+ var PROPS_CLIENT_XY = ['clientX', 'clientY'];
576
+
577
+ /**
578
+ * create new input type manager
579
+ * @param {Manager} manager
580
+ * @param {Function} callback
581
+ * @returns {Input}
582
+ * @constructor
583
+ */
584
+ function Input(manager, callback) {
585
+ var self = this;
586
+ this.manager = manager;
587
+ this.callback = callback;
588
+ this.element = manager.element;
589
+ this.target = manager.options.inputTarget;
590
+
591
+ // smaller wrapper around the handler, for the scope and the enabled state of the manager,
592
+ // so when disabled the input events are completely bypassed.
593
+ this.domHandler = function(ev) {
594
+ if (boolOrFn(manager.options.enable, [manager])) {
595
+ self.handler(ev);
596
+ }
597
+ };
598
+
599
+ this.init();
600
+
601
+ }
602
+
603
+ Input.prototype = {
604
+ /**
605
+ * should handle the inputEvent data and trigger the callback
606
+ * @virtual
607
+ */
608
+ handler: function() { },
609
+
610
+ /**
611
+ * bind the events
612
+ */
613
+ init: function() {
614
+ this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
615
+ this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
616
+ this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
617
+ },
618
+
619
+ /**
620
+ * unbind the events
621
+ */
622
+ destroy: function() {
623
+ this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
624
+ this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
625
+ this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
626
+ }
627
+ };
628
+
629
+ /**
630
+ * create new input type manager
631
+ * called by the Manager constructor
632
+ * @param {Hammer} manager
633
+ * @returns {Input}
634
+ */
635
+ function createInputInstance(manager) {
636
+ var Type;
637
+ var inputClass = manager.options.inputClass;
638
+
639
+ if (inputClass) {
640
+ Type = inputClass;
641
+ } else if (SUPPORT_POINTER_EVENTS) {
642
+ Type = PointerEventInput;
643
+ } else if (SUPPORT_ONLY_TOUCH) {
644
+ Type = TouchInput;
645
+ } else if (!SUPPORT_TOUCH) {
646
+ Type = MouseInput;
647
+ } else {
648
+ Type = TouchMouseInput;
649
+ }
650
+ return new (Type)(manager, inputHandler);
651
+ }
652
+
653
+ /**
654
+ * handle input events
655
+ * @param {Manager} manager
656
+ * @param {String} eventType
657
+ * @param {Object} input
658
+ */
659
+ function inputHandler(manager, eventType, input) {
660
+ var pointersLen = input.pointers.length;
661
+ var changedPointersLen = input.changedPointers.length;
662
+ var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
663
+ var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
664
+
665
+ input.isFirst = !!isFirst;
666
+ input.isFinal = !!isFinal;
667
+
668
+ if (isFirst) {
669
+ manager.session = {};
670
+ }
671
+
672
+ // source event is the normalized value of the domEvents
673
+ // like 'touchstart, mouseup, pointerdown'
674
+ input.eventType = eventType;
675
+
676
+ // compute scale, rotation etc
677
+ computeInputData(manager, input);
678
+
679
+ // emit secret event
680
+ manager.emit('hammer.input', input);
681
+
682
+ manager.recognize(input);
683
+ manager.session.prevInput = input;
684
+ }
685
+
686
+ /**
687
+ * extend the data with some usable properties like scale, rotate, velocity etc
688
+ * @param {Object} manager
689
+ * @param {Object} input
690
+ */
691
+ function computeInputData(manager, input) {
692
+ var session = manager.session;
693
+ var pointers = input.pointers;
694
+ var pointersLength = pointers.length;
695
+
696
+ // store the first input to calculate the distance and direction
697
+ if (!session.firstInput) {
698
+ session.firstInput = simpleCloneInputData(input);
699
+ }
700
+
701
+ // to compute scale and rotation we need to store the multiple touches
702
+ if (pointersLength > 1 && !session.firstMultiple) {
703
+ session.firstMultiple = simpleCloneInputData(input);
704
+ } else if (pointersLength === 1) {
705
+ session.firstMultiple = false;
706
+ }
707
+
708
+ var firstInput = session.firstInput;
709
+ var firstMultiple = session.firstMultiple;
710
+ var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
711
+
712
+ var center = input.center = getCenter(pointers);
713
+ input.timeStamp = now();
714
+ input.deltaTime = input.timeStamp - firstInput.timeStamp;
715
+
716
+ input.angle = getAngle(offsetCenter, center);
717
+ input.distance = getDistance(offsetCenter, center);
718
+
719
+ computeDeltaXY(session, input);
720
+ input.offsetDirection = getDirection(input.deltaX, input.deltaY);
721
+
722
+ var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
723
+ input.overallVelocityX = overallVelocity.x;
724
+ input.overallVelocityY = overallVelocity.y;
725
+ input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y;
726
+
727
+ input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
728
+ input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
729
+
730
+ input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length >
731
+ session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers);
732
+
733
+ computeIntervalInputData(session, input);
734
+
735
+ // find the correct target
736
+ var target = manager.element;
737
+ if (hasParent(input.srcEvent.target, target)) {
738
+ target = input.srcEvent.target;
739
+ }
740
+ input.target = target;
741
+ }
742
+
743
+ function computeDeltaXY(session, input) {
744
+ var center = input.center;
745
+ var offset = session.offsetDelta || {};
746
+ var prevDelta = session.prevDelta || {};
747
+ var prevInput = session.prevInput || {};
748
+
749
+ if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
750
+ prevDelta = session.prevDelta = {
751
+ x: prevInput.deltaX || 0,
752
+ y: prevInput.deltaY || 0
753
+ };
754
+
755
+ offset = session.offsetDelta = {
756
+ x: center.x,
757
+ y: center.y
758
+ };
759
+ }
760
+
761
+ input.deltaX = prevDelta.x + (center.x - offset.x);
762
+ input.deltaY = prevDelta.y + (center.y - offset.y);
763
+ }
764
+
765
+ /**
766
+ * velocity is calculated every x ms
767
+ * @param {Object} session
768
+ * @param {Object} input
769
+ */
770
+ function computeIntervalInputData(session, input) {
771
+ var last = session.lastInterval || input,
772
+ deltaTime = input.timeStamp - last.timeStamp,
773
+ velocity, velocityX, velocityY, direction;
774
+
775
+ if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined$1)) {
776
+ var deltaX = input.deltaX - last.deltaX;
777
+ var deltaY = input.deltaY - last.deltaY;
778
+
779
+ var v = getVelocity(deltaTime, deltaX, deltaY);
780
+ velocityX = v.x;
781
+ velocityY = v.y;
782
+ velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
783
+ direction = getDirection(deltaX, deltaY);
784
+
785
+ session.lastInterval = input;
786
+ } else {
787
+ // use latest velocity info if it doesn't overtake a minimum period
788
+ velocity = last.velocity;
789
+ velocityX = last.velocityX;
790
+ velocityY = last.velocityY;
791
+ direction = last.direction;
792
+ }
793
+
794
+ input.velocity = velocity;
795
+ input.velocityX = velocityX;
796
+ input.velocityY = velocityY;
797
+ input.direction = direction;
798
+ }
799
+
800
+ /**
801
+ * create a simple clone from the input used for storage of firstInput and firstMultiple
802
+ * @param {Object} input
803
+ * @returns {Object} clonedInputData
804
+ */
805
+ function simpleCloneInputData(input) {
806
+ // make a simple copy of the pointers because we will get a reference if we don't
807
+ // we only need clientXY for the calculations
808
+ var pointers = [];
809
+ var i = 0;
810
+ while (i < input.pointers.length) {
811
+ pointers[i] = {
812
+ clientX: round(input.pointers[i].clientX),
813
+ clientY: round(input.pointers[i].clientY)
814
+ };
815
+ i++;
816
+ }
817
+
818
+ return {
819
+ timeStamp: now(),
820
+ pointers: pointers,
821
+ center: getCenter(pointers),
822
+ deltaX: input.deltaX,
823
+ deltaY: input.deltaY
824
+ };
825
+ }
826
+
827
+ /**
828
+ * get the center of all the pointers
829
+ * @param {Array} pointers
830
+ * @return {Object} center contains `x` and `y` properties
831
+ */
832
+ function getCenter(pointers) {
833
+ var pointersLength = pointers.length;
834
+
835
+ // no need to loop when only one touch
836
+ if (pointersLength === 1) {
837
+ return {
838
+ x: round(pointers[0].clientX),
839
+ y: round(pointers[0].clientY)
840
+ };
841
+ }
842
+
843
+ var x = 0, y = 0, i = 0;
844
+ while (i < pointersLength) {
845
+ x += pointers[i].clientX;
846
+ y += pointers[i].clientY;
847
+ i++;
848
+ }
849
+
850
+ return {
851
+ x: round(x / pointersLength),
852
+ y: round(y / pointersLength)
853
+ };
854
+ }
855
+
856
+ /**
857
+ * calculate the velocity between two points. unit is in px per ms.
858
+ * @param {Number} deltaTime
859
+ * @param {Number} x
860
+ * @param {Number} y
861
+ * @return {Object} velocity `x` and `y`
862
+ */
863
+ function getVelocity(deltaTime, x, y) {
864
+ return {
865
+ x: x / deltaTime || 0,
866
+ y: y / deltaTime || 0
867
+ };
868
+ }
869
+
870
+ /**
871
+ * get the direction between two points
872
+ * @param {Number} x
873
+ * @param {Number} y
874
+ * @return {Number} direction
875
+ */
876
+ function getDirection(x, y) {
877
+ if (x === y) {
878
+ return DIRECTION_NONE;
879
+ }
880
+
881
+ if (abs(x) >= abs(y)) {
882
+ return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
883
+ }
884
+ return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
885
+ }
886
+
887
+ /**
888
+ * calculate the absolute distance between two points
889
+ * @param {Object} p1 {x, y}
890
+ * @param {Object} p2 {x, y}
891
+ * @param {Array} [props] containing x and y keys
892
+ * @return {Number} distance
893
+ */
894
+ function getDistance(p1, p2, props) {
895
+ if (!props) {
896
+ props = PROPS_XY;
897
+ }
898
+ var x = p2[props[0]] - p1[props[0]],
899
+ y = p2[props[1]] - p1[props[1]];
900
+
901
+ return Math.sqrt((x * x) + (y * y));
902
+ }
903
+
904
+ /**
905
+ * calculate the angle between two coordinates
906
+ * @param {Object} p1
907
+ * @param {Object} p2
908
+ * @param {Array} [props] containing x and y keys
909
+ * @return {Number} angle
910
+ */
911
+ function getAngle(p1, p2, props) {
912
+ if (!props) {
913
+ props = PROPS_XY;
914
+ }
915
+ var x = p2[props[0]] - p1[props[0]],
916
+ y = p2[props[1]] - p1[props[1]];
917
+ return Math.atan2(y, x) * 180 / Math.PI;
918
+ }
919
+
920
+ /**
921
+ * calculate the rotation degrees between two pointersets
922
+ * @param {Array} start array of pointers
923
+ * @param {Array} end array of pointers
924
+ * @return {Number} rotation
925
+ */
926
+ function getRotation(start, end) {
927
+ return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
928
+ }
929
+
930
+ /**
931
+ * calculate the scale factor between two pointersets
932
+ * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
933
+ * @param {Array} start array of pointers
934
+ * @param {Array} end array of pointers
935
+ * @return {Number} scale
936
+ */
937
+ function getScale(start, end) {
938
+ return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
939
+ }
940
+
941
+ var MOUSE_INPUT_MAP = {
942
+ mousedown: INPUT_START,
943
+ mousemove: INPUT_MOVE,
944
+ mouseup: INPUT_END
945
+ };
946
+
947
+ var MOUSE_ELEMENT_EVENTS = 'mousedown';
948
+ var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
949
+
950
+ /**
951
+ * Mouse events input
952
+ * @constructor
953
+ * @extends Input
954
+ */
955
+ function MouseInput() {
956
+ this.evEl = MOUSE_ELEMENT_EVENTS;
957
+ this.evWin = MOUSE_WINDOW_EVENTS;
958
+
959
+ this.pressed = false; // mousedown state
960
+
961
+ Input.apply(this, arguments);
962
+ }
963
+
964
+ inherit(MouseInput, Input, {
965
+ /**
966
+ * handle mouse events
967
+ * @param {Object} ev
968
+ */
969
+ handler: function MEhandler(ev) {
970
+ var eventType = MOUSE_INPUT_MAP[ev.type];
971
+
972
+ // on start we want to have the left mouse button down
973
+ if (eventType & INPUT_START && ev.button === 0) {
974
+ this.pressed = true;
975
+ }
976
+
977
+ if (eventType & INPUT_MOVE && ev.which !== 1) {
978
+ eventType = INPUT_END;
979
+ }
980
+
981
+ // mouse must be down
982
+ if (!this.pressed) {
983
+ return;
984
+ }
985
+
986
+ if (eventType & INPUT_END) {
987
+ this.pressed = false;
988
+ }
989
+
990
+ this.callback(this.manager, eventType, {
991
+ pointers: [ev],
992
+ changedPointers: [ev],
993
+ pointerType: INPUT_TYPE_MOUSE,
994
+ srcEvent: ev
995
+ });
996
+ }
997
+ });
998
+
999
+ var POINTER_INPUT_MAP = {
1000
+ pointerdown: INPUT_START,
1001
+ pointermove: INPUT_MOVE,
1002
+ pointerup: INPUT_END,
1003
+ pointercancel: INPUT_CANCEL,
1004
+ pointerout: INPUT_CANCEL
1005
+ };
1006
+
1007
+ // in IE10 the pointer types is defined as an enum
1008
+ var IE10_POINTER_TYPE_ENUM = {
1009
+ 2: INPUT_TYPE_TOUCH,
1010
+ 3: INPUT_TYPE_PEN,
1011
+ 4: INPUT_TYPE_MOUSE,
1012
+ 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
1013
+ };
1014
+
1015
+ var POINTER_ELEMENT_EVENTS = 'pointerdown';
1016
+ var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
1017
+
1018
+ // IE10 has prefixed support, and case-sensitive
1019
+ if (window.MSPointerEvent && !window.PointerEvent) {
1020
+ POINTER_ELEMENT_EVENTS = 'MSPointerDown';
1021
+ POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
1022
+ }
1023
+
1024
+ /**
1025
+ * Pointer events input
1026
+ * @constructor
1027
+ * @extends Input
1028
+ */
1029
+ function PointerEventInput() {
1030
+ this.evEl = POINTER_ELEMENT_EVENTS;
1031
+ this.evWin = POINTER_WINDOW_EVENTS;
1032
+
1033
+ Input.apply(this, arguments);
1034
+
1035
+ this.store = (this.manager.session.pointerEvents = []);
1036
+ }
1037
+
1038
+ inherit(PointerEventInput, Input, {
1039
+ /**
1040
+ * handle mouse events
1041
+ * @param {Object} ev
1042
+ */
1043
+ handler: function PEhandler(ev) {
1044
+ var store = this.store;
1045
+ var removePointer = false;
1046
+
1047
+ var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
1048
+ var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
1049
+ var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
1050
+
1051
+ var isTouch = (pointerType == INPUT_TYPE_TOUCH);
1052
+
1053
+ // get index of the event in the store
1054
+ var storeIndex = inArray(store, ev.pointerId, 'pointerId');
1055
+
1056
+ // start and mouse must be down
1057
+ if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
1058
+ if (storeIndex < 0) {
1059
+ store.push(ev);
1060
+ storeIndex = store.length - 1;
1061
+ }
1062
+ } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
1063
+ removePointer = true;
1064
+ }
1065
+
1066
+ // it not found, so the pointer hasn't been down (so it's probably a hover)
1067
+ if (storeIndex < 0) {
1068
+ return;
1069
+ }
1070
+
1071
+ // update the event in the store
1072
+ store[storeIndex] = ev;
1073
+
1074
+ this.callback(this.manager, eventType, {
1075
+ pointers: store,
1076
+ changedPointers: [ev],
1077
+ pointerType: pointerType,
1078
+ srcEvent: ev
1079
+ });
1080
+
1081
+ if (removePointer) {
1082
+ // remove from the store
1083
+ store.splice(storeIndex, 1);
1084
+ }
1085
+ }
1086
+ });
1087
+
1088
+ var SINGLE_TOUCH_INPUT_MAP = {
1089
+ touchstart: INPUT_START,
1090
+ touchmove: INPUT_MOVE,
1091
+ touchend: INPUT_END,
1092
+ touchcancel: INPUT_CANCEL
1093
+ };
1094
+
1095
+ var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
1096
+ var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
1097
+
1098
+ /**
1099
+ * Touch events input
1100
+ * @constructor
1101
+ * @extends Input
1102
+ */
1103
+ function SingleTouchInput() {
1104
+ this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
1105
+ this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
1106
+ this.started = false;
1107
+
1108
+ Input.apply(this, arguments);
1109
+ }
1110
+
1111
+ inherit(SingleTouchInput, Input, {
1112
+ handler: function TEhandler(ev) {
1113
+ var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
1114
+
1115
+ // should we handle the touch events?
1116
+ if (type === INPUT_START) {
1117
+ this.started = true;
1118
+ }
1119
+
1120
+ if (!this.started) {
1121
+ return;
1122
+ }
1123
+
1124
+ var touches = normalizeSingleTouches.call(this, ev, type);
1125
+
1126
+ // when done, reset the started state
1127
+ if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
1128
+ this.started = false;
1129
+ }
1130
+
1131
+ this.callback(this.manager, type, {
1132
+ pointers: touches[0],
1133
+ changedPointers: touches[1],
1134
+ pointerType: INPUT_TYPE_TOUCH,
1135
+ srcEvent: ev
1136
+ });
1137
+ }
1138
+ });
1139
+
1140
+ /**
1141
+ * @this {TouchInput}
1142
+ * @param {Object} ev
1143
+ * @param {Number} type flag
1144
+ * @returns {undefined|Array} [all, changed]
1145
+ */
1146
+ function normalizeSingleTouches(ev, type) {
1147
+ var all = toArray(ev.touches);
1148
+ var changed = toArray(ev.changedTouches);
1149
+
1150
+ if (type & (INPUT_END | INPUT_CANCEL)) {
1151
+ all = uniqueArray(all.concat(changed), 'identifier', true);
1152
+ }
1153
+
1154
+ return [all, changed];
1155
+ }
1156
+
1157
+ var TOUCH_INPUT_MAP = {
1158
+ touchstart: INPUT_START,
1159
+ touchmove: INPUT_MOVE,
1160
+ touchend: INPUT_END,
1161
+ touchcancel: INPUT_CANCEL
1162
+ };
1163
+
1164
+ var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
1165
+
1166
+ /**
1167
+ * Multi-user touch events input
1168
+ * @constructor
1169
+ * @extends Input
1170
+ */
1171
+ function TouchInput() {
1172
+ this.evTarget = TOUCH_TARGET_EVENTS;
1173
+ this.targetIds = {};
1174
+
1175
+ Input.apply(this, arguments);
1176
+ }
1177
+
1178
+ inherit(TouchInput, Input, {
1179
+ handler: function MTEhandler(ev) {
1180
+ var type = TOUCH_INPUT_MAP[ev.type];
1181
+ var touches = getTouches.call(this, ev, type);
1182
+ if (!touches) {
1183
+ return;
1184
+ }
1185
+
1186
+ this.callback(this.manager, type, {
1187
+ pointers: touches[0],
1188
+ changedPointers: touches[1],
1189
+ pointerType: INPUT_TYPE_TOUCH,
1190
+ srcEvent: ev
1191
+ });
1192
+ }
1193
+ });
1194
+
1195
+ /**
1196
+ * @this {TouchInput}
1197
+ * @param {Object} ev
1198
+ * @param {Number} type flag
1199
+ * @returns {undefined|Array} [all, changed]
1200
+ */
1201
+ function getTouches(ev, type) {
1202
+ var allTouches = toArray(ev.touches);
1203
+ var targetIds = this.targetIds;
1204
+
1205
+ // when there is only one touch, the process can be simplified
1206
+ if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
1207
+ targetIds[allTouches[0].identifier] = true;
1208
+ return [allTouches, allTouches];
1209
+ }
1210
+
1211
+ var i,
1212
+ targetTouches,
1213
+ changedTouches = toArray(ev.changedTouches),
1214
+ changedTargetTouches = [],
1215
+ target = this.target;
1216
+
1217
+ // get target touches from touches
1218
+ targetTouches = allTouches.filter(function(touch) {
1219
+ return hasParent(touch.target, target);
1220
+ });
1221
+
1222
+ // collect touches
1223
+ if (type === INPUT_START) {
1224
+ i = 0;
1225
+ while (i < targetTouches.length) {
1226
+ targetIds[targetTouches[i].identifier] = true;
1227
+ i++;
1228
+ }
1229
+ }
1230
+
1231
+ // filter changed touches to only contain touches that exist in the collected target ids
1232
+ i = 0;
1233
+ while (i < changedTouches.length) {
1234
+ if (targetIds[changedTouches[i].identifier]) {
1235
+ changedTargetTouches.push(changedTouches[i]);
1236
+ }
1237
+
1238
+ // cleanup removed touches
1239
+ if (type & (INPUT_END | INPUT_CANCEL)) {
1240
+ delete targetIds[changedTouches[i].identifier];
1241
+ }
1242
+ i++;
1243
+ }
1244
+
1245
+ if (!changedTargetTouches.length) {
1246
+ return;
1247
+ }
1248
+
1249
+ return [
1250
+ // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
1251
+ uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
1252
+ changedTargetTouches
1253
+ ];
1254
+ }
1255
+
1256
+ /**
1257
+ * Combined touch and mouse input
1258
+ *
1259
+ * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
1260
+ * This because touch devices also emit mouse events while doing a touch.
1261
+ *
1262
+ * @constructor
1263
+ * @extends Input
1264
+ */
1265
+
1266
+ var DEDUP_TIMEOUT = 2500;
1267
+ var DEDUP_DISTANCE = 25;
1268
+
1269
+ function TouchMouseInput() {
1270
+ Input.apply(this, arguments);
1271
+
1272
+ var handler = bindFn(this.handler, this);
1273
+ this.touch = new TouchInput(this.manager, handler);
1274
+ this.mouse = new MouseInput(this.manager, handler);
1275
+
1276
+ this.primaryTouch = null;
1277
+ this.lastTouches = [];
1278
+ }
1279
+
1280
+ inherit(TouchMouseInput, Input, {
1281
+ /**
1282
+ * handle mouse and touch events
1283
+ * @param {Hammer} manager
1284
+ * @param {String} inputEvent
1285
+ * @param {Object} inputData
1286
+ */
1287
+ handler: function TMEhandler(manager, inputEvent, inputData) {
1288
+ var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
1289
+ isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
1290
+
1291
+ if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
1292
+ return;
1293
+ }
1294
+
1295
+ // when we're in a touch event, record touches to de-dupe synthetic mouse event
1296
+ if (isTouch) {
1297
+ recordTouches.call(this, inputEvent, inputData);
1298
+ } else if (isMouse && isSyntheticEvent.call(this, inputData)) {
1299
+ return;
1300
+ }
1301
+
1302
+ this.callback(manager, inputEvent, inputData);
1303
+ },
1304
+
1305
+ /**
1306
+ * remove the event listeners
1307
+ */
1308
+ destroy: function destroy() {
1309
+ this.touch.destroy();
1310
+ this.mouse.destroy();
1311
+ }
1312
+ });
1313
+
1314
+ function recordTouches(eventType, eventData) {
1315
+ if (eventType & INPUT_START) {
1316
+ this.primaryTouch = eventData.changedPointers[0].identifier;
1317
+ setLastTouch.call(this, eventData);
1318
+ } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
1319
+ setLastTouch.call(this, eventData);
1320
+ }
1321
+ }
1322
+
1323
+ function setLastTouch(eventData) {
1324
+ var touch = eventData.changedPointers[0];
1325
+
1326
+ if (touch.identifier === this.primaryTouch) {
1327
+ var lastTouch = {x: touch.clientX, y: touch.clientY};
1328
+ this.lastTouches.push(lastTouch);
1329
+ var lts = this.lastTouches;
1330
+ var removeLastTouch = function() {
1331
+ var i = lts.indexOf(lastTouch);
1332
+ if (i > -1) {
1333
+ lts.splice(i, 1);
1334
+ }
1335
+ };
1336
+ setTimeout(removeLastTouch, DEDUP_TIMEOUT);
1337
+ }
1338
+ }
1339
+
1340
+ function isSyntheticEvent(eventData) {
1341
+ var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY;
1342
+ for (var i = 0; i < this.lastTouches.length; i++) {
1343
+ var t = this.lastTouches[i];
1344
+ var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
1345
+ if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
1346
+ return true;
1347
+ }
1348
+ }
1349
+ return false;
1350
+ }
1351
+
1352
+ var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
1353
+ var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined$1;
1354
+
1355
+ // magical touchAction value
1356
+ var TOUCH_ACTION_COMPUTE = 'compute';
1357
+ var TOUCH_ACTION_AUTO = 'auto';
1358
+ var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
1359
+ var TOUCH_ACTION_NONE = 'none';
1360
+ var TOUCH_ACTION_PAN_X = 'pan-x';
1361
+ var TOUCH_ACTION_PAN_Y = 'pan-y';
1362
+ var TOUCH_ACTION_MAP = getTouchActionProps();
1363
+
1364
+ /**
1365
+ * Touch Action
1366
+ * sets the touchAction property or uses the js alternative
1367
+ * @param {Manager} manager
1368
+ * @param {String} value
1369
+ * @constructor
1370
+ */
1371
+ function TouchAction(manager, value) {
1372
+ this.manager = manager;
1373
+ this.set(value);
1374
+ }
1375
+
1376
+ TouchAction.prototype = {
1377
+ /**
1378
+ * set the touchAction value on the element or enable the polyfill
1379
+ * @param {String} value
1380
+ */
1381
+ set: function(value) {
1382
+ // find out the touch-action by the event handlers
1383
+ if (value == TOUCH_ACTION_COMPUTE) {
1384
+ value = this.compute();
1385
+ }
1386
+
1387
+ if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
1388
+ this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
1389
+ }
1390
+ this.actions = value.toLowerCase().trim();
1391
+ },
1392
+
1393
+ /**
1394
+ * just re-set the touchAction value
1395
+ */
1396
+ update: function() {
1397
+ this.set(this.manager.options.touchAction);
1398
+ },
1399
+
1400
+ /**
1401
+ * compute the value for the touchAction property based on the recognizer's settings
1402
+ * @returns {String} value
1403
+ */
1404
+ compute: function() {
1405
+ var actions = [];
1406
+ each(this.manager.recognizers, function(recognizer) {
1407
+ if (boolOrFn(recognizer.options.enable, [recognizer])) {
1408
+ actions = actions.concat(recognizer.getTouchAction());
1409
+ }
1410
+ });
1411
+ return cleanTouchActions(actions.join(' '));
1412
+ },
1413
+
1414
+ /**
1415
+ * this method is called on each input cycle and provides the preventing of the browser behavior
1416
+ * @param {Object} input
1417
+ */
1418
+ preventDefaults: function(input) {
1419
+ var srcEvent = input.srcEvent;
1420
+ var direction = input.offsetDirection;
1421
+
1422
+ // if the touch action did prevented once this session
1423
+ if (this.manager.session.prevented) {
1424
+ srcEvent.preventDefault();
1425
+ return;
1426
+ }
1427
+
1428
+ var actions = this.actions;
1429
+ var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
1430
+ var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
1431
+ var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
1432
+
1433
+ if (hasNone) {
1434
+ //do not prevent defaults if this is a tap gesture
1435
+
1436
+ var isTapPointer = input.pointers.length === 1;
1437
+ var isTapMovement = input.distance < 2;
1438
+ var isTapTouchTime = input.deltaTime < 250;
1439
+
1440
+ if (isTapPointer && isTapMovement && isTapTouchTime) {
1441
+ return;
1442
+ }
1443
+ }
1444
+
1445
+ if (hasPanX && hasPanY) {
1446
+ // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
1447
+ return;
1448
+ }
1449
+
1450
+ if (hasNone ||
1451
+ (hasPanY && direction & DIRECTION_HORIZONTAL) ||
1452
+ (hasPanX && direction & DIRECTION_VERTICAL)) {
1453
+ return this.preventSrc(srcEvent);
1454
+ }
1455
+ },
1456
+
1457
+ /**
1458
+ * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
1459
+ * @param {Object} srcEvent
1460
+ */
1461
+ preventSrc: function(srcEvent) {
1462
+ this.manager.session.prevented = true;
1463
+ srcEvent.preventDefault();
1464
+ }
1465
+ };
1466
+
1467
+ /**
1468
+ * when the touchActions are collected they are not a valid value, so we need to clean things up. *
1469
+ * @param {String} actions
1470
+ * @returns {*}
1471
+ */
1472
+ function cleanTouchActions(actions) {
1473
+ // none
1474
+ if (inStr(actions, TOUCH_ACTION_NONE)) {
1475
+ return TOUCH_ACTION_NONE;
1476
+ }
1477
+
1478
+ var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
1479
+ var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
1480
+
1481
+ // if both pan-x and pan-y are set (different recognizers
1482
+ // for different directions, e.g. horizontal pan but vertical swipe?)
1483
+ // we need none (as otherwise with pan-x pan-y combined none of these
1484
+ // recognizers will work, since the browser would handle all panning
1485
+ if (hasPanX && hasPanY) {
1486
+ return TOUCH_ACTION_NONE;
1487
+ }
1488
+
1489
+ // pan-x OR pan-y
1490
+ if (hasPanX || hasPanY) {
1491
+ return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
1492
+ }
1493
+
1494
+ // manipulation
1495
+ if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
1496
+ return TOUCH_ACTION_MANIPULATION;
1497
+ }
1498
+
1499
+ return TOUCH_ACTION_AUTO;
1500
+ }
1501
+
1502
+ function getTouchActionProps() {
1503
+ if (!NATIVE_TOUCH_ACTION) {
1504
+ return false;
1505
+ }
1506
+ var touchMap = {};
1507
+ var cssSupports = window.CSS && window.CSS.supports;
1508
+ ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) {
1509
+
1510
+ // If css.supports is not supported but there is native touch-action assume it supports
1511
+ // all values. This is the case for IE 10 and 11.
1512
+ touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;
1513
+ });
1514
+ return touchMap;
1515
+ }
1516
+
1517
+ /**
1518
+ * Recognizer flow explained; *
1519
+ * All recognizers have the initial state of POSSIBLE when a input session starts.
1520
+ * The definition of a input session is from the first input until the last input, with all it's movement in it. *
1521
+ * Example session for mouse-input: mousedown -> mousemove -> mouseup
1522
+ *
1523
+ * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
1524
+ * which determines with state it should be.
1525
+ *
1526
+ * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
1527
+ * POSSIBLE to give it another change on the next cycle.
1528
+ *
1529
+ * Possible
1530
+ * |
1531
+ * +-----+---------------+
1532
+ * | |
1533
+ * +-----+-----+ |
1534
+ * | | |
1535
+ * Failed Cancelled |
1536
+ * +-------+------+
1537
+ * | |
1538
+ * Recognized Began
1539
+ * |
1540
+ * Changed
1541
+ * |
1542
+ * Ended/Recognized
1543
+ */
1544
+ var STATE_POSSIBLE = 1;
1545
+ var STATE_BEGAN = 2;
1546
+ var STATE_CHANGED = 4;
1547
+ var STATE_ENDED = 8;
1548
+ var STATE_RECOGNIZED = STATE_ENDED;
1549
+ var STATE_CANCELLED = 16;
1550
+ var STATE_FAILED = 32;
1551
+
1552
+ /**
1553
+ * Recognizer
1554
+ * Every recognizer needs to extend from this class.
1555
+ * @constructor
1556
+ * @param {Object} options
1557
+ */
1558
+ function Recognizer(options) {
1559
+ this.options = assign({}, this.defaults, options || {});
1560
+
1561
+ this.id = uniqueId();
1562
+
1563
+ this.manager = null;
1564
+
1565
+ // default is enable true
1566
+ this.options.enable = ifUndefined(this.options.enable, true);
1567
+
1568
+ this.state = STATE_POSSIBLE;
1569
+
1570
+ this.simultaneous = {};
1571
+ this.requireFail = [];
1572
+ }
1573
+
1574
+ Recognizer.prototype = {
1575
+ /**
1576
+ * @virtual
1577
+ * @type {Object}
1578
+ */
1579
+ defaults: {},
1580
+
1581
+ /**
1582
+ * set options
1583
+ * @param {Object} options
1584
+ * @return {Recognizer}
1585
+ */
1586
+ set: function(options) {
1587
+ assign(this.options, options);
1588
+
1589
+ // also update the touchAction, in case something changed about the directions/enabled state
1590
+ this.manager && this.manager.touchAction.update();
1591
+ return this;
1592
+ },
1593
+
1594
+ /**
1595
+ * recognize simultaneous with an other recognizer.
1596
+ * @param {Recognizer} otherRecognizer
1597
+ * @returns {Recognizer} this
1598
+ */
1599
+ recognizeWith: function(otherRecognizer) {
1600
+ if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
1601
+ return this;
1602
+ }
1603
+
1604
+ var simultaneous = this.simultaneous;
1605
+ otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1606
+ if (!simultaneous[otherRecognizer.id]) {
1607
+ simultaneous[otherRecognizer.id] = otherRecognizer;
1608
+ otherRecognizer.recognizeWith(this);
1609
+ }
1610
+ return this;
1611
+ },
1612
+
1613
+ /**
1614
+ * drop the simultaneous link. it doesnt remove the link on the other recognizer.
1615
+ * @param {Recognizer} otherRecognizer
1616
+ * @returns {Recognizer} this
1617
+ */
1618
+ dropRecognizeWith: function(otherRecognizer) {
1619
+ if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
1620
+ return this;
1621
+ }
1622
+
1623
+ otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1624
+ delete this.simultaneous[otherRecognizer.id];
1625
+ return this;
1626
+ },
1627
+
1628
+ /**
1629
+ * recognizer can only run when an other is failing
1630
+ * @param {Recognizer} otherRecognizer
1631
+ * @returns {Recognizer} this
1632
+ */
1633
+ requireFailure: function(otherRecognizer) {
1634
+ if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
1635
+ return this;
1636
+ }
1637
+
1638
+ var requireFail = this.requireFail;
1639
+ otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1640
+ if (inArray(requireFail, otherRecognizer) === -1) {
1641
+ requireFail.push(otherRecognizer);
1642
+ otherRecognizer.requireFailure(this);
1643
+ }
1644
+ return this;
1645
+ },
1646
+
1647
+ /**
1648
+ * drop the requireFailure link. it does not remove the link on the other recognizer.
1649
+ * @param {Recognizer} otherRecognizer
1650
+ * @returns {Recognizer} this
1651
+ */
1652
+ dropRequireFailure: function(otherRecognizer) {
1653
+ if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
1654
+ return this;
1655
+ }
1656
+
1657
+ otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
1658
+ var index = inArray(this.requireFail, otherRecognizer);
1659
+ if (index > -1) {
1660
+ this.requireFail.splice(index, 1);
1661
+ }
1662
+ return this;
1663
+ },
1664
+
1665
+ /**
1666
+ * has require failures boolean
1667
+ * @returns {boolean}
1668
+ */
1669
+ hasRequireFailures: function() {
1670
+ return this.requireFail.length > 0;
1671
+ },
1672
+
1673
+ /**
1674
+ * if the recognizer can recognize simultaneous with an other recognizer
1675
+ * @param {Recognizer} otherRecognizer
1676
+ * @returns {Boolean}
1677
+ */
1678
+ canRecognizeWith: function(otherRecognizer) {
1679
+ return !!this.simultaneous[otherRecognizer.id];
1680
+ },
1681
+
1682
+ /**
1683
+ * You should use `tryEmit` instead of `emit` directly to check
1684
+ * that all the needed recognizers has failed before emitting.
1685
+ * @param {Object} input
1686
+ */
1687
+ emit: function(input) {
1688
+ var self = this;
1689
+ var state = this.state;
1690
+
1691
+ function emit(event) {
1692
+ self.manager.emit(event, input);
1693
+ }
1694
+
1695
+ // 'panstart' and 'panmove'
1696
+ if (state < STATE_ENDED) {
1697
+ emit(self.options.event + stateStr(state));
1698
+ }
1699
+
1700
+ emit(self.options.event); // simple 'eventName' events
1701
+
1702
+ if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...)
1703
+ emit(input.additionalEvent);
1704
+ }
1705
+
1706
+ // panend and pancancel
1707
+ if (state >= STATE_ENDED) {
1708
+ emit(self.options.event + stateStr(state));
1709
+ }
1710
+ },
1711
+
1712
+ /**
1713
+ * Check that all the require failure recognizers has failed,
1714
+ * if true, it emits a gesture event,
1715
+ * otherwise, setup the state to FAILED.
1716
+ * @param {Object} input
1717
+ */
1718
+ tryEmit: function(input) {
1719
+ if (this.canEmit()) {
1720
+ return this.emit(input);
1721
+ }
1722
+ // it's failing anyway
1723
+ this.state = STATE_FAILED;
1724
+ },
1725
+
1726
+ /**
1727
+ * can we emit?
1728
+ * @returns {boolean}
1729
+ */
1730
+ canEmit: function() {
1731
+ var i = 0;
1732
+ while (i < this.requireFail.length) {
1733
+ if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
1734
+ return false;
1735
+ }
1736
+ i++;
1737
+ }
1738
+ return true;
1739
+ },
1740
+
1741
+ /**
1742
+ * update the recognizer
1743
+ * @param {Object} inputData
1744
+ */
1745
+ recognize: function(inputData) {
1746
+ // make a new copy of the inputData
1747
+ // so we can change the inputData without messing up the other recognizers
1748
+ var inputDataClone = assign({}, inputData);
1749
+
1750
+ // is is enabled and allow recognizing?
1751
+ if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
1752
+ this.reset();
1753
+ this.state = STATE_FAILED;
1754
+ return;
1755
+ }
1756
+
1757
+ // reset when we've reached the end
1758
+ if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
1759
+ this.state = STATE_POSSIBLE;
1760
+ }
1761
+
1762
+ this.state = this.process(inputDataClone);
1763
+
1764
+ // the recognizer has recognized a gesture
1765
+ // so trigger an event
1766
+ if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
1767
+ this.tryEmit(inputDataClone);
1768
+ }
1769
+ },
1770
+
1771
+ /**
1772
+ * return the state of the recognizer
1773
+ * the actual recognizing happens in this method
1774
+ * @virtual
1775
+ * @param {Object} inputData
1776
+ * @returns {Const} STATE
1777
+ */
1778
+ process: function(inputData) { }, // jshint ignore:line
1779
+
1780
+ /**
1781
+ * return the preferred touch-action
1782
+ * @virtual
1783
+ * @returns {Array}
1784
+ */
1785
+ getTouchAction: function() { },
1786
+
1787
+ /**
1788
+ * called when the gesture isn't allowed to recognize
1789
+ * like when another is being recognized or it is disabled
1790
+ * @virtual
1791
+ */
1792
+ reset: function() { }
1793
+ };
1794
+
1795
+ /**
1796
+ * get a usable string, used as event postfix
1797
+ * @param {Const} state
1798
+ * @returns {String} state
1799
+ */
1800
+ function stateStr(state) {
1801
+ if (state & STATE_CANCELLED) {
1802
+ return 'cancel';
1803
+ } else if (state & STATE_ENDED) {
1804
+ return 'end';
1805
+ } else if (state & STATE_CHANGED) {
1806
+ return 'move';
1807
+ } else if (state & STATE_BEGAN) {
1808
+ return 'start';
1809
+ }
1810
+ return '';
1811
+ }
1812
+
1813
+ /**
1814
+ * direction cons to string
1815
+ * @param {Const} direction
1816
+ * @returns {String}
1817
+ */
1818
+ function directionStr(direction) {
1819
+ if (direction == DIRECTION_DOWN) {
1820
+ return 'down';
1821
+ } else if (direction == DIRECTION_UP) {
1822
+ return 'up';
1823
+ } else if (direction == DIRECTION_LEFT) {
1824
+ return 'left';
1825
+ } else if (direction == DIRECTION_RIGHT) {
1826
+ return 'right';
1827
+ }
1828
+ return '';
1829
+ }
1830
+
1831
+ /**
1832
+ * get a recognizer by name if it is bound to a manager
1833
+ * @param {Recognizer|String} otherRecognizer
1834
+ * @param {Recognizer} recognizer
1835
+ * @returns {Recognizer}
1836
+ */
1837
+ function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
1838
+ var manager = recognizer.manager;
1839
+ if (manager) {
1840
+ return manager.get(otherRecognizer);
1841
+ }
1842
+ return otherRecognizer;
1843
+ }
1844
+
1845
+ /**
1846
+ * This recognizer is just used as a base for the simple attribute recognizers.
1847
+ * @constructor
1848
+ * @extends Recognizer
1849
+ */
1850
+ function AttrRecognizer() {
1851
+ Recognizer.apply(this, arguments);
1852
+ }
1853
+
1854
+ inherit(AttrRecognizer, Recognizer, {
1855
+ /**
1856
+ * @namespace
1857
+ * @memberof AttrRecognizer
1858
+ */
1859
+ defaults: {
1860
+ /**
1861
+ * @type {Number}
1862
+ * @default 1
1863
+ */
1864
+ pointers: 1
1865
+ },
1866
+
1867
+ /**
1868
+ * Used to check if it the recognizer receives valid input, like input.distance > 10.
1869
+ * @memberof AttrRecognizer
1870
+ * @param {Object} input
1871
+ * @returns {Boolean} recognized
1872
+ */
1873
+ attrTest: function(input) {
1874
+ var optionPointers = this.options.pointers;
1875
+ return optionPointers === 0 || input.pointers.length === optionPointers;
1876
+ },
1877
+
1878
+ /**
1879
+ * Process the input and return the state for the recognizer
1880
+ * @memberof AttrRecognizer
1881
+ * @param {Object} input
1882
+ * @returns {*} State
1883
+ */
1884
+ process: function(input) {
1885
+ var state = this.state;
1886
+ var eventType = input.eventType;
1887
+
1888
+ var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
1889
+ var isValid = this.attrTest(input);
1890
+
1891
+ // on cancel input and we've recognized before, return STATE_CANCELLED
1892
+ if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
1893
+ return state | STATE_CANCELLED;
1894
+ } else if (isRecognized || isValid) {
1895
+ if (eventType & INPUT_END) {
1896
+ return state | STATE_ENDED;
1897
+ } else if (!(state & STATE_BEGAN)) {
1898
+ return STATE_BEGAN;
1899
+ }
1900
+ return state | STATE_CHANGED;
1901
+ }
1902
+ return STATE_FAILED;
1903
+ }
1904
+ });
1905
+
1906
+ /**
1907
+ * Pan
1908
+ * Recognized when the pointer is down and moved in the allowed direction.
1909
+ * @constructor
1910
+ * @extends AttrRecognizer
1911
+ */
1912
+ function PanRecognizer() {
1913
+ AttrRecognizer.apply(this, arguments);
1914
+
1915
+ this.pX = null;
1916
+ this.pY = null;
1917
+ }
1918
+
1919
+ inherit(PanRecognizer, AttrRecognizer, {
1920
+ /**
1921
+ * @namespace
1922
+ * @memberof PanRecognizer
1923
+ */
1924
+ defaults: {
1925
+ event: 'pan',
1926
+ threshold: 10,
1927
+ pointers: 1,
1928
+ direction: DIRECTION_ALL
1929
+ },
1930
+
1931
+ getTouchAction: function() {
1932
+ var direction = this.options.direction;
1933
+ var actions = [];
1934
+ if (direction & DIRECTION_HORIZONTAL) {
1935
+ actions.push(TOUCH_ACTION_PAN_Y);
1936
+ }
1937
+ if (direction & DIRECTION_VERTICAL) {
1938
+ actions.push(TOUCH_ACTION_PAN_X);
1939
+ }
1940
+ return actions;
1941
+ },
1942
+
1943
+ directionTest: function(input) {
1944
+ var options = this.options;
1945
+ var hasMoved = true;
1946
+ var distance = input.distance;
1947
+ var direction = input.direction;
1948
+ var x = input.deltaX;
1949
+ var y = input.deltaY;
1950
+
1951
+ // lock to axis?
1952
+ if (!(direction & options.direction)) {
1953
+ if (options.direction & DIRECTION_HORIZONTAL) {
1954
+ direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
1955
+ hasMoved = x != this.pX;
1956
+ distance = Math.abs(input.deltaX);
1957
+ } else {
1958
+ direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
1959
+ hasMoved = y != this.pY;
1960
+ distance = Math.abs(input.deltaY);
1961
+ }
1962
+ }
1963
+ input.direction = direction;
1964
+ return hasMoved && distance > options.threshold && direction & options.direction;
1965
+ },
1966
+
1967
+ attrTest: function(input) {
1968
+ return AttrRecognizer.prototype.attrTest.call(this, input) &&
1969
+ (this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
1970
+ },
1971
+
1972
+ emit: function(input) {
1973
+
1974
+ this.pX = input.deltaX;
1975
+ this.pY = input.deltaY;
1976
+
1977
+ var direction = directionStr(input.direction);
1978
+
1979
+ if (direction) {
1980
+ input.additionalEvent = this.options.event + direction;
1981
+ }
1982
+ this._super.emit.call(this, input);
1983
+ }
1984
+ });
1985
+
1986
+ /**
1987
+ * Pinch
1988
+ * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
1989
+ * @constructor
1990
+ * @extends AttrRecognizer
1991
+ */
1992
+ function PinchRecognizer() {
1993
+ AttrRecognizer.apply(this, arguments);
1994
+ }
1995
+
1996
+ inherit(PinchRecognizer, AttrRecognizer, {
1997
+ /**
1998
+ * @namespace
1999
+ * @memberof PinchRecognizer
2000
+ */
2001
+ defaults: {
2002
+ event: 'pinch',
2003
+ threshold: 0,
2004
+ pointers: 2
2005
+ },
2006
+
2007
+ getTouchAction: function() {
2008
+ return [TOUCH_ACTION_NONE];
2009
+ },
2010
+
2011
+ attrTest: function(input) {
2012
+ return this._super.attrTest.call(this, input) &&
2013
+ (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
2014
+ },
2015
+
2016
+ emit: function(input) {
2017
+ if (input.scale !== 1) {
2018
+ var inOut = input.scale < 1 ? 'in' : 'out';
2019
+ input.additionalEvent = this.options.event + inOut;
2020
+ }
2021
+ this._super.emit.call(this, input);
2022
+ }
2023
+ });
2024
+
2025
+ /**
2026
+ * Press
2027
+ * Recognized when the pointer is down for x ms without any movement.
2028
+ * @constructor
2029
+ * @extends Recognizer
2030
+ */
2031
+ function PressRecognizer() {
2032
+ Recognizer.apply(this, arguments);
2033
+
2034
+ this._timer = null;
2035
+ this._input = null;
2036
+ }
2037
+
2038
+ inherit(PressRecognizer, Recognizer, {
2039
+ /**
2040
+ * @namespace
2041
+ * @memberof PressRecognizer
2042
+ */
2043
+ defaults: {
2044
+ event: 'press',
2045
+ pointers: 1,
2046
+ time: 251, // minimal time of the pointer to be pressed
2047
+ threshold: 9 // a minimal movement is ok, but keep it low
2048
+ },
2049
+
2050
+ getTouchAction: function() {
2051
+ return [TOUCH_ACTION_AUTO];
2052
+ },
2053
+
2054
+ process: function(input) {
2055
+ var options = this.options;
2056
+ var validPointers = input.pointers.length === options.pointers;
2057
+ var validMovement = input.distance < options.threshold;
2058
+ var validTime = input.deltaTime > options.time;
2059
+
2060
+ this._input = input;
2061
+
2062
+ // we only allow little movement
2063
+ // and we've reached an end event, so a tap is possible
2064
+ if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
2065
+ this.reset();
2066
+ } else if (input.eventType & INPUT_START) {
2067
+ this.reset();
2068
+ this._timer = setTimeoutContext(function() {
2069
+ this.state = STATE_RECOGNIZED;
2070
+ this.tryEmit();
2071
+ }, options.time, this);
2072
+ } else if (input.eventType & INPUT_END) {
2073
+ return STATE_RECOGNIZED;
2074
+ }
2075
+ return STATE_FAILED;
2076
+ },
2077
+
2078
+ reset: function() {
2079
+ clearTimeout(this._timer);
2080
+ },
2081
+
2082
+ emit: function(input) {
2083
+ if (this.state !== STATE_RECOGNIZED) {
2084
+ return;
2085
+ }
2086
+
2087
+ if (input && (input.eventType & INPUT_END)) {
2088
+ this.manager.emit(this.options.event + 'up', input);
2089
+ } else {
2090
+ this._input.timeStamp = now();
2091
+ this.manager.emit(this.options.event, this._input);
2092
+ }
2093
+ }
2094
+ });
2095
+
2096
+ /**
2097
+ * Rotate
2098
+ * Recognized when two or more pointer are moving in a circular motion.
2099
+ * @constructor
2100
+ * @extends AttrRecognizer
2101
+ */
2102
+ function RotateRecognizer() {
2103
+ AttrRecognizer.apply(this, arguments);
2104
+ }
2105
+
2106
+ inherit(RotateRecognizer, AttrRecognizer, {
2107
+ /**
2108
+ * @namespace
2109
+ * @memberof RotateRecognizer
2110
+ */
2111
+ defaults: {
2112
+ event: 'rotate',
2113
+ threshold: 0,
2114
+ pointers: 2
2115
+ },
2116
+
2117
+ getTouchAction: function() {
2118
+ return [TOUCH_ACTION_NONE];
2119
+ },
2120
+
2121
+ attrTest: function(input) {
2122
+ return this._super.attrTest.call(this, input) &&
2123
+ (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
2124
+ }
2125
+ });
2126
+
2127
+ /**
2128
+ * Swipe
2129
+ * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
2130
+ * @constructor
2131
+ * @extends AttrRecognizer
2132
+ */
2133
+ function SwipeRecognizer() {
2134
+ AttrRecognizer.apply(this, arguments);
2135
+ }
2136
+
2137
+ inherit(SwipeRecognizer, AttrRecognizer, {
2138
+ /**
2139
+ * @namespace
2140
+ * @memberof SwipeRecognizer
2141
+ */
2142
+ defaults: {
2143
+ event: 'swipe',
2144
+ threshold: 10,
2145
+ velocity: 0.3,
2146
+ direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
2147
+ pointers: 1
2148
+ },
2149
+
2150
+ getTouchAction: function() {
2151
+ return PanRecognizer.prototype.getTouchAction.call(this);
2152
+ },
2153
+
2154
+ attrTest: function(input) {
2155
+ var direction = this.options.direction;
2156
+ var velocity;
2157
+
2158
+ if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
2159
+ velocity = input.overallVelocity;
2160
+ } else if (direction & DIRECTION_HORIZONTAL) {
2161
+ velocity = input.overallVelocityX;
2162
+ } else if (direction & DIRECTION_VERTICAL) {
2163
+ velocity = input.overallVelocityY;
2164
+ }
2165
+
2166
+ return this._super.attrTest.call(this, input) &&
2167
+ direction & input.offsetDirection &&
2168
+ input.distance > this.options.threshold &&
2169
+ input.maxPointers == this.options.pointers &&
2170
+ abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
2171
+ },
2172
+
2173
+ emit: function(input) {
2174
+ var direction = directionStr(input.offsetDirection);
2175
+ if (direction) {
2176
+ this.manager.emit(this.options.event + direction, input);
2177
+ }
2178
+
2179
+ this.manager.emit(this.options.event, input);
2180
+ }
2181
+ });
2182
+
2183
+ /**
2184
+ * A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
2185
+ * between the given interval and position. The delay option can be used to recognize multi-taps without firing
2186
+ * a single tap.
2187
+ *
2188
+ * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
2189
+ * multi-taps being recognized.
2190
+ * @constructor
2191
+ * @extends Recognizer
2192
+ */
2193
+ function TapRecognizer() {
2194
+ Recognizer.apply(this, arguments);
2195
+
2196
+ // previous time and center,
2197
+ // used for tap counting
2198
+ this.pTime = false;
2199
+ this.pCenter = false;
2200
+
2201
+ this._timer = null;
2202
+ this._input = null;
2203
+ this.count = 0;
2204
+ }
2205
+
2206
+ inherit(TapRecognizer, Recognizer, {
2207
+ /**
2208
+ * @namespace
2209
+ * @memberof PinchRecognizer
2210
+ */
2211
+ defaults: {
2212
+ event: 'tap',
2213
+ pointers: 1,
2214
+ taps: 1,
2215
+ interval: 300, // max time between the multi-tap taps
2216
+ time: 250, // max time of the pointer to be down (like finger on the screen)
2217
+ threshold: 9, // a minimal movement is ok, but keep it low
2218
+ posThreshold: 10 // a multi-tap can be a bit off the initial position
2219
+ },
2220
+
2221
+ getTouchAction: function() {
2222
+ return [TOUCH_ACTION_MANIPULATION];
2223
+ },
2224
+
2225
+ process: function(input) {
2226
+ var options = this.options;
2227
+
2228
+ var validPointers = input.pointers.length === options.pointers;
2229
+ var validMovement = input.distance < options.threshold;
2230
+ var validTouchTime = input.deltaTime < options.time;
2231
+
2232
+ this.reset();
2233
+
2234
+ if ((input.eventType & INPUT_START) && (this.count === 0)) {
2235
+ return this.failTimeout();
2236
+ }
2237
+
2238
+ // we only allow little movement
2239
+ // and we've reached an end event, so a tap is possible
2240
+ if (validMovement && validTouchTime && validPointers) {
2241
+ if (input.eventType != INPUT_END) {
2242
+ return this.failTimeout();
2243
+ }
2244
+
2245
+ var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
2246
+ var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
2247
+
2248
+ this.pTime = input.timeStamp;
2249
+ this.pCenter = input.center;
2250
+
2251
+ if (!validMultiTap || !validInterval) {
2252
+ this.count = 1;
2253
+ } else {
2254
+ this.count += 1;
2255
+ }
2256
+
2257
+ this._input = input;
2258
+
2259
+ // if tap count matches we have recognized it,
2260
+ // else it has began recognizing...
2261
+ var tapCount = this.count % options.taps;
2262
+ if (tapCount === 0) {
2263
+ // no failing requirements, immediately trigger the tap event
2264
+ // or wait as long as the multitap interval to trigger
2265
+ if (!this.hasRequireFailures()) {
2266
+ return STATE_RECOGNIZED;
2267
+ } else {
2268
+ this._timer = setTimeoutContext(function() {
2269
+ this.state = STATE_RECOGNIZED;
2270
+ this.tryEmit();
2271
+ }, options.interval, this);
2272
+ return STATE_BEGAN;
2273
+ }
2274
+ }
2275
+ }
2276
+ return STATE_FAILED;
2277
+ },
2278
+
2279
+ failTimeout: function() {
2280
+ this._timer = setTimeoutContext(function() {
2281
+ this.state = STATE_FAILED;
2282
+ }, this.options.interval, this);
2283
+ return STATE_FAILED;
2284
+ },
2285
+
2286
+ reset: function() {
2287
+ clearTimeout(this._timer);
2288
+ },
2289
+
2290
+ emit: function() {
2291
+ if (this.state == STATE_RECOGNIZED) {
2292
+ this._input.tapCount = this.count;
2293
+ this.manager.emit(this.options.event, this._input);
2294
+ }
2295
+ }
2296
+ });
2297
+
2298
+ /**
2299
+ * Simple way to create a manager with a default set of recognizers.
2300
+ * @param {HTMLElement} element
2301
+ * @param {Object} [options]
2302
+ * @constructor
2303
+ */
2304
+ function Hammer(element, options) {
2305
+ options = options || {};
2306
+ options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
2307
+ return new Manager(element, options);
2308
+ }
2309
+
2310
+ /**
2311
+ * @const {string}
2312
+ */
2313
+ Hammer.VERSION = '2.0.7';
2314
+
2315
+ /**
2316
+ * default settings
2317
+ * @namespace
2318
+ */
2319
+ Hammer.defaults = {
2320
+ /**
2321
+ * set if DOM events are being triggered.
2322
+ * But this is slower and unused by simple implementations, so disabled by default.
2323
+ * @type {Boolean}
2324
+ * @default false
2325
+ */
2326
+ domEvents: false,
2327
+
2328
+ /**
2329
+ * The value for the touchAction property/fallback.
2330
+ * When set to `compute` it will magically set the correct value based on the added recognizers.
2331
+ * @type {String}
2332
+ * @default compute
2333
+ */
2334
+ touchAction: TOUCH_ACTION_COMPUTE,
2335
+
2336
+ /**
2337
+ * @type {Boolean}
2338
+ * @default true
2339
+ */
2340
+ enable: true,
2341
+
2342
+ /**
2343
+ * EXPERIMENTAL FEATURE -- can be removed/changed
2344
+ * Change the parent input target element.
2345
+ * If Null, then it is being set the to main element.
2346
+ * @type {Null|EventTarget}
2347
+ * @default null
2348
+ */
2349
+ inputTarget: null,
2350
+
2351
+ /**
2352
+ * force an input class
2353
+ * @type {Null|Function}
2354
+ * @default null
2355
+ */
2356
+ inputClass: null,
2357
+
2358
+ /**
2359
+ * Default recognizer setup when calling `Hammer()`
2360
+ * When creating a new Manager these will be skipped.
2361
+ * @type {Array}
2362
+ */
2363
+ preset: [
2364
+ // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
2365
+ [RotateRecognizer, {enable: false}],
2366
+ [PinchRecognizer, {enable: false}, ['rotate']],
2367
+ [SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}],
2368
+ [PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']],
2369
+ [TapRecognizer],
2370
+ [TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']],
2371
+ [PressRecognizer]
2372
+ ],
2373
+
2374
+ /**
2375
+ * Some CSS properties can be used to improve the working of Hammer.
2376
+ * Add them to this method and they will be set when creating a new Manager.
2377
+ * @namespace
2378
+ */
2379
+ cssProps: {
2380
+ /**
2381
+ * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
2382
+ * @type {String}
2383
+ * @default 'none'
2384
+ */
2385
+ userSelect: 'none',
2386
+
2387
+ /**
2388
+ * Disable the Windows Phone grippers when pressing an element.
2389
+ * @type {String}
2390
+ * @default 'none'
2391
+ */
2392
+ touchSelect: 'none',
2393
+
2394
+ /**
2395
+ * Disables the default callout shown when you touch and hold a touch target.
2396
+ * On iOS, when you touch and hold a touch target such as a link, Safari displays
2397
+ * a callout containing information about the link. This property allows you to disable that callout.
2398
+ * @type {String}
2399
+ * @default 'none'
2400
+ */
2401
+ touchCallout: 'none',
2402
+
2403
+ /**
2404
+ * Specifies whether zooming is enabled. Used by IE10>
2405
+ * @type {String}
2406
+ * @default 'none'
2407
+ */
2408
+ contentZooming: 'none',
2409
+
2410
+ /**
2411
+ * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
2412
+ * @type {String}
2413
+ * @default 'none'
2414
+ */
2415
+ userDrag: 'none',
2416
+
2417
+ /**
2418
+ * Overrides the highlight color shown when the user taps a link or a JavaScript
2419
+ * clickable element in iOS. This property obeys the alpha value, if specified.
2420
+ * @type {String}
2421
+ * @default 'rgba(0,0,0,0)'
2422
+ */
2423
+ tapHighlightColor: 'rgba(0,0,0,0)'
2424
+ }
2425
+ };
2426
+
2427
+ var STOP = 1;
2428
+ var FORCED_STOP = 2;
2429
+
2430
+ /**
2431
+ * Manager
2432
+ * @param {HTMLElement} element
2433
+ * @param {Object} [options]
2434
+ * @constructor
2435
+ */
2436
+ function Manager(element, options) {
2437
+ this.options = assign({}, Hammer.defaults, options || {});
2438
+
2439
+ this.options.inputTarget = this.options.inputTarget || element;
2440
+
2441
+ this.handlers = {};
2442
+ this.session = {};
2443
+ this.recognizers = [];
2444
+ this.oldCssProps = {};
2445
+
2446
+ this.element = element;
2447
+ this.input = createInputInstance(this);
2448
+ this.touchAction = new TouchAction(this, this.options.touchAction);
2449
+
2450
+ toggleCssProps(this, true);
2451
+
2452
+ each(this.options.recognizers, function(item) {
2453
+ var recognizer = this.add(new (item[0])(item[1]));
2454
+ item[2] && recognizer.recognizeWith(item[2]);
2455
+ item[3] && recognizer.requireFailure(item[3]);
2456
+ }, this);
2457
+ }
2458
+
2459
+ Manager.prototype = {
2460
+ /**
2461
+ * set options
2462
+ * @param {Object} options
2463
+ * @returns {Manager}
2464
+ */
2465
+ set: function(options) {
2466
+ assign(this.options, options);
2467
+
2468
+ // Options that need a little more setup
2469
+ if (options.touchAction) {
2470
+ this.touchAction.update();
2471
+ }
2472
+ if (options.inputTarget) {
2473
+ // Clean up existing event listeners and reinitialize
2474
+ this.input.destroy();
2475
+ this.input.target = options.inputTarget;
2476
+ this.input.init();
2477
+ }
2478
+ return this;
2479
+ },
2480
+
2481
+ /**
2482
+ * stop recognizing for this session.
2483
+ * This session will be discarded, when a new [input]start event is fired.
2484
+ * When forced, the recognizer cycle is stopped immediately.
2485
+ * @param {Boolean} [force]
2486
+ */
2487
+ stop: function(force) {
2488
+ this.session.stopped = force ? FORCED_STOP : STOP;
2489
+ },
2490
+
2491
+ /**
2492
+ * run the recognizers!
2493
+ * called by the inputHandler function on every movement of the pointers (touches)
2494
+ * it walks through all the recognizers and tries to detect the gesture that is being made
2495
+ * @param {Object} inputData
2496
+ */
2497
+ recognize: function(inputData) {
2498
+ var session = this.session;
2499
+ if (session.stopped) {
2500
+ return;
2501
+ }
2502
+
2503
+ // run the touch-action polyfill
2504
+ this.touchAction.preventDefaults(inputData);
2505
+
2506
+ var recognizer;
2507
+ var recognizers = this.recognizers;
2508
+
2509
+ // this holds the recognizer that is being recognized.
2510
+ // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
2511
+ // if no recognizer is detecting a thing, it is set to `null`
2512
+ var curRecognizer = session.curRecognizer;
2513
+
2514
+ // reset when the last recognizer is recognized
2515
+ // or when we're in a new session
2516
+ if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
2517
+ curRecognizer = session.curRecognizer = null;
2518
+ }
2519
+
2520
+ var i = 0;
2521
+ while (i < recognizers.length) {
2522
+ recognizer = recognizers[i];
2523
+
2524
+ // find out if we are allowed try to recognize the input for this one.
2525
+ // 1. allow if the session is NOT forced stopped (see the .stop() method)
2526
+ // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
2527
+ // that is being recognized.
2528
+ // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
2529
+ // this can be setup with the `recognizeWith()` method on the recognizer.
2530
+ if (session.stopped !== FORCED_STOP && ( // 1
2531
+ !curRecognizer || recognizer == curRecognizer || // 2
2532
+ recognizer.canRecognizeWith(curRecognizer))) { // 3
2533
+ recognizer.recognize(inputData);
2534
+ } else {
2535
+ recognizer.reset();
2536
+ }
2537
+
2538
+ // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
2539
+ // current active recognizer. but only if we don't already have an active recognizer
2540
+ if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
2541
+ curRecognizer = session.curRecognizer = recognizer;
2542
+ }
2543
+ i++;
2544
+ }
2545
+ },
2546
+
2547
+ /**
2548
+ * get a recognizer by its event name.
2549
+ * @param {Recognizer|String} recognizer
2550
+ * @returns {Recognizer|Null}
2551
+ */
2552
+ get: function(recognizer) {
2553
+ if (recognizer instanceof Recognizer) {
2554
+ return recognizer;
2555
+ }
2556
+
2557
+ var recognizers = this.recognizers;
2558
+ for (var i = 0; i < recognizers.length; i++) {
2559
+ if (recognizers[i].options.event == recognizer) {
2560
+ return recognizers[i];
2561
+ }
2562
+ }
2563
+ return null;
2564
+ },
2565
+
2566
+ /**
2567
+ * add a recognizer to the manager
2568
+ * existing recognizers with the same event name will be removed
2569
+ * @param {Recognizer} recognizer
2570
+ * @returns {Recognizer|Manager}
2571
+ */
2572
+ add: function(recognizer) {
2573
+ if (invokeArrayArg(recognizer, 'add', this)) {
2574
+ return this;
2575
+ }
2576
+
2577
+ // remove existing
2578
+ var existing = this.get(recognizer.options.event);
2579
+ if (existing) {
2580
+ this.remove(existing);
2581
+ }
2582
+
2583
+ this.recognizers.push(recognizer);
2584
+ recognizer.manager = this;
2585
+
2586
+ this.touchAction.update();
2587
+ return recognizer;
2588
+ },
2589
+
2590
+ /**
2591
+ * remove a recognizer by name or instance
2592
+ * @param {Recognizer|String} recognizer
2593
+ * @returns {Manager}
2594
+ */
2595
+ remove: function(recognizer) {
2596
+ if (invokeArrayArg(recognizer, 'remove', this)) {
2597
+ return this;
2598
+ }
2599
+
2600
+ recognizer = this.get(recognizer);
2601
+
2602
+ // let's make sure this recognizer exists
2603
+ if (recognizer) {
2604
+ var recognizers = this.recognizers;
2605
+ var index = inArray(recognizers, recognizer);
2606
+
2607
+ if (index !== -1) {
2608
+ recognizers.splice(index, 1);
2609
+ this.touchAction.update();
2610
+ }
2611
+ }
2612
+
2613
+ return this;
2614
+ },
2615
+
2616
+ /**
2617
+ * bind event
2618
+ * @param {String} events
2619
+ * @param {Function} handler
2620
+ * @returns {EventEmitter} this
2621
+ */
2622
+ on: function(events, handler) {
2623
+ if (events === undefined$1) {
2624
+ return;
2625
+ }
2626
+ if (handler === undefined$1) {
2627
+ return;
2628
+ }
2629
+
2630
+ var handlers = this.handlers;
2631
+ each(splitStr(events), function(event) {
2632
+ handlers[event] = handlers[event] || [];
2633
+ handlers[event].push(handler);
2634
+ });
2635
+ return this;
2636
+ },
2637
+
2638
+ /**
2639
+ * unbind event, leave emit blank to remove all handlers
2640
+ * @param {String} events
2641
+ * @param {Function} [handler]
2642
+ * @returns {EventEmitter} this
2643
+ */
2644
+ off: function(events, handler) {
2645
+ if (events === undefined$1) {
2646
+ return;
2647
+ }
2648
+
2649
+ var handlers = this.handlers;
2650
+ each(splitStr(events), function(event) {
2651
+ if (!handler) {
2652
+ delete handlers[event];
2653
+ } else {
2654
+ handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
2655
+ }
2656
+ });
2657
+ return this;
2658
+ },
2659
+
2660
+ /**
2661
+ * emit event to the listeners
2662
+ * @param {String} event
2663
+ * @param {Object} data
2664
+ */
2665
+ emit: function(event, data) {
2666
+ // we also want to trigger dom events
2667
+ if (this.options.domEvents) {
2668
+ triggerDomEvent(event, data);
2669
+ }
2670
+
2671
+ // no handlers, so skip it all
2672
+ var handlers = this.handlers[event] && this.handlers[event].slice();
2673
+ if (!handlers || !handlers.length) {
2674
+ return;
2675
+ }
2676
+
2677
+ data.type = event;
2678
+ data.preventDefault = function() {
2679
+ data.srcEvent.preventDefault();
2680
+ };
2681
+
2682
+ var i = 0;
2683
+ while (i < handlers.length) {
2684
+ handlers[i](data);
2685
+ i++;
2686
+ }
2687
+ },
2688
+
2689
+ /**
2690
+ * destroy the manager and unbinds all events
2691
+ * it doesn't unbind dom events, that is the user own responsibility
2692
+ */
2693
+ destroy: function() {
2694
+ this.element && toggleCssProps(this, false);
2695
+
2696
+ this.handlers = {};
2697
+ this.session = {};
2698
+ this.input.destroy();
2699
+ this.element = null;
2700
+ }
2701
+ };
2702
+
2703
+ /**
2704
+ * add/remove the css properties as defined in manager.options.cssProps
2705
+ * @param {Manager} manager
2706
+ * @param {Boolean} add
2707
+ */
2708
+ function toggleCssProps(manager, add) {
2709
+ var element = manager.element;
2710
+ if (!element.style) {
2711
+ return;
2712
+ }
2713
+ var prop;
2714
+ each(manager.options.cssProps, function(value, name) {
2715
+ prop = prefixed(element.style, name);
2716
+ if (add) {
2717
+ manager.oldCssProps[prop] = element.style[prop];
2718
+ element.style[prop] = value;
2719
+ } else {
2720
+ element.style[prop] = manager.oldCssProps[prop] || '';
2721
+ }
2722
+ });
2723
+ if (!add) {
2724
+ manager.oldCssProps = {};
2725
+ }
2726
+ }
2727
+
2728
+ /**
2729
+ * trigger dom event
2730
+ * @param {String} event
2731
+ * @param {Object} data
2732
+ */
2733
+ function triggerDomEvent(event, data) {
2734
+ var gestureEvent = document.createEvent('Event');
2735
+ gestureEvent.initEvent(event, true, true);
2736
+ gestureEvent.gesture = data;
2737
+ data.target.dispatchEvent(gestureEvent);
2738
+ }
2739
+
2740
+ assign(Hammer, {
2741
+ INPUT_START: INPUT_START,
2742
+ INPUT_MOVE: INPUT_MOVE,
2743
+ INPUT_END: INPUT_END,
2744
+ INPUT_CANCEL: INPUT_CANCEL,
2745
+
2746
+ STATE_POSSIBLE: STATE_POSSIBLE,
2747
+ STATE_BEGAN: STATE_BEGAN,
2748
+ STATE_CHANGED: STATE_CHANGED,
2749
+ STATE_ENDED: STATE_ENDED,
2750
+ STATE_RECOGNIZED: STATE_RECOGNIZED,
2751
+ STATE_CANCELLED: STATE_CANCELLED,
2752
+ STATE_FAILED: STATE_FAILED,
2753
+
2754
+ DIRECTION_NONE: DIRECTION_NONE,
2755
+ DIRECTION_LEFT: DIRECTION_LEFT,
2756
+ DIRECTION_RIGHT: DIRECTION_RIGHT,
2757
+ DIRECTION_UP: DIRECTION_UP,
2758
+ DIRECTION_DOWN: DIRECTION_DOWN,
2759
+ DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
2760
+ DIRECTION_VERTICAL: DIRECTION_VERTICAL,
2761
+ DIRECTION_ALL: DIRECTION_ALL,
2762
+
2763
+ Manager: Manager,
2764
+ Input: Input,
2765
+ TouchAction: TouchAction,
2766
+
2767
+ TouchInput: TouchInput,
2768
+ MouseInput: MouseInput,
2769
+ PointerEventInput: PointerEventInput,
2770
+ TouchMouseInput: TouchMouseInput,
2771
+ SingleTouchInput: SingleTouchInput,
2772
+
2773
+ Recognizer: Recognizer,
2774
+ AttrRecognizer: AttrRecognizer,
2775
+ Tap: TapRecognizer,
2776
+ Pan: PanRecognizer,
2777
+ Swipe: SwipeRecognizer,
2778
+ Pinch: PinchRecognizer,
2779
+ Rotate: RotateRecognizer,
2780
+ Press: PressRecognizer,
2781
+
2782
+ on: addEventListeners,
2783
+ off: removeEventListeners,
2784
+ each: each,
2785
+ merge: merge,
2786
+ extend: extend,
2787
+ assign: assign,
2788
+ inherit: inherit,
2789
+ bindFn: bindFn,
2790
+ prefixed: prefixed
2791
+ });
2792
+
2793
+ // this prevents errors when Hammer is loaded in the presence of an AMD
2794
+ // style loader but by script tag, not by the loader.
2795
+ var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line
2796
+ freeGlobal.Hammer = Hammer;
2797
+
2798
+ if (typeof undefined$1 === 'function' && undefined$1.amd) {
2799
+ undefined$1(function() {
2800
+ return Hammer;
2801
+ });
2802
+ } else if (module.exports) {
2803
+ module.exports = Hammer;
2804
+ } else {
2805
+ window[exportName] = Hammer;
2806
+ }
2807
+
2808
+ })(window, document, 'Hammer');
2809
+ }(hammer));
2810
+
2811
+ var Hammer = hammer.exports;
2812
+
2813
+ var Hammer$1 = /*#__PURE__*/Object.freeze(/*#__PURE__*/_mergeNamespaces({
2814
+ __proto__: null,
2815
+ 'default': Hammer
2816
+ }, [hammer.exports]));
2817
+
2818
+ // uuid
2819
+ function S4() {
2820
+ return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
2821
+ }
2822
+ /**
2823
+ * 随机生成一个uuid值
2824
+ */
2825
+ function uuid() {
2826
+ // then to call it, plus stitch in '4' in the third group
2827
+ return (S4() + S4() + '-' + S4() + '-4' + S4().substr(0, 3) + '-' + S4() + '-' + S4() + S4() + S4()).toLowerCase();
2828
+ }
2829
+
2830
+ class Polyline {
2831
+ id = uuid();
2832
+ points = [];
2833
+ lines = [];
2834
+ push(line) {
2835
+ const next = this.getNext(line);
2836
+ if (!next)
2837
+ throw new Error('当前线段于上一条线段无法构成折线');
2838
+ this.lines.push(next.line);
2839
+ this.points.push(...next.points);
2840
+ return this.lines.length;
2841
+ }
2842
+ pop() {
2843
+ const lastPoint = this.lines.pop();
2844
+ const polylineLength = this.lines.length;
2845
+ if (polylineLength === 0)
2846
+ this.points.slice(0, this.points.length);
2847
+ else
2848
+ this.points.pop();
2849
+ return lastPoint;
2850
+ }
2851
+ getNext(line) {
2852
+ const lastPoint = this.points.slice(-1)[0];
2853
+ if (!lastPoint)
2854
+ return { line: line, points: line.points };
2855
+ if (!line.points.includes(lastPoint))
2856
+ return null;
2857
+ const nextPoint = line.points.find((point) => point !== lastPoint);
2858
+ if (!nextPoint)
2859
+ return null;
2860
+ return { line: line, points: [nextPoint] };
2861
+ }
2862
+ toJson() {
2863
+ return {
2864
+ id: this.id,
2865
+ lines: this.lines.map((line) => line.id),
2866
+ points: this.points.map((point) => point.id),
2867
+ };
2868
+ }
2869
+ toCompletelyJson() {
2870
+ return {
2871
+ id: this.id,
2872
+ points: this.points.map((point) => point.toJson()),
2873
+ lines: this.lines.map((line) => line.toCompletelyJson()),
2874
+ };
2875
+ }
2876
+ }
2877
+
2878
+ const lineWidth = 2;
2879
+ const lightLineWidth = 4;
2880
+ const lineColor = new three.Color(0xffffff);
2881
+ const lightLineColor = new three.Color(0x2d7cff);
2882
+ const pointColor = new three.Color(0xffffff);
2883
+ const lightPointColor = new three.Color(0x2d7cff);
2884
+ const pointSize = 8;
2885
+ const lightPointSize = 16;
2886
+ const pointImage = 'data:image/png;base64,' +
2887
+ 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgBAMAAACBVGfHAAAAIVBMVEUAAAD////////////////////////////////////////PIev5AAAACnRSTlMAG/Py2baba05un7UgfgAAAHJJREFUKM9joBpgLHVSCRdA4metAoJlCJHmVWBgAeNzroKCCVCBLpjACqgJVjCBxRBT2FbBQQJYQAohsBAsUIUQWA4WiEIILAULeCEEloAFtBACizAEMLRgGIphLabDMJ2O6TlM72MGECIIMQIZIxqoBQCPvpJ/e9FaAAAAAABJRU5ErkJggg==';
2888
+ const pointTexture = new three.TextureLoader().load(pointImage);
2889
+ const normalLineOpts = {
2890
+ pointTexture,
2891
+ pointSize,
2892
+ lineWidth,
2893
+ lineColor,
2894
+ pointColor,
2895
+ lineRenderOrder: 20,
2896
+ pointsRenderOrder: 20,
2897
+ };
2898
+ Object.assign({}, normalLineOpts, { dashed: true });
2899
+ const lightLineOpts = {
2900
+ pointTexture,
2901
+ pointSize: lightPointSize,
2902
+ lineWidth: lightLineWidth,
2903
+ lineColor: lightLineColor,
2904
+ pointColor: lightPointColor,
2905
+ lineRenderOrder: 10,
2906
+ pointsRenderOrder: 10,
2907
+ };
2908
+
2909
+ function creatLine(start, end, opts) {
2910
+ const lineWidth = opts?.lineWidth ?? 2;
2911
+ const lineColor = opts?.lineColor ?? new three.Color(0xffffff);
2912
+ const pointSize = opts?.pointSize ?? 5;
2913
+ const lineRenderOrder = opts?.lineRenderOrder ?? 10;
2914
+ const pointsRenderOrder = opts?.lineRenderOrder ?? 20;
2915
+ const line$1 = new line.Line(start, end);
2916
+ // set line
2917
+ line$1.setMaterial({ linewidth: lineWidth, color: lineColor });
2918
+ line$1.line.material.depthTest = false;
2919
+ line$1.line.material.transparent = true;
2920
+ line$1.line.renderOrder = lineRenderOrder;
2921
+ // set point
2922
+ line$1.points.renderOrder = pointsRenderOrder;
2923
+ const pointMaterial = line$1.points.material;
2924
+ pointMaterial.depthTest = false;
2925
+ pointMaterial.size = pointSize;
2926
+ opts?.pointColor && pointMaterial.color.set(opts.pointColor).convertSRGBToLinear();
2927
+ if (opts?.pointTexture)
2928
+ pointMaterial.map = opts.pointTexture;
2929
+ return line$1;
2930
+ }
2931
+ function creatLineMesh(line, type) {
2932
+ const [point, anotherPoint] = line.points;
2933
+ const opts = type === 'light' ? lightLineOpts : normalLineOpts;
2934
+ const fiveLine = creatLine(point.position, anotherPoint.position, opts);
2935
+ fiveLine.name = 'normalLine_' + line.id;
2936
+ return fiveLine;
2937
+ }
2938
+
2939
+ function isNDCPointInScreen(ndcPoint) {
2940
+ const { x, y, z } = ndcPoint;
2941
+ if (Math.abs(x) > 1 || Math.abs(y) > 1 || Math.abs(z) > 1)
2942
+ return false;
2943
+ return true;
2944
+ }
2945
+
2946
+ function creatContentDom() {
2947
+ const contentDom = document.createElement('div');
2948
+ contentDom.style.height = '24px';
2949
+ contentDom.style.width = '62px';
2950
+ contentDom.style.lineHeight = '24px';
2951
+ contentDom.style.textAlign = 'center';
2952
+ contentDom.style.transform = 'translate(-50%, -50%)';
2953
+ contentDom.style.borderRadius = '12px';
2954
+ contentDom.style.fontSize = '14px';
2955
+ contentDom.style.color = '#000000';
2956
+ contentDom.style.background = '#fff';
2957
+ contentDom.style.pointerEvents = 'all';
2958
+ contentDom.style.cursor = 'pointer';
2959
+ return contentDom;
2960
+ }
2961
+ function createContainerDom(line) {
2962
+ const containerDom = document.createElement('div');
2963
+ containerDom.id = 'distance_' + line.id;
2964
+ containerDom.classList.add('five-plugin-measure__distance');
2965
+ containerDom.style.opacity = '0';
2966
+ containerDom.style.position = 'absolute';
2967
+ containerDom.style.left = '0';
2968
+ containerDom.style.top = '0';
2969
+ containerDom.style.transform = 'translate3d(0, 0, 0)';
2970
+ return containerDom;
2971
+ }
2972
+ function creatDistanceItem(props) {
2973
+ function handleClick() {
2974
+ highlight();
2975
+ props.clickCallback?.(distanceItem);
2976
+ }
2977
+ function highlight() {
2978
+ if (userDistanceItem)
2979
+ return userDistanceItem.highlight();
2980
+ contentDom.style.border = '1px solid #538FFF';
2981
+ contentDom.style.color = '#538FFF';
2982
+ }
2983
+ function unHighlight() {
2984
+ if (userDistanceItem)
2985
+ return userDistanceItem.unHighlight();
2986
+ contentDom.style.border = 'none';
2987
+ contentDom.style.color = '#000';
2988
+ }
2989
+ function update(five) {
2990
+ const fiveElement = five.getElement();
2991
+ if (!fiveElement)
2992
+ return;
2993
+ const screenWidth = fiveElement.clientWidth;
2994
+ const screenHeight = fiveElement.clientHeight;
2995
+ if (line.points.length < 2)
2996
+ return;
2997
+ const [startPoint, endPoint] = line.points;
2998
+ const ndcStartPosition = startPoint.position.clone().project(five.camera);
2999
+ const ndcEndPosition = endPoint.position.clone().project(five.camera);
3000
+ const ndcDomPosition = ndcStartPosition.clone().lerp(ndcEndPosition, 0.5);
3001
+ const visible = (() => {
3002
+ // 对于超过近平面和远平面的点,计算会有问题
3003
+ if (Math.abs(ndcStartPosition.z) > 1 || Math.abs(ndcEndPosition.z) > 1)
3004
+ return false;
3005
+ if (!isNDCPointInScreen(ndcStartPosition) && !isNDCPointInScreen(ndcEndPosition))
3006
+ return false;
3007
+ if (!isNDCPointInScreen(ndcDomPosition))
3008
+ return false;
3009
+ const screenStartPosition = new three.Vector2(ndcStartPosition.x * screenWidth, ndcStartPosition.y * screenHeight);
3010
+ const screenEndPosition = new three.Vector2(ndcEndPosition.x * screenWidth, ndcEndPosition.y * screenHeight);
3011
+ if (screenStartPosition.distanceTo(screenEndPosition) < 20)
3012
+ return false;
3013
+ return true;
3014
+ })();
3015
+ if (visible === false) {
3016
+ containerDom.style.opacity = '0';
3017
+ containerDom.style.pointerEvents = 'none';
3018
+ return;
3019
+ }
3020
+ // 更新 UI
3021
+ const left = ((ndcDomPosition.x + 1) / 2) * screenWidth;
3022
+ const top = (-(ndcDomPosition.y - 1) / 2) * screenHeight;
3023
+ containerDom.style.transform = `translate3d(${left}px, ${top}px, 10px)`;
3024
+ containerDom.style.opacity = '1';
3025
+ containerDom.style.pointerEvents = 'all';
3026
+ if (userDistanceItem) {
3027
+ userDistanceItem.update({ line: line.toCompletelyJson(), polyline: line.getPolyline().toCompletelyJson() });
3028
+ }
3029
+ const distanceString = startPoint.position.clone().distanceTo(endPoint.position).toFixed(2) + 'm';
3030
+ contentDom.innerText !== distanceString && (contentDom.innerText = distanceString);
3031
+ }
3032
+ function appendTo(container) {
3033
+ container.appendChild(containerDom);
3034
+ containerDom.addEventListener('click', handleClick);
3035
+ }
3036
+ function remove() {
3037
+ contentDom.removeEventListener('click', handleClick);
3038
+ containerDom.remove();
3039
+ }
3040
+ const { line } = props;
3041
+ const lineID = line.id;
3042
+ const contentDom = creatContentDom();
3043
+ const containerDom = createContainerDom(line);
3044
+ const userDistanceItem = props.userDistanceItem;
3045
+ const ndcPosition = new three.Vector3(0, 0, 0);
3046
+ const distanceItem = {
3047
+ lineID,
3048
+ ndcPosition,
3049
+ update,
3050
+ appendTo,
3051
+ remove,
3052
+ highlight: highlight,
3053
+ unHighlight: unHighlight,
3054
+ };
3055
+ userDistanceItem?.element ? containerDom.appendChild(userDistanceItem.element) : containerDom.appendChild(contentDom);
3056
+ return distanceItem;
3057
+ }
3058
+
3059
+ class Line {
3060
+ id;
3061
+ selected = false;
3062
+ type = 'line';
3063
+ model;
3064
+ mesh;
3065
+ points;
3066
+ lightMesh;
3067
+ hook;
3068
+ distanceItem;
3069
+ polyline;
3070
+ constructor(point, anotherPoint, model) {
3071
+ this.id = uuid();
3072
+ this.model = model;
3073
+ if (point.id === anotherPoint.id)
3074
+ throw new Error('无效的线段, 一个点无法构成线段');
3075
+ this.hook = new five.Subscribe();
3076
+ this.points = [point, anotherPoint];
3077
+ this.mesh = creatLineMesh(this, 'normal');
3078
+ this.lightMesh = creatLineMesh(this, 'light');
3079
+ this.distanceItem = creatDistanceItem({
3080
+ line: this,
3081
+ clickCallback: () => this.hook.emit('selected', this),
3082
+ userDistanceItem: this.model.params.userDistanceItemCreator
3083
+ ? this.model.params.userDistanceItemCreator()
3084
+ : undefined,
3085
+ });
3086
+ point.lines.push(this);
3087
+ anotherPoint.lines.push(this);
3088
+ }
3089
+ clear() {
3090
+ this.selected = false;
3091
+ this.polyline = undefined;
3092
+ }
3093
+ getPolyline() {
3094
+ if (this.polyline)
3095
+ return this.polyline;
3096
+ const modelPolyline = this.model.polylines.find((polyline) => polyline.lines.includes(this));
3097
+ this.polyline = modelPolyline;
3098
+ if (modelPolyline)
3099
+ return modelPolyline;
3100
+ const polyline = new Polyline();
3101
+ polyline.push(this);
3102
+ return polyline;
3103
+ }
3104
+ findAnotherPoint(point) {
3105
+ return this.points.find(({ id }) => id !== point.id);
3106
+ }
3107
+ toJson() {
3108
+ return { id: this.id, points: this.points.map(({ id }) => id) };
3109
+ }
3110
+ toCompletelyJson() {
3111
+ return { id: this.id, points: this.points.map((point) => point.toJson()) };
3112
+ }
3113
+ clone() {
3114
+ const line = new Line(this.points[0].clone(), this.points[1].clone(), this.model);
3115
+ return line;
3116
+ }
3117
+ }
3118
+
3119
+ /**
3120
+ * 从数组中删除
3121
+ * @param item
3122
+ * @param array
3123
+ * @return 如果删除返回 item
3124
+ */
3125
+ function removeArrayItem(item, array) {
3126
+ for (let index = 0, len = array.length; index < len; index++) {
3127
+ if (item === array[index])
3128
+ return array.splice(index, 1)[0];
3129
+ }
3130
+ }
3131
+
3132
+ class Point {
3133
+ id;
3134
+ lines;
3135
+ position;
3136
+ type = 'point';
3137
+ constructor(position) {
3138
+ this.id = uuid();
3139
+ this.lines = [];
3140
+ this.position = new three.Vector3();
3141
+ position instanceof three.Vector3 ? this.position.copy(position) : this.position.fromArray(position);
3142
+ }
3143
+ toJson() {
3144
+ return { id: this.id, lines: this.lines.map(({ id }) => id), position: this.position.toArray() };
3145
+ }
3146
+ addLine(line) {
3147
+ this.lines.push(line);
3148
+ }
3149
+ removeLine(line) {
3150
+ removeArrayItem(line, this.lines);
3151
+ }
3152
+ clone() {
3153
+ const point = new Point(this.position);
3154
+ return point;
3155
+ }
3156
+ }
3157
+
3158
+ class Model {
3159
+ lines = [];
3160
+ points = [];
3161
+ params;
3162
+ polylines = [];
3163
+ hook = new five.Subscribe();
3164
+ constructor(params) {
3165
+ this.params = params;
3166
+ }
3167
+ addLine(line) {
3168
+ const [startPoint, endPoint] = line.points;
3169
+ if (!startPoint || !endPoint)
3170
+ return this;
3171
+ if (!this.includes(startPoint))
3172
+ this.points.push(startPoint);
3173
+ if (!this.includes(endPoint))
3174
+ this.points.push(endPoint);
3175
+ this.lines.push(line);
3176
+ const lastPolyline = this.polylines.find((polyline) => !!polyline.getNext(line));
3177
+ if (lastPolyline) {
3178
+ lastPolyline.push(line);
3179
+ }
3180
+ else {
3181
+ const polyline = new Polyline();
3182
+ polyline.push(line);
3183
+ this.polylines.push(polyline);
3184
+ }
3185
+ this.hook.emit('lineAdded', line);
3186
+ }
3187
+ removeLineByID(lineID) {
3188
+ const line = this.getLineByID(lineID);
3189
+ if (line)
3190
+ this.removeLine(line);
3191
+ }
3192
+ removeLine(line) {
3193
+ // handle polyline
3194
+ const polyline = this.polylines.find((polyline) => polyline.lines.includes(line));
3195
+ if (polyline) {
3196
+ if (polyline.lines.slice(-1)[0] !== line)
3197
+ throw new Error('不能从中间删除线段');
3198
+ polyline.pop();
3199
+ if (polyline.lines.length === 0)
3200
+ removeArrayItem(polyline, this.polylines);
3201
+ }
3202
+ const [point, anotherPoint] = line.points;
3203
+ if (point.lines.length === 0)
3204
+ removeArrayItem(point, this.points);
3205
+ if (anotherPoint.lines.length === 0)
3206
+ removeArrayItem(anotherPoint, this.points);
3207
+ removeArrayItem(line, this.lines);
3208
+ line.clear();
3209
+ this.hook.emit('lineRemoved', line);
3210
+ return this;
3211
+ }
3212
+ mergeModel(model) {
3213
+ model.lines.forEach((line) => this.addLine(line));
3214
+ }
3215
+ includes(item) {
3216
+ if (item.type === 'point') {
3217
+ return this.points.find(({ id }) => id === item.id) !== undefined;
3218
+ }
3219
+ else if (item.type === 'line') {
3220
+ return this.lines.find(({ id }) => id === item.id) !== undefined;
3221
+ }
3222
+ }
3223
+ getPointByID(id) {
3224
+ return this.points.find(({ id: _id }) => _id === id);
3225
+ }
3226
+ getLineByID(id) {
3227
+ return this.lines.find(({ id: _id }) => _id === id);
3228
+ }
3229
+ getClosestPoint() { }
3230
+ parse(data) {
3231
+ const points = data.points.map(({ id, position }) => {
3232
+ const point = new Point(position);
3233
+ point.id = id;
3234
+ return point;
3235
+ });
3236
+ const lines = data.lines.map((data) => {
3237
+ const [pointID, anotherPointID] = data.points;
3238
+ const point = this.getPointByID.call({ points }, pointID);
3239
+ const anotherPoint = this.getPointByID.call({ points }, anotherPointID);
3240
+ if (!point || !anotherPoint)
3241
+ throw new Error('线上的点不存在');
3242
+ const line = new Line(point, anotherPoint, this);
3243
+ line.id = data.id;
3244
+ return line;
3245
+ });
3246
+ const polylines = data.polylines.map((polylineJson) => {
3247
+ const polyline = new Polyline();
3248
+ polylineJson.lines.forEach((lineID) => {
3249
+ const line = lines.find(({ id }) => id === lineID);
3250
+ line && polyline.push(line);
3251
+ });
3252
+ return polyline;
3253
+ });
3254
+ this.points.splice(0, this.points.length, ...points);
3255
+ this.lines.splice(0, this.lines.length, ...lines);
3256
+ this.polylines.splice(0, this.polylines.length, ...polylines);
3257
+ return this;
3258
+ }
3259
+ toJson() {
3260
+ return {
3261
+ points: this.points.map((point) => point.toJson()),
3262
+ lines: this.lines.map((line) => line.toJson()),
3263
+ polylines: this.polylines.map((polyline) => polyline.toJson()).filter((polylines) => polylines.lines.length > 0),
3264
+ };
3265
+ }
3266
+ }
3267
+
3268
+ /**
3269
+ * 创建一个防抖动函数,该函数在高频调用时会每隔 wait 毫秒后调用 func 方法
3270
+ * `throttle` 会在第一次调用时立刻调用一次
3271
+ * @param func - 要防抖动的函数
3272
+ * @param wait - 需要延迟的毫秒数
3273
+ */
3274
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3275
+ function throttle(func, wait = 200) {
3276
+ let last;
3277
+ return function (...args) {
3278
+ if (last)
3279
+ return;
3280
+ func(...args);
3281
+ last = setTimeout(function () {
3282
+ last = null;
3283
+ }, wait);
3284
+ };
3285
+ }
3286
+
3287
+ const preventDefault = (e) => e.preventDefault();
3288
+
3289
+ class BaseController {
3290
+ five;
3291
+ group;
3292
+ model;
3293
+ disposed = false;
3294
+ mouseGroup;
3295
+ container;
3296
+ fiveHelper;
3297
+ hook;
3298
+ magnifier;
3299
+ userDistanceItemCreator;
3300
+ constructor(params) {
3301
+ // ==================== Params ====================
3302
+ this.five = params.five;
3303
+ this.hook = params.hook;
3304
+ this.model = params.model;
3305
+ this.magnifier = params.magnifier;
3306
+ this.container = params.container;
3307
+ this.fiveHelper = params.fiveHelper;
3308
+ this.userDistanceItemCreator = params.userDistanceItemCreator;
3309
+ // ==================== Groups ====================
3310
+ this.group = params.group;
3311
+ this.mouseGroup = params.mouseGroup;
3312
+ const fiveElement = this.five.getElement();
3313
+ if (fiveElement) {
3314
+ fiveElement.addEventListener('touchstart', preventDefault);
3315
+ fiveElement.addEventListener('contextmenu', preventDefault);
3316
+ }
3317
+ }
3318
+ removeLine(line) {
3319
+ this.group.remove(line.mesh, line.lightMesh);
3320
+ line.distanceItem.remove();
3321
+ this.five.needsRender = true;
3322
+ }
3323
+ updateDistanceUI = () => {
3324
+ this.model.lines.forEach((line) => line.distanceItem.update(this.five));
3325
+ };
3326
+ updateMouseGroup(intersection, mesh) {
3327
+ if (!intersection)
3328
+ return this.mouseGroup;
3329
+ // ============ update mouseGroup position ============
3330
+ const adsorbentPoint = this.fiveHelper.getAdsorbentPoint(intersection);
3331
+ const viewPosition = adsorbentPoint ? adsorbentPoint : intersection.point;
3332
+ this.mouseGroup.position.copy(viewPosition);
3333
+ // ============ update mouseGroup quaternion ============
3334
+ if (mesh) {
3335
+ this.mouseGroup.quaternion.copy(mesh.quaternion);
3336
+ }
3337
+ else if (intersection.face) {
3338
+ const normal = intersection.face.normal;
3339
+ const positionVector = normal.clone().multiplyScalar(0.05);
3340
+ const position = intersection.point.clone().add(positionVector);
3341
+ const lookAtVector = position.clone().add(positionVector);
3342
+ this.mouseGroup.lookAt(lookAtVector);
3343
+ }
3344
+ return this.mouseGroup;
3345
+ }
3346
+ dispose() {
3347
+ this.disposed = true;
3348
+ this.magnifier.dispose();
3349
+ this.model.lines.forEach((line) => this.removeLine(line));
3350
+ const fiveElement = this.five.getElement();
3351
+ if (fiveElement) {
3352
+ fiveElement.removeEventListener('touchstart', preventDefault);
3353
+ fiveElement.removeEventListener('contextmenu', preventDefault);
3354
+ }
3355
+ }
3356
+ }
3357
+
3358
+ /**
3359
+ * 从 Hammer 事件中获取操作的点在交互 DOM 中的位置
3360
+ * @ignore TODO: make a suitable name
3361
+ */
3362
+ function getPointFromHammerEvent(event) {
3363
+ // clientX 与 clientY 是相对 document 的,需要转换成相对于 target 的坐标
3364
+ const { x: clientX, y: clientY } = event.center;
3365
+ const { clientWidth, clientHeight } = event.target;
3366
+ const clientRect = event.target.getBoundingClientRect();
3367
+ const position = new three.Vector2(clientX, clientY).sub(new three.Vector2(clientRect.left, clientRect.top));
3368
+ const mouse = new three.Vector2((position.x / clientWidth) * 2 - 1, -(position.y / clientHeight) * 2 + 1);
3369
+ return { point: position, ndcPoint: mouse };
3370
+ }
3371
+
3372
+ /** 通过鼠标事件或者触摸事件,获取当前点击屏幕关联的射线与模型的交点 */
3373
+ function getIntersectionFromEvent(five, event) {
3374
+ const mouse = getPointFromHammerEvent(event).ndcPoint;
3375
+ const raycaster = new three.Raycaster();
3376
+ raycaster.setFromCamera(mouse, five.camera);
3377
+ return five.model.intersectRaycaster(raycaster);
3378
+ }
3379
+
3380
+ class EditController extends BaseController {
3381
+ type = 'edit';
3382
+ model = new Model({ userDistanceItemCreator: this.userDistanceItemCreator });
3383
+ pressPoint;
3384
+ hasAppendDashed = false;
3385
+ hasAppendMouseGroup = false;
3386
+ fiveElement;
3387
+ /** 上一个端点位置 */
3388
+ lastPoint = null;
3389
+ /** 鼠标点到上一个端点连接的虚线 */
3390
+ dashed;
3391
+ hammer;
3392
+ /** 根据 intersection 更新放大镜和吸附点 */
3393
+ onIntersectionUpdate = throttle((intersection, mesh) => {
3394
+ if (this.hasAppendMouseGroup === false) {
3395
+ this.group.add(this.mouseGroup);
3396
+ this.magnifier.appendTo(this.container);
3397
+ this.hasAppendMouseGroup = true;
3398
+ }
3399
+ const position = this.updateMouseGroup(intersection, mesh).position;
3400
+ this.pressPoint?.position.copy(position);
3401
+ this.updateDashed();
3402
+ requestAnimationFrame(() => this.magnifier.updateWithPoint(this.mouseGroup.position));
3403
+ this.five.needsRender = true;
3404
+ }, 20);
3405
+ constructor(params) {
3406
+ super(params);
3407
+ // ==================== 虚线 ====================
3408
+ this.dashed = new Line(new Point([0, 0, 0]), new Point([0, 0, 0]), this.model);
3409
+ this.dashed.mesh.setMaterial({ dashed: true, dashScale: 100 });
3410
+ // ==================== 事件监听 ====================
3411
+ // five
3412
+ this.five.on('cameraUpdate', this.onCameraUpdate);
3413
+ this.five.on('wantsPanGesture', this.onWantsPanGesture);
3414
+ this.five.on('wantsTapGesture', this.onWantsTapGesture);
3415
+ this.five.on('wantsToMoveToPano', this.onWantsToMoveToPano);
3416
+ this.five.on('intersectionOnModelUpdate', this.onIntersectionUpdate);
3417
+ // model
3418
+ this.model.hook.on('lineAdded', this.onLineChanged);
3419
+ this.model.hook.on('lineRemoved', this.onLineChanged);
3420
+ // hammer
3421
+ const fiveElement = this.five.getElement();
3422
+ if (fiveElement) {
3423
+ this.fiveElement = fiveElement;
3424
+ const hammer = new Hammer$1(fiveElement);
3425
+ this.hammer = hammer;
3426
+ hammer.on('tap', this.onTap);
3427
+ hammer.on('pan', this.onPan);
3428
+ hammer.on('press', this.onPress);
3429
+ hammer.on('panend', this.onPanEnd);
3430
+ }
3431
+ // fiveElement
3432
+ this.fiveElement?.addEventListener('mouseleave', this.onMouseLeave);
3433
+ // ==================== 其他 ====================
3434
+ this.hook.emit('anchorChange', null);
3435
+ this.five.refresh();
3436
+ }
3437
+ dispose() {
3438
+ super.dispose();
3439
+ this.group.remove(this.mouseGroup, this.dashed.mesh);
3440
+ // ==================== 解除事件监听 ====================
3441
+ // five
3442
+ this.five.off('cameraUpdate', this.onCameraUpdate);
3443
+ this.five.off('wantsPanGesture', this.onWantsPanGesture);
3444
+ this.five.off('wantsTapGesture', this.onWantsTapGesture);
3445
+ this.five.off('wantsToMoveToPano', this.onWantsToMoveToPano);
3446
+ this.five.off('intersectionOnModelUpdate', this.onIntersectionUpdate);
3447
+ // model
3448
+ this.model.hook.off('lineAdded', this.onLineChanged);
3449
+ this.model.hook.off('lineRemoved', this.onLineChanged);
3450
+ // hammer
3451
+ this.hammer?.destroy();
3452
+ // fiveElement
3453
+ this.fiveElement?.removeEventListener('mouseleave', this.onMouseLeave);
3454
+ this.magnifier.dispose();
3455
+ this.dashed.distanceItem.remove();
3456
+ this.five.needsRender = true;
3457
+ }
3458
+ getEditingLines() {
3459
+ return this.model.lines;
3460
+ }
3461
+ /** 撤销编辑 */
3462
+ revoke = () => {
3463
+ // ============ revoke points ============
3464
+ // 如果当前没有虚线,只有起始点,需要删除起始点,重置起始状态。并删除虚线实例
3465
+ if (this.model.lines.length === 0 && this.lastPoint) {
3466
+ this.lastPoint = null;
3467
+ this.hasAppendDashed = false;
3468
+ this.dashed.distanceItem.remove();
3469
+ this.group.remove(this.dashed.mesh);
3470
+ this.hook.emit('anchorChange', null);
3471
+ this.five.needsRender = true;
3472
+ return;
3473
+ }
3474
+ if (this.model.lines.length === 0 && !this.lastPoint)
3475
+ return;
3476
+ if (!this.lastPoint)
3477
+ return;
3478
+ const revokedLine = this.model.lines[this.model.lines.length - 1];
3479
+ const lastPoint = revokedLine.findAnotherPoint(this.lastPoint);
3480
+ if (!lastPoint)
3481
+ return;
3482
+ this.lastPoint = lastPoint;
3483
+ this.hook.emit('anchorChange', lastPoint.position);
3484
+ // ============ revoke lines ============
3485
+ this.group.remove(revokedLine.mesh);
3486
+ this.model.removeLine(revokedLine);
3487
+ // ============ revoke mouse group ============
3488
+ this.hasAppendMouseGroup = false;
3489
+ this.mouseGroup.position.copy(this.lastPoint.position);
3490
+ this.group.remove(this.mouseGroup);
3491
+ // ============ revoke lineDistance ============
3492
+ revokedLine.distanceItem.remove();
3493
+ // ============ revoke dashed ============
3494
+ this.updateDashed();
3495
+ // ============ revoke magnifier ============
3496
+ this.magnifier.dispose();
3497
+ this.five.needsRender = true;
3498
+ };
3499
+ onMouseLeave = () => {
3500
+ this.magnifier.dispose();
3501
+ this.group.remove(this.mouseGroup);
3502
+ this.hasAppendMouseGroup = false;
3503
+ if (this.lastPoint) {
3504
+ this.mouseGroup.position.copy(this.lastPoint.position);
3505
+ this.updateDashed();
3506
+ }
3507
+ };
3508
+ /** 编辑线条发生改变时通知外部 */
3509
+ onLineChanged = () => {
3510
+ this.hook.emit('editedLineChange', this.model.lines.map((line) => line.toCompletelyJson()));
3511
+ };
3512
+ onPress = (e) => {
3513
+ const [intersection] = getIntersectionFromEvent(this.five, e);
3514
+ if (!intersection || !intersection.face)
3515
+ return;
3516
+ const nowPoint = new Point(intersection.point);
3517
+ this.pressPoint = nowPoint;
3518
+ this.onIntersectionUpdate(intersection);
3519
+ };
3520
+ /**
3521
+ * 1. 如果之前没有长按行为「即没有长按点时」-> 滑动全景
3522
+ * 2. 如果有长按点,把长按点位置更新为当前位置
3523
+ */
3524
+ onPan = (e) => {
3525
+ if (!this.pressPoint)
3526
+ return;
3527
+ const [intersection] = getIntersectionFromEvent(this.five, e);
3528
+ if (!intersection || !intersection.face)
3529
+ return;
3530
+ this.onIntersectionUpdate(intersection);
3531
+ };
3532
+ onPanEnd = (e) => {
3533
+ if (!this.pressPoint)
3534
+ return;
3535
+ this.onTap(e);
3536
+ };
3537
+ /**
3538
+ * 1. 如果存在上一个点,需要绘制当前点到上一个点的连线
3539
+ * 2. 把上一个点的位置更新为当前点的位置
3540
+ * 3. 清除 mouseGroup 和 magnifier
3541
+ */
3542
+ onTap = (e) => {
3543
+ if (!this.hasAppendDashed) {
3544
+ this.dashed.distanceItem.appendTo(this.container);
3545
+ this.group.add(this.dashed.mesh);
3546
+ }
3547
+ this.hasAppendDashed = true;
3548
+ const [intersection] = getIntersectionFromEvent(this.five, e);
3549
+ this.updateMouseGroup(intersection);
3550
+ const nowPoint = new Point(this.mouseGroup.position);
3551
+ const lastPoint = this.lastPoint;
3552
+ if (nowPoint)
3553
+ this.lastPoint = nowPoint;
3554
+ if (nowPoint && lastPoint) {
3555
+ const line = new Line(lastPoint, nowPoint, this.model);
3556
+ line.distanceItem.appendTo(this.container);
3557
+ this.model.addLine(line);
3558
+ this.group.add(line.mesh);
3559
+ line.distanceItem.update(this.five);
3560
+ }
3561
+ this.pressPoint = undefined;
3562
+ this.hasAppendMouseGroup = false;
3563
+ this.magnifier.dispose();
3564
+ this.group.remove(this.mouseGroup);
3565
+ this.updateDashed();
3566
+ this.five.needsRender = true;
3567
+ this.hook.emit('anchorChange', nowPoint.position);
3568
+ };
3569
+ onWantsTapGesture = () => false;
3570
+ /** 编辑时取消走点 */
3571
+ onWantsToMoveToPano = () => false;
3572
+ /** 存在长按点时不能移动全景 */
3573
+ onWantsPanGesture = () => (this.pressPoint ? false : undefined);
3574
+ /** 移动全景时更新 distanceItem 在屏幕上的位置 */
3575
+ onCameraUpdate = () => {
3576
+ this.updateDistanceUI();
3577
+ this.dashed.distanceItem.update(this.five);
3578
+ };
3579
+ /** 更新虚线 */
3580
+ updateDashed = () => {
3581
+ if (!this.lastPoint)
3582
+ return;
3583
+ this.dashed.points[0].position.copy(this.lastPoint.position);
3584
+ this.dashed.points[1].position.copy(this.mouseGroup.position);
3585
+ this.dashed.mesh.setPoints(this.lastPoint.position, this.mouseGroup.position);
3586
+ this.dashed.distanceItem.update(this.five);
3587
+ };
3588
+ }
3589
+
3590
+ const svg = `<svg class="fpm__delete-icon" width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
3591
+ <defs>
3592
+ <linearGradient x1="21.443%" y1="100%" x2="67.281%" y2="6.672%" id="a">
3593
+ <stop stop-color="#FFFCFC" stop-opacity=".6" offset="0%" />
3594
+ <stop stop-color="#FFF" offset="100%" />
3595
+ </linearGradient>
3596
+ </defs>
3597
+ <path
3598
+ d="M14.932 3.545a.75.75 0 0 1 .102 1.494l-.102.006H13.83l-.979 8.813a2.05 2.05 0 0 1-1.882 1.818l-.155.006H4.868a2.05 2.05 0 0 1-2.037-1.824l-.98-8.813H.75a.75.75 0 0 1-.102-1.493l.102-.007h14.182zm-2.611 1.5H3.36l.961 8.648a.55.55 0 0 0 .369.46l.087.021.091.008h5.946a.55.55 0 0 0 .546-.49l.961-8.647zM10.795 0a.75.75 0 0 1 .102 1.493l-.102.007H4.886A.75.75 0 0 1 4.785.007L4.886 0h5.91z"
3599
+ transform="translate(2.16 2.16)"
3600
+ fill="url(#a)"
3601
+ fill-rule="nonzero"
3602
+ />
3603
+ </svg>`;
3604
+
3605
+ const image$1 = `data:image/png;base64,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`;
3606
+
3607
+ const image = `data:image/png;base64,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`;
3608
+
3609
+ class DeleteDom {
3610
+ visible = false;
3611
+ five;
3612
+ lines = [];
3613
+ points = [];
3614
+ onClick;
3615
+ content = document.createElement('div');
3616
+ container = document.createElement('div');
3617
+ constructor(five, opts) {
3618
+ this.five = five;
3619
+ this.onClick = opts?.onClick || (() => void 0);
3620
+ // container
3621
+ this.container.classList.add('fpm__delete');
3622
+ this.container.style.opacity = '0';
3623
+ this.container.style.position = 'absolute';
3624
+ this.container.style.left = '0';
3625
+ this.container.style.top = '0';
3626
+ this.container.style.transform = `translate3d(0, 0, 10px)`;
3627
+ this.container.style.pointerEvents = `none`;
3628
+ // content
3629
+ this.content.classList.add('fpm__delete-content');
3630
+ this.content.style.width = '67px';
3631
+ this.content.style.height = '31px';
3632
+ this.content.style.display = 'flex';
3633
+ this.content.style.alignItems = 'center';
3634
+ this.content.style.justifyContent = 'center';
3635
+ this.content.style.transform = 'translate(-50%, -50%)';
3636
+ this.content.style.color = '#fff';
3637
+ this.content.style.fontSize = '14px';
3638
+ this.content.style.lineHeight = '31px';
3639
+ this.content.style.borderRadius = '15px';
3640
+ this.content.style.backgroundSize = '100% 100%';
3641
+ this.content.style.cursor = 'pointer';
3642
+ this.content.style.userSelect = 'none';
3643
+ this.content.style.backgroundImage = `url(${image$1})`;
3644
+ this.content.innerHTML = `
3645
+ ${svg}
3646
+ <span>删除</span>
3647
+ `;
3648
+ this.container.append(this.content);
3649
+ const deleteSvgDom = this.content.querySelector('.fpm__delete-icon');
3650
+ if (deleteSvgDom) {
3651
+ deleteSvgDom.style.width = '20px';
3652
+ deleteSvgDom.style.height = '20px';
3653
+ deleteSvgDom.style.marginRight = '2px';
3654
+ }
3655
+ this.content.addEventListener('click', this.onClick);
3656
+ this.content.addEventListener('mouseenter', this.onMouseEnter);
3657
+ this.content.addEventListener('mouseleave', this.onMouseLeave);
3658
+ }
3659
+ dispose() {
3660
+ this.content.removeEventListener('click', this.onClick);
3661
+ this.content.removeEventListener('mouseenter', this.onMouseEnter);
3662
+ this.content.removeEventListener('mouseleave', this.onMouseLeave);
3663
+ this.container.remove();
3664
+ }
3665
+ appendTo(element) {
3666
+ element.append(this.container);
3667
+ return this;
3668
+ }
3669
+ setLines(lines) {
3670
+ this.lines = lines;
3671
+ this.points = Array.from(new Set(this.lines.map((line) => [line.points[0], line.points[1]]).flat(1)));
3672
+ return this;
3673
+ }
3674
+ updatePosition() {
3675
+ if (this.lines.length === 0)
3676
+ return this;
3677
+ const points = this.points.map((point) => point.position);
3678
+ const ndcPoints = points.map((point) => point.clone().project(this.five.camera));
3679
+ if (ndcPoints.some((ndcPoint) => Math.abs(ndcPoint.z) > 1))
3680
+ return this.hide();
3681
+ const xArray = ndcPoints.map((point) => point.x);
3682
+ const yArray = ndcPoints.map((point) => point.y);
3683
+ const centerX = (Math.min(...xArray) + Math.max(...xArray)) / 2;
3684
+ const maxY = Math.max(...yArray);
3685
+ const wrapper = this.container.parentElement;
3686
+ if (!wrapper)
3687
+ return this;
3688
+ const centerScreenX = ((centerX + 1) / 2) * wrapper.clientWidth;
3689
+ const maxScreenY = (-(maxY - 1) / 2) * wrapper.clientHeight;
3690
+ const x = centerScreenX;
3691
+ const y = maxScreenY - 34;
3692
+ this.container.style.transform = `translate3d(${x}px, ${y}px, 10px)`;
3693
+ return this.show();
3694
+ }
3695
+ hide() {
3696
+ this.visible = false;
3697
+ this.container.style.opacity = '0';
3698
+ this.container.style.pointerEvents = 'none';
3699
+ return this;
3700
+ }
3701
+ show() {
3702
+ this.visible = true;
3703
+ this.container.style.opacity = '1';
3704
+ this.container.style.pointerEvents = 'auto';
3705
+ return this;
3706
+ }
3707
+ onMouseEnter = () => {
3708
+ this.content.style.backgroundImage = `url(${image})`;
3709
+ };
3710
+ onMouseLeave = () => {
3711
+ this.content.style.backgroundImage = `url(${image$1})`;
3712
+ };
3713
+ }
3714
+
3715
+ /**
3716
+ * 获取一点对于线段上最近的一点,
3717
+ * 如果可以是过直线垂线的垂足,不行的话取线段的两端
3718
+ * @param point
3719
+ * @param linePoints
3720
+ * @return
3721
+ */
3722
+ function closestPointOnLine(point, linePoints) {
3723
+ const tA = point.x - linePoints[0].x;
3724
+ const tB = point.y - linePoints[0].y;
3725
+ const tC = linePoints[1].x - linePoints[0].x;
3726
+ const tD = linePoints[1].y - linePoints[0].y;
3727
+ // 设线段为 AB 线段,线段外一点为 P
3728
+ // tDot = AP 向量与 AB 向量乘积,tLenSq 为 |AB|平方。
3729
+ // tParam 是 AP 向量在 AB 向量投影向量 AC 与 AB 向量的比。
3730
+ const tDot = tA * tC + tB * tD;
3731
+ const tLenSq = tC * tC + tD * tD;
3732
+ const tParam = tDot / tLenSq;
3733
+ let tXx, tYy;
3734
+ if (tParam < 0 || samePointAt(linePoints[0], linePoints[1])) {
3735
+ tXx = linePoints[0].x;
3736
+ tYy = linePoints[0].y;
3737
+ }
3738
+ else if (tParam > 1) {
3739
+ tXx = linePoints[1].x;
3740
+ tYy = linePoints[1].y;
3741
+ }
3742
+ else {
3743
+ tXx = linePoints[0].x + tParam * tC;
3744
+ tYy = linePoints[0].y + tParam * tD;
3745
+ }
3746
+ return new three.Vector2(tXx, tYy);
3747
+ }
3748
+ /**
3749
+ * 检查两个点是否位置相同
3750
+ * point: { x: number, y: number }
3751
+ * @param point1
3752
+ * @param point2
3753
+ * @return
3754
+ */
3755
+ function samePointAt(point1, point2) {
3756
+ return point1.x === point2.x && point1.y === point2.y;
3757
+ }
3758
+
3759
+ function ndc2Screen(ndcPosition, containerSize) {
3760
+ const left = ((ndcPosition.x + 1) / 2) * containerSize.width;
3761
+ const top = (-(ndcPosition.y - 1) / 2) * containerSize.height;
3762
+ return new three.Vector2(left, top);
3763
+ }
3764
+
3765
+ /**
3766
+ * @param tapPoint 注意这里的坐标是相对于 FiveElement 的
3767
+ */
3768
+ // eslint-disable-next-line max-params
3769
+ function findClosestPoint(five, points, tapPoint, maxDistance) {
3770
+ const container = five.getElement();
3771
+ if (!container)
3772
+ return null;
3773
+ if (points.length === 0)
3774
+ return null;
3775
+ const containerSize = { width: container.clientWidth, height: container.clientHeight };
3776
+ const ndcPoints = points
3777
+ .map((point) => {
3778
+ const ndcPosition = point.position.clone().project(five.camera);
3779
+ if (!isNDCPointInScreen(ndcPosition))
3780
+ return { distance: Infinity, point };
3781
+ const screenPosition = ndc2Screen(ndcPosition, containerSize);
3782
+ const distance = screenPosition.distanceTo(tapPoint);
3783
+ return { distance, point };
3784
+ })
3785
+ .sort((a, b) => a.distance - b.distance);
3786
+ if (typeof maxDistance === 'number' && ndcPoints[0].distance > maxDistance)
3787
+ return null;
3788
+ return ndcPoints[0];
3789
+ }
3790
+
3791
+ function findAssociatedLines(line) {
3792
+ // 找跟这个线段相邻的线
3793
+ const mergeNextLine = (point, nextIndex, target) => {
3794
+ const nextLine = point.lines.find((line) => {
3795
+ const pointIndex = line.points.findIndex(({ id }) => id === point.id);
3796
+ if (pointIndex === nextIndex)
3797
+ return false;
3798
+ return true;
3799
+ });
3800
+ if (!nextLine)
3801
+ return target;
3802
+ const nextPoint = nextLine.points[nextIndex];
3803
+ if (!nextPoint)
3804
+ return target;
3805
+ return mergeNextLine(nextPoint, nextIndex, target.concat(nextLine));
3806
+ };
3807
+ const rightLines = mergeNextLine(line.points[0], 1, []);
3808
+ const leftLines = mergeNextLine(line.points[0], 0, []);
3809
+ const lines = rightLines.concat(leftLines);
3810
+ return lines;
3811
+ }
3812
+
3813
+ class WatchController extends BaseController {
3814
+ type = 'watch';
3815
+ deleteDom;
3816
+ highlightedLines = [];
3817
+ fiveElement;
3818
+ editPointState;
3819
+ hammer;
3820
+ constructor(params) {
3821
+ super(params);
3822
+ this.deleteDom = new DeleteDom(this.five, { onClick: this.deleteDomClickCallback }).appendTo(this.container);
3823
+ this.model.lines.forEach((line) => {
3824
+ line.distanceItem.appendTo(this.container);
3825
+ line.distanceItem.update(this.five);
3826
+ line.hook.on('selected', this.chooseLine);
3827
+ this.group.add(line.mesh);
3828
+ });
3829
+ const fiveElement = this.five.getElement();
3830
+ if (fiveElement) {
3831
+ this.fiveElement = fiveElement;
3832
+ const hammer = new Hammer(fiveElement);
3833
+ this.hammer = hammer;
3834
+ hammer.on('pan', this.onPan);
3835
+ hammer.on('panstart', this.onPanStart);
3836
+ hammer.on('panend', this.onPanEnd);
3837
+ }
3838
+ this.model.hook.on('lineRemoved', this.lineRemoved);
3839
+ this.five.on('cameraUpdate', this.onCameraUpdate);
3840
+ this.five.on('wantsTapGesture', this.wantsTapGesture);
3841
+ this.five.on('wantsPanGesture', this.wantsPanGesture);
3842
+ this.five.needsRender = true;
3843
+ }
3844
+ dispose() {
3845
+ super.dispose();
3846
+ this.deleteDom.dispose();
3847
+ this.model.hook.off('lineRemoved', this.lineRemoved);
3848
+ this.five.off('cameraUpdate', this.onCameraUpdate);
3849
+ this.five.off('wantsPanGesture', this.wantsPanGesture);
3850
+ this.five.off('wantsTapGesture', this.wantsTapGesture);
3851
+ this.five.needsRender = true;
3852
+ this.hook.emit('selectedChange', []);
3853
+ this.hammer?.destroy();
3854
+ }
3855
+ highlightLine(line) {
3856
+ if (line.selected)
3857
+ return;
3858
+ line.selected = true;
3859
+ this.group.add(line.lightMesh);
3860
+ line.distanceItem.highlight();
3861
+ this.five.needsRender = true;
3862
+ }
3863
+ clearHighlightLines() {
3864
+ if (this.group.children.length === 0)
3865
+ return;
3866
+ this.deleteDom.setLines([]).hide();
3867
+ this.model.lines.forEach((line) => {
3868
+ line.selected = false;
3869
+ line.distanceItem.unHighlight();
3870
+ this.group.remove(line.lightMesh);
3871
+ });
3872
+ this.highlightedLines = [];
3873
+ this.five.needsRender = true;
3874
+ }
3875
+ onPanStart = (e) => {
3876
+ if (this.model.points.length === 0 || !this.fiveElement)
3877
+ return;
3878
+ const mouse = getPointFromHammerEvent(e).point;
3879
+ const closestPoint = findClosestPoint(this.five, this.model.points, mouse, 20)?.point;
3880
+ if (!closestPoint) {
3881
+ this.editPointState = undefined;
3882
+ return;
3883
+ }
3884
+ const editPointState = {
3885
+ point: closestPoint,
3886
+ associatedLines: findAssociatedLines(closestPoint.lines[0]),
3887
+ };
3888
+ const cancelDragLine = this.hook.emit('wantsDragLine', {
3889
+ point: closestPoint.id,
3890
+ lines: editPointState.associatedLines.map(({ id }) => id),
3891
+ });
3892
+ if (cancelDragLine)
3893
+ return;
3894
+ this.editPointState = editPointState;
3895
+ this.magnifier.appendTo(this.container);
3896
+ this.group.add(this.mouseGroup);
3897
+ };
3898
+ onPanEnd = () => {
3899
+ if (!this.editPointState)
3900
+ return;
3901
+ // 把拖动的线从虚线转换为实线
3902
+ this.editPointState.point.lines.forEach((line) => line.mesh.setMaterial({ dashed: false }));
3903
+ // 还原选中态
3904
+ this.highlightLines(this.editPointState.associatedLines);
3905
+ this.editPointState = undefined;
3906
+ this.magnifier.dispose();
3907
+ this.group.remove(this.mouseGroup);
3908
+ };
3909
+ onPan = (e) => {
3910
+ if (!this.editPointState || !this.fiveElement)
3911
+ return;
3912
+ const mouse = getPointFromHammerEvent(e).ndcPoint;
3913
+ const raycaster = new three.Raycaster();
3914
+ raycaster.setFromCamera(mouse, this.five.camera);
3915
+ const [intersection] = this.five.model.intersectRaycaster(raycaster);
3916
+ if (!intersection)
3917
+ return;
3918
+ this.onIntersectionUpdate(intersection);
3919
+ };
3920
+ onIntersectionUpdate = (intersection, mesh) => {
3921
+ if (!this.editPointState)
3922
+ return;
3923
+ // 拖动过程中清除选中态
3924
+ this.clearHighlightLines();
3925
+ // 把拖动点相关的线变成虚线 & 改变相关线的位置
3926
+ this.editPointState.point.position.copy(intersection.point);
3927
+ this.editPointState.point.lines.forEach((line) => {
3928
+ line.mesh.setPoints(line.points[0].position.clone(), line.points[1].position.clone());
3929
+ line.lightMesh.setPoints(line.points[0].position.clone(), line.points[1].position.clone());
3930
+ line.mesh.setMaterial({ dashed: true });
3931
+ });
3932
+ this.updateDistanceUI();
3933
+ this.magnifier.updateWithPoint(intersection.point);
3934
+ this.mouseGroup.position.copy(intersection.point);
3935
+ if (mesh) {
3936
+ this.mouseGroup.quaternion.copy(mesh.quaternion);
3937
+ }
3938
+ else if (intersection.face) {
3939
+ const face = intersection.face.normal;
3940
+ const positionVector = face.clone().multiplyScalar(0.05);
3941
+ const position = intersection.point.clone().add(positionVector);
3942
+ const lookAtVector = position.clone().add(positionVector);
3943
+ this.mouseGroup.lookAt(lookAtVector);
3944
+ }
3945
+ this.five.needsRender = true;
3946
+ this.hook.emit('selectedChange', this.editPointState.associatedLines.map((line) => line.toCompletelyJson()));
3947
+ };
3948
+ wantsPanGesture = () => {
3949
+ if (this.editPointState)
3950
+ return false;
3951
+ };
3952
+ wantsTapGesture = (raycaster) => {
3953
+ const [target] = this.five.model.intersectRaycaster(raycaster);
3954
+ if (!target)
3955
+ return;
3956
+ const camera = this.five.camera;
3957
+ const ndcTarget = target.point.clone().project(camera);
3958
+ const screenWidth = this.container.clientWidth;
3959
+ const screenHeight = this.container.clientHeight;
3960
+ const targetScreenPosition = new three.Vector2(ndcTarget.x * screenWidth, ndcTarget.y * screenHeight);
3961
+ // 把线的端点全部映射到屏幕上,过滤掉不在视野内的线,同时乘以屏幕宽 & 高
3962
+ const screenLines = this.model.lines
3963
+ .map((line) => {
3964
+ const [startPoint, endPoint] = line.points;
3965
+ const ndcStartPoint = startPoint.position.clone().project(camera);
3966
+ const ndcEndPoint = endPoint.position.clone().project(camera);
3967
+ if (!isNDCPointInScreen(ndcStartPoint) && !isNDCPointInScreen(ndcEndPoint))
3968
+ return null;
3969
+ const startScreenPosition = new three.Vector2(ndcStartPoint.x * screenWidth, ndcStartPoint.y * screenHeight);
3970
+ const endScreenPosition = new three.Vector2(ndcEndPoint.x * screenWidth, ndcEndPoint.y * screenHeight);
3971
+ return { id: line.id, points: [startScreenPosition, endScreenPosition] };
3972
+ })
3973
+ .filter((line) => !!line);
3974
+ if (screenLines.length === 0)
3975
+ return;
3976
+ // 找这些线距离鼠标点击位置最近的线
3977
+ const distanceLines = screenLines
3978
+ .map((line) => {
3979
+ const closestPoint = closestPointOnLine(targetScreenPosition, line.points);
3980
+ return { id: line.id, distance: closestPoint.distanceTo(targetScreenPosition) };
3981
+ })
3982
+ .sort((a, b) => a.distance - b.distance);
3983
+ const closestScreenLine = distanceLines[0];
3984
+ if (closestScreenLine.distance > 20)
3985
+ return;
3986
+ const closestLine = this.model.lines.find(({ id }) => id === closestScreenLine.id);
3987
+ if (!closestLine)
3988
+ return;
3989
+ this.chooseLine(closestLine);
3990
+ return false;
3991
+ };
3992
+ chooseLine = (line) => {
3993
+ const highlightLines = findAssociatedLines(line);
3994
+ this.highlightLines(highlightLines);
3995
+ this.five.needsRender = true;
3996
+ this.hook.emit('selectedChange', highlightLines.map((line) => line.toCompletelyJson()));
3997
+ };
3998
+ highlightLines(lines) {
3999
+ this.clearHighlightLines();
4000
+ this.highlightedLines = lines;
4001
+ this.deleteDom.setLines(lines).updatePosition().show();
4002
+ lines.forEach((line) => this.highlightLine(line));
4003
+ }
4004
+ lineRemoved = (line) => {
4005
+ this.removeLine(line);
4006
+ // TODO: 这个逻辑不太好,改进一下
4007
+ this.hook.emit('selectedChange', this.model.lines.filter((line) => line.selected).map((line) => line.toCompletelyJson()));
4008
+ };
4009
+ onCameraUpdate = () => {
4010
+ this.updateDistanceUI();
4011
+ this.highlightedLines.length > 0 && this.deleteDom.updatePosition();
4012
+ };
4013
+ deleteDomClickCallback = () => {
4014
+ const firstLine = this.highlightedLines[0];
4015
+ // TODO: 优化折线的删除逻辑
4016
+ firstLine
4017
+ .getPolyline()
4018
+ .lines.slice()
4019
+ .reverse()
4020
+ .forEach((line) => this.model.removeLine(line));
4021
+ this.highlightedLines = [];
4022
+ // this.clearHighlightLines()
4023
+ // this.highlightedLines.forEach((line) => this.model.removeLine(line))
4024
+ this.deleteDom.setLines([]).hide();
4025
+ };
4026
+ }
4027
+
4028
+ const planTextureUrl = `data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAjoAAAI6CAMAAAAZlhLyAAACB1BMVEUAAAD+/v6qqqqgoKCLi4t7e3u4uLhvb29MTExZWVlCQkJgYGBqamo4ODi9vb3///9FRUXPz887Ozv///9QUFBWVlZdXV38/Pzj4+Pn5+f8/Pz5+fn9/f329vZoaGje3t78/Pz////x8fH8/Pzs7OyBgYHd3d39/f319fX+/v79/f2Kior6+vr////+/v76+vr+/v7////8/Pz9/f3+/v7m5ub7+/v+/v7+/v7j4+P////+/v79/f3d3d3h4eH4+Pj+/v79/f12dnbc3Nz9/f3w8PD9/f34+Pj9/f3+/v5jY2P8/Pz9/f2ioqJubm7v7+/+/v76+vr5+fnv7+/09PSDg4P////t7e3+/v7+/v7+/v7///+ZmZl7e3v7+/vy8vL+/v7+/v7p6en19fX////s7Oz+/v6lpaX+/v7r6+vg4OD9/f3q6ur///////+UlJTt7e329vbz8/Pg4OD///+wsLCdnZ2QkJDe3t77+/vz8/Pw8PD+/v7c3Nyqqqrw8PD4+Pj+/v7////4+Pj////s7Oyurq7f39/p6en8/Pz////8/Pz19fVycnK0tLT////q6ure3t7o6Oj////s7Oz39/fd3d3h4eH+/v7j4+P////+/v7n5+f///////////////+ysrLe3t7////////8/PzHx8fl5eX////39/fv7+/d3d3///8S/hbOAAAArHRSTlMAzhATFhkNGyEfIx4dJQ/OKwoozS4wMh3Uy4SPbjs34kJ9EAkGP+8Snk1nRRo5JYl2eDQiA88wY3PXRDYN6dyTX0s751SxPJdhPjRdV1M4ti0XFa+pQiq5aShQSE09IKJwWMilWr9SVzLC3wvFwplKvKKY9spfUEjge6yqnexaLpqQakgBtVz1wQe9i4s6ZaG788fGKIXx95TZzKbSuKu1s2LlsJb7dqiu/cSWYhzVwQAALl1JREFUeNrs0jFqalEUheE9C9ugAQloCg0WmuIJIbxHUsQUQhQEQUTINNI463fvqU2xT3G5xfetNYQ/+M3PT7SDfDo/T0/SIe+pCJAOt0mHvrgvAqRDUn061/vrNSDrOhqNpEOFURGQNfqWDlW+i4CadJ6lQ95zESAdbpMOfTEcPg+Hw4CsphvpUGM4bsoZB2SNW9JB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`;
4029
+ function getMouseGroup() {
4030
+ const group = new three.Group();
4031
+ const planGeometry = new three.PlaneGeometry(0.3, 0.3);
4032
+ const planTexture = new three.TextureLoader().load(planTextureUrl);
4033
+ planTexture.encoding = three.sRGBEncoding;
4034
+ const planMaterial = new three.MeshBasicMaterial({ map: planTexture, transparent: true, depthTest: false });
4035
+ const planMesh = new three.Mesh(planGeometry, planMaterial);
4036
+ const zPath = new three.CurvePath();
4037
+ zPath.add(new three.LineCurve3(new three.Vector3(0, 0, 0), new three.Vector3(0, 0, 0.1)));
4038
+ const zGeometry = new three.TubeGeometry(zPath, 10, 0.005);
4039
+ const zMaterial = new three.MeshBasicMaterial({ color: 0x33f1ef, depthTest: false, side: three.DoubleSide });
4040
+ const zMesh = new three.Mesh(zGeometry, zMaterial);
4041
+ const ballGeometry = new three.SphereGeometry(0.01, 32, 32);
4042
+ const ballMesh = new three.Mesh(ballGeometry, zMaterial);
4043
+ ballMesh.position.set(0, 0, 0.1);
4044
+ group.name = 'mouse-current';
4045
+ group.add(planMesh, zMesh, ballMesh);
4046
+ return group;
4047
+ }
4048
+
4049
+ const MAIN_NORMAL_PATH = 'M31.379 15.466a1.045 1.045 0 0 1-.92 1.076l-11.276.607a1.6 1.6 0 0 0-1.512 1.511l-.599 11.113a1.045 1.045 0 0 1-.92 1.075l-.164.008a1.183 1.183 0 0 1-1.123-.975l-.016-.164-.221-10.768a1.6 1.6 0 0 0-1.567-1.567l-11.3-.231-.165-.016a1.187 1.187 0 0 1-.964-.996l-.01-.127.007-.164c.061-.496.455-.876.958-.917l.118-.003 11.112-.599a1.6 1.6 0 0 0 1.498-1.37l.014-.142.607-11.276a1.045 1.045 0 0 1 1.076-.92c.573.015 1.055.46 1.13 1.019l.009.121.221 10.766a1.6 1.6 0 0 0 1.567 1.566l11.3.234a1.181 1.181 0 0 1 1.14 1.139z';
4050
+ const MAIN_DONE_PATH = 'M27.1772552,8.15828895 C27.8664561,7.48070421 28.5574369,7.81156875 28.8336646,8.04968716 C29.1098924,8.28780557 29.3990219,9.110014 28.8256559,9.79263351 L28.7110903,9.9165024 L13.9697229,25.1399531 C13.3288458,25.7700285 12.3239388,25.8070917 11.6402346,25.2511429 L11.5159715,25.1399531 L3.7056151,18.0063788 C3.01641417,17.3287941 3.00699739,16.2207954 3.68458213,15.5315945 C4.32230894,14.8829348 5.3413021,14.8364368 6.03356826,15.3981178 L6.15936649,15.5105615 L12.6856594,21.9049888 L27.1772552,8.15828895 Z';
4051
+ const MAIN_MOUSE_ENTER_FILL = 'url(#fpm__main-b)';
4052
+ const MAIN_MOUSE_LEAVE_FILL = 'url(#fpm__main-c)';
4053
+ const revokeSvg = `
4054
+ <svg class="fpm__revoke-icon" width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
4055
+ <defs>
4056
+ <linearGradient x1="47.631%" y1="55.183%" x2="2.967%" y2="86.323%" id="fpm__revoke-a">
4057
+ <stop stop-color="#FFF" offset="0%" />
4058
+ <stop stop-color="#FFF" stop-opacity=".5" offset="100%" />
4059
+ </linearGradient>
4060
+ <linearGradient x1="5.297%" y1="43.016%" x2="38.238%" y2="79.932%" id="fpm__revoke-b">
4061
+ <stop stop-color="#FFF" offset="0%" />
4062
+ <stop stop-color="#FFF" stop-opacity="0" offset="100%" />
4063
+ </linearGradient>
4064
+ </defs>
4065
+ <path
4066
+ d="M13.388 7.108c.552 0 1.005.42 1.06.957l.006.11v1.224c0 .921.745 1.667 1.666 1.667h7.184c5.804 0 10.509 4.616 10.509 10.309 0 5.595-4.544 10.15-10.21 10.305l-.3.004H8.924c-.917 0-1.66-.729-1.66-1.628 0-.846.658-1.541 1.5-1.62l.16-.008h14.38c3.972 0 7.191-3.158 7.191-7.053 0-3.81-3.08-6.916-6.933-7.049l-.257-.004H10.029l-.109-.005H8.212c-.245 0-.482-.085-.67-.237l-.09-.082a1.066 1.066 0 0 1-.065-1.422l.079-.086 5.175-5.077c.2-.195.468-.305.747-.305z"
4067
+ fill="url(#fpm__revoke-a)"
4068
+ fill-rule="nonzero"
4069
+ stroke="url(#fpm__revoke-b)"
4070
+ stroke-width=".5"
4071
+ />
4072
+ </svg>
4073
+ `;
4074
+ const exitSvg = `
4075
+ <svg class="fpm__exit-icon width="40" height="40" viewBox="0 0 40 40" xmlns="http://www.w3.org/2000/svg">
4076
+ <defs>
4077
+ <linearGradient x1="36.288%" y1="73.736%" x2="54.242%" y2="97.166%" id="fpm__exit-a">
4078
+ <stop stop-color="#FFF" offset="0%" />
4079
+ <stop stop-color="#FFF" stop-opacity=".5" offset="100%" />
4080
+ </linearGradient>
4081
+ <linearGradient x1="100%" y1="47.234%" x2="24.047%" y2="47.234%" id="fpm__exit-b">
4082
+ <stop stop-color="#FFF" offset="0%" />
4083
+ <stop stop-color="#FFF" stop-opacity=".005" offset="99.535%" />
4084
+ <stop stop-color="#FFF" stop-opacity="0" offset="100%" />
4085
+ </linearGradient>
4086
+ </defs>
4087
+ <path
4088
+ d="M22 7a1.5 1.5 0 0 1 .144 2.993L22 10h-9a1.5 1.5 0 0 0-1.493 1.356l-.007.144v17a1.5 1.5 0 0 0 1.356 1.493L13 30h9a1.5 1.5 0 0 1 .144 2.993L22 33h-9a4.5 4.5 0 0 1-4.495-4.288L8.5 28.5v-17a4.5 4.5 0 0 1 4.288-4.495L13 7h9zm6.317 7.755a1 1 0 0 1 .7.286l4.856 4.764a1 1 0 0 1-.7 1.713h-5.856V21.5h-8.032a1.5 1.5 0 1 1 0-3h6.365c.92 0 1.666-.746 1.667-1.667v-1.078a1 1 0 0 1 1-1z"
4089
+ fill="url(#fpm__exit-a)"
4090
+ fill-rule="nonzero"
4091
+ stroke="url(#fpm__exit-b)"
4092
+ stroke-width=".5"
4093
+ />
4094
+ </svg>
4095
+ `;
4096
+ const mainSvg = `
4097
+ <svg class="fpm__main-icon" width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg">
4098
+ <defs>
4099
+ <mask id="fpm__main-icon-mask">
4100
+ <rect id="fpm__main-icon-mask-black" x="0" y="0" width="30" height="30" fill="black"></rect>
4101
+ <rect id="fpm__main-icon-mask-white" x="0" y="0" width="0" height="30" fill="white"></rect>
4102
+ </mask>
4103
+ <linearGradient id="fpm__main-a" x1="25.371%" y1="0%" x2="109.587%" y2="172.268%">
4104
+ <stop stop-color="#FFF" offset="0%" />
4105
+ <stop stop-color="#FFF" stop-opacity=".77" offset="44.051%" />
4106
+ <stop stop-color="#FFF" stop-opacity=".201" offset="100%" />
4107
+ </linearGradient>
4108
+ <radialGradient id="fpm__main-b" fx="50%" fy="50%" r="50.864%" gradientTransform="matrix(-.98302 0 0 -1 .992 1)">
4109
+ <stop stop-color="#2D7CFF" offset="0%" />
4110
+ <stop stop-color="#2D7CFF" stop-opacity=".3" offset="100%" />
4111
+ </radialGradient>
4112
+ <radialGradient id="fpm__main-c" fx="50%" fy="50%" r="50.864%" gradientTransform="matrix(-.98302 0 0 -1 .992 1)">
4113
+ <stop stop-opacity=".4" offset="0%" />
4114
+ <stop stop-opacity=".12" offset="100%" />
4115
+ </radialGradient>
4116
+ </defs>
4117
+ <g fill="none" fill-rule="evenodd">
4118
+ <circle fill="url(#fpm__main-a)" cx="30" cy="30" r="30" />
4119
+ <path
4120
+ class="fpm__main-icon-path"
4121
+ d="${MAIN_NORMAL_PATH}"
4122
+ fill="${MAIN_MOUSE_LEAVE_FILL}"
4123
+ fill-rule="nonzero"
4124
+ transform="translate(14 14)"
4125
+ />
4126
+ </g>
4127
+ </svg>
4128
+ `;
4129
+ var htmlString = `
4130
+ <style>
4131
+ .fpm__revoke {
4132
+ opacity: 0.3;
4133
+ }
4134
+
4135
+ .fpm__revoke.enabled {
4136
+ opacity: 0.7;
4137
+ }
4138
+
4139
+ .fpm__revoke.enabled:hover {
4140
+ opacity: 1;
4141
+ }
4142
+
4143
+ .fpm__revoke-icon {
4144
+ width: 40px;
4145
+ height: 40px;
4146
+ margin-top: 10px;
4147
+ cursor: pointer;
4148
+ }
4149
+ </style>
4150
+ <div class="fpm_ui-bg"></div>
4151
+ <div class="fpm_operating-space">
4152
+ <div class="fpm__ui-item fpm__revoke">
4153
+ ${revokeSvg}
4154
+ <span class="fpm__text fpm__revoke-text">撤销</span>
4155
+ </div>
4156
+ <div class="fpm__ui-item fpm__main">
4157
+ ${mainSvg}
4158
+ <span class="fpm__text fpm__main-text">添加</span>
4159
+ </div>
4160
+ <div class="fpm__ui-item fpm__exit">
4161
+ ${exitSvg}
4162
+ <span class="fpm__text fpm__exit-text">退出</span>
4163
+ </div>
4164
+ </div>
4165
+ `;
4166
+
4167
+ const uiWrapperStyle = {
4168
+ position: 'absolute',
4169
+ top: '0',
4170
+ left: '0',
4171
+ width: '100%',
4172
+ height: '100%',
4173
+ opacity: '0',
4174
+ transform: 'translate(0, 10px)',
4175
+ transition: 'opacity 500ms ease-in-out, transform 500ms ease-in-out',
4176
+ };
4177
+ const operatingSpaceStyle = {
4178
+ position: 'absolute',
4179
+ left: '50%',
4180
+ bottom: '32px',
4181
+ transform: 'translateX(-50%)',
4182
+ width: '300px',
4183
+ height: '89px',
4184
+ display: 'flex',
4185
+ justifyContent: 'space-between',
4186
+ fontSize: '16px',
4187
+ pointerEvents: 'all',
4188
+ color: '#fff',
4189
+ zIndex: '10',
4190
+ };
4191
+ const buttonGroupStyle = {
4192
+ height: '100%',
4193
+ width: 'max-content',
4194
+ display: 'flex',
4195
+ flexDirection: 'column',
4196
+ justifyContent: 'space-between',
4197
+ alignItems: 'center',
4198
+ };
4199
+ // 操作区下方的背景
4200
+ const controllerBackgroundStyle = {
4201
+ position: 'absolute',
4202
+ bottom: '0',
4203
+ left: '0',
4204
+ opacity: '0.5',
4205
+ width: '100%',
4206
+ height: '184px',
4207
+ background: `linear-gradient(180deg, rgba(0,0,0,0.00) 0%, #000000 100%)`,
4208
+ zIndex: '0',
4209
+ };
4210
+ // item
4211
+ const mainItemStyle = {
4212
+ margin: '0 80px',
4213
+ opacity: '0.7',
4214
+ };
4215
+ const exitItemStyle = {
4216
+ opacity: '0.7',
4217
+ };
4218
+ // icon
4219
+ const mainIconStyle = {
4220
+ width: '60px',
4221
+ height: '60px',
4222
+ backgroundSize: '100%',
4223
+ cursor: 'pointer',
4224
+ };
4225
+ const exitIconStyle = {
4226
+ width: '40px',
4227
+ height: '40px',
4228
+ marginTop: '10px',
4229
+ backgroundSize: '100%',
4230
+ cursor: 'pointer',
4231
+ };
4232
+ // text
4233
+ const textStyle = {
4234
+ cursor: 'default',
4235
+ userSelect: 'none',
4236
+ };
4237
+
4238
+ const _requestAnimationFrame = window.requestAnimationFrame || ((fn) => setTimeout(fn, 16));
4239
+ const _cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
4240
+ /**
4241
+ * 在每个 AnimationFrame 中调用传入的函数
4242
+ * @param callback 每次 AnimationFrame 中调用的函数
4243
+ * @param frame 每秒运行多少次
4244
+ * @returns 返回一个函数,调用可以停止 AnimationFrameLoop
4245
+ */
4246
+ function requestAnimationFrameInterval(callback, frame = 60) {
4247
+ let index = -1;
4248
+ let oldTime = 0;
4249
+ let startTime = -1;
4250
+ const minDeltaTime = 1000 / frame;
4251
+ function loop(time) {
4252
+ startTime === -1 && (startTime = time);
4253
+ index = _requestAnimationFrame(loop);
4254
+ const deltaTime = time - oldTime;
4255
+ if (deltaTime < minDeltaTime)
4256
+ return;
4257
+ oldTime = time;
4258
+ callback && callback(time - startTime);
4259
+ }
4260
+ index = _requestAnimationFrame(loop);
4261
+ return function stop() {
4262
+ _cancelAnimationFrame(index);
4263
+ };
4264
+ }
4265
+ // export { Easing } from './tween'
4266
+ // export { default as tween } from './tween'
4267
+
4268
+ class BetterTween extends TWEEN__default["default"].Tween {
4269
+ disposeMethods = [];
4270
+ animationFrameDisposer;
4271
+ onDispose = (callback) => {
4272
+ this.disposeMethods.push(callback);
4273
+ return this;
4274
+ };
4275
+ play = () => {
4276
+ this.start(0);
4277
+ this.animationFrameDisposer = requestAnimationFrameInterval((time) => this.update(time));
4278
+ return this;
4279
+ };
4280
+ dispose = () => {
4281
+ this.stop();
4282
+ this.animationFrameDisposer?.();
4283
+ this.disposeMethods.forEach((fn) => fn());
4284
+ this.disposeMethods = [];
4285
+ TWEEN__default["default"].remove(this);
4286
+ };
4287
+ }
4288
+ function tweenProgress(duration, easing = TWEEN__default["default"].Easing.Linear.None) {
4289
+ const tween = new BetterTween({ progress: 0 }).to({ progress: 1 });
4290
+ if (duration !== undefined)
4291
+ tween.duration(duration);
4292
+ if (easing !== undefined)
4293
+ tween.easing(easing);
4294
+ return tween;
4295
+ }
4296
+
4297
+ class MainBtnController {
4298
+ container;
4299
+ measureController;
4300
+ mainIconMaskTween;
4301
+ mainElement;
4302
+ constructor(measureController, container) {
4303
+ this.measureController = measureController;
4304
+ this.container = container;
4305
+ this.mainElement = this.getMainElement();
4306
+ Object.assign(this.mainElement.mainIcon.style, mainIconStyle);
4307
+ Object.assign(this.mainElement.mainItem.style, mainItemStyle);
4308
+ this.change2Add();
4309
+ this.measureController.hook.on('modeChange', this.modeChangeHandler);
4310
+ this.mainElement.mainIcon.addEventListener('click', this.onClick);
4311
+ this.mainElement.mainIcon.addEventListener('mouseenter', this.onMouseEnter);
4312
+ this.mainElement.mainIcon.addEventListener('mouseleave', this.onMouseLeave);
4313
+ }
4314
+ dispose() {
4315
+ this.measureController.hook.off('modeChange', this.modeChangeHandler);
4316
+ this.measureController.hook.off('editedLineChange', this.editedLineChangeHandler);
4317
+ this.mainElement.mainIcon.removeEventListener('click', this.onClick);
4318
+ this.mainElement.mainIcon.removeEventListener('mouseenter', this.onMouseEnter);
4319
+ this.mainElement.mainIcon.removeEventListener('mouseleave', this.onMouseLeave);
4320
+ }
4321
+ getMainElement() {
4322
+ const mainTextDom = this.container.querySelector('.fpm__main-text');
4323
+ const mainItem = this.container.querySelector('.fpm__main');
4324
+ const mainIcon = this.container.querySelector('.fpm__main-icon');
4325
+ const pathDom = mainItem?.querySelector('.fpm__main-icon-path');
4326
+ const maskWhiteRect = mainIcon?.querySelector('#fpm__main-icon-mask-white');
4327
+ if (!mainItem || !mainTextDom || !mainIcon || !pathDom || !maskWhiteRect)
4328
+ throw new Error('cannot find dom');
4329
+ return { mainTextDom, mainItem, mainIcon, pathDom, maskWhiteRect };
4330
+ }
4331
+ change2Add() {
4332
+ this.measureController.hook.off('editedLineChange', this.editedLineChangeHandler);
4333
+ const { mainIcon, mainTextDom, pathDom } = this.mainElement;
4334
+ mainIcon.style.transition = mainTextDom.innerText === '完成' ? 'none' : 'transform 300ms ease-in-out';
4335
+ mainIcon.style.transform = 'rotate(0deg)';
4336
+ mainTextDom.innerText = '添加';
4337
+ pathDom?.setAttribute('d', MAIN_NORMAL_PATH);
4338
+ }
4339
+ change2Cancel(withAnime = true) {
4340
+ const { mainIcon, mainTextDom, pathDom } = this.mainElement;
4341
+ pathDom.setAttribute('d', MAIN_NORMAL_PATH);
4342
+ pathDom.setAttribute('mask', '');
4343
+ mainIcon.style.transition = withAnime ? 'transform 300ms ease-in-out' : 'none';
4344
+ mainIcon.style.transform = 'rotate(45deg)';
4345
+ mainTextDom && (mainTextDom.innerText = '取消');
4346
+ this.measureController.hook.on('editedLineChange', this.editedLineChangeHandler);
4347
+ }
4348
+ change2Done() {
4349
+ const { mainTextDom, mainIcon, pathDom, maskWhiteRect } = this.getMainElement();
4350
+ if (mainTextDom.innerText === '完成')
4351
+ return;
4352
+ mainIcon.style.transition = 'none';
4353
+ mainIcon.style.transform = 'rotate(0deg)';
4354
+ mainTextDom.innerText = '完成';
4355
+ pathDom.setAttribute('d', MAIN_DONE_PATH);
4356
+ pathDom.setAttribute('mask', `url(#fpm__main-icon-mask)`);
4357
+ this.mainIconMaskTween?.dispose();
4358
+ this.mainIconMaskTween = tweenProgress()
4359
+ .easing(TWEEN__default["default"].Easing.Quartic.InOut)
4360
+ .onUpdate(({ progress }) => {
4361
+ maskWhiteRect.setAttribute('width', (progress * 30).toString());
4362
+ })
4363
+ .onComplete(() => this.mainIconMaskTween?.dispose())
4364
+ .play();
4365
+ }
4366
+ /* 鼠标移入时变成蓝色 */
4367
+ onMouseEnter = () => {
4368
+ const { mainItem, pathDom } = this.mainElement;
4369
+ mainItem.style.opacity = '1';
4370
+ pathDom.setAttribute('fill', MAIN_MOUSE_ENTER_FILL);
4371
+ };
4372
+ /* 鼠标移出时变成灰色 */
4373
+ onMouseLeave = () => {
4374
+ const { mainItem, pathDom } = this.mainElement;
4375
+ mainItem.style.opacity = '0.7';
4376
+ pathDom.setAttribute('fill', MAIN_MOUSE_LEAVE_FILL);
4377
+ };
4378
+ onClick = () => {
4379
+ const mode = this.measureController.getCurrentMode();
4380
+ mode === 'Watch' ? this.measureController.changeMode('Edit') : this.measureController.save().changeMode('Watch');
4381
+ };
4382
+ editedLineChangeHandler = (lines) => {
4383
+ // 线的数量大于 1 时,没有状态的变化
4384
+ if (lines.length > 1)
4385
+ return;
4386
+ // 因为撤销导致的状态变更 -> 取消
4387
+ if (lines.length === 0)
4388
+ return this.change2Cancel(false);
4389
+ this.change2Done();
4390
+ };
4391
+ modeChangeHandler = (mode) => {
4392
+ mode === 'Watch' ? this.change2Add() : this.change2Cancel();
4393
+ };
4394
+ }
4395
+
4396
+ class Revoke {
4397
+ container;
4398
+ revokeIcon;
4399
+ revokeItem;
4400
+ measureController;
4401
+ constructor(measureController, container) {
4402
+ this.measureController = measureController;
4403
+ this.container = container;
4404
+ const revokeIcon = this.container.querySelector('.fpm__revoke-icon');
4405
+ const revokeItem = this.container.querySelector('.fpm__revoke');
4406
+ if (!revokeIcon || !revokeItem)
4407
+ throw new Error('不正确的选择器');
4408
+ this.revokeIcon = revokeIcon;
4409
+ this.revokeItem = revokeItem;
4410
+ this.revokeIcon.addEventListener('click', this.onClick);
4411
+ measureController.hook.on('modeChange', this.onModeChange);
4412
+ }
4413
+ dispose() {
4414
+ this.revokeIcon.removeEventListener('click', this.onClick);
4415
+ this.measureController.hook.off('modeChange', this.onModeChange);
4416
+ }
4417
+ onClick = () => {
4418
+ this.measureController.revoke();
4419
+ };
4420
+ onModeChange = (mode) => {
4421
+ if (mode !== 'Edit') {
4422
+ this.revokeItem.classList.remove('enabled');
4423
+ return;
4424
+ }
4425
+ this.revokeItem.classList.add('enabled');
4426
+ };
4427
+ handleRevoke = () => {
4428
+ return () => { };
4429
+ };
4430
+ }
4431
+
4432
+ class UIController {
4433
+ revoke;
4434
+ container;
4435
+ mainController;
4436
+ disposers = [];
4437
+ measureController;
4438
+ constructor(measureController, params) {
4439
+ this.measureController = measureController;
4440
+ this.container = document.createElement('div');
4441
+ this.container.innerHTML = htmlString;
4442
+ this.container.classList.add('fpm__ui-controller');
4443
+ params.container.appendChild(this.container);
4444
+ const textDoms = this.container.querySelectorAll('.fpm__text');
4445
+ const UIItems = this.container.querySelectorAll('.fpm__ui-item');
4446
+ const bgDom = this.container.querySelector('.fpm_ui-bg');
4447
+ const operatingSpaceDom = this.container.querySelector('.fpm_operating-space');
4448
+ Object.assign(bgDom?.style, controllerBackgroundStyle);
4449
+ Object.assign(operatingSpaceDom?.style, operatingSpaceStyle);
4450
+ Object.assign(this.container.style, uiWrapperStyle);
4451
+ UIItems.forEach((item) => Object.assign(item.style, buttonGroupStyle));
4452
+ textDoms.forEach((item) => Object.assign(item.style, textStyle));
4453
+ }
4454
+ dispose() {
4455
+ this.hide();
4456
+ this.container.remove();
4457
+ }
4458
+ show() {
4459
+ this.container.style.opacity = '1';
4460
+ this.container.style.transform = 'translate(0, 0)';
4461
+ this.revoke = new Revoke(this.measureController, this.container);
4462
+ this.mainController = new MainBtnController(this.measureController, this.container);
4463
+ this.disposers.push(this.handleExit());
4464
+ return this;
4465
+ }
4466
+ hide() {
4467
+ this.container.style.opacity = '0';
4468
+ this.container.style.transform = 'translate(0, 10px)';
4469
+ this.revoke?.dispose();
4470
+ this.mainController?.dispose();
4471
+ this.disposers.forEach((disposer) => disposer());
4472
+ this.disposers = [];
4473
+ return this;
4474
+ }
4475
+ handleExit = () => {
4476
+ const exitIcon = this.container.querySelector('.fpm__exit-icon');
4477
+ const exitItem = this.container.querySelector('.fpm__exit');
4478
+ if (!exitItem || !exitIcon)
4479
+ throw new Error('cannot find dom');
4480
+ Object.assign(exitItem.style, exitItemStyle);
4481
+ Object.assign(exitIcon?.style, exitIconStyle);
4482
+ const onMouseEnter = () => (exitItem.style.opacity = '1');
4483
+ const onMouseLeave = () => (exitItem.style.opacity = '0.7');
4484
+ const handleClick = () => {
4485
+ this.measureController.disable();
4486
+ };
4487
+ exitIcon.addEventListener('click', handleClick);
4488
+ exitIcon.addEventListener('mouseenter', onMouseEnter);
4489
+ exitIcon.addEventListener('mouseleave', onMouseLeave);
4490
+ return () => {
4491
+ exitIcon.removeEventListener('click', handleClick);
4492
+ exitIcon.removeEventListener('mouseenter', onMouseEnter);
4493
+ exitIcon.removeEventListener('mouseleave', onMouseLeave);
4494
+ };
4495
+ };
4496
+ }
4497
+
4498
+ class GuideController {
4499
+ measureController;
4500
+ textDom = document.createElement('span');
4501
+ container = document.createElement('div');
4502
+ hasAnchor = false;
4503
+ constructor(measureController, params) {
4504
+ this.initDom();
4505
+ params.container.append(this.container);
4506
+ this.measureController = measureController;
4507
+ measureController.hook.on('modeChange', this.onModelChange);
4508
+ measureController.hook.on('anchorChange', this.anchorChange);
4509
+ measureController.hook.on('editedLineChange', this.onEditedLineChange);
4510
+ }
4511
+ dispose() {
4512
+ this.hide();
4513
+ this.container.remove();
4514
+ }
4515
+ show() {
4516
+ this.container.style.opacity = '1';
4517
+ this.container.style.transform = 'translate(0, 0)';
4518
+ return this;
4519
+ }
4520
+ hide() {
4521
+ this.container.style.opacity = '0';
4522
+ this.container.style.transform = 'translate(0, -10px)';
4523
+ this.measureController.hook.off('modeChange', this.onModelChange);
4524
+ this.measureController.hook.off('anchorChange', this.anchorChange);
4525
+ this.measureController.hook.off('editedLineChange', this.onEditedLineChange);
4526
+ return this;
4527
+ }
4528
+ initDom() {
4529
+ const container = this.container;
4530
+ const textDom = this.textDom;
4531
+ container.classList.add('fpm__guide-container');
4532
+ container.style.position = 'absolute';
4533
+ container.style.top = '0px';
4534
+ container.style.left = '0px';
4535
+ container.style.width = '100%';
4536
+ container.style.height = '110px';
4537
+ container.style.display = 'flex';
4538
+ container.style.alignItems = 'center';
4539
+ container.style.justifyContent = 'center';
4540
+ container.style.transform = 'translate(0, -10px)';
4541
+ container.style.background = `linear-gradient(180deg, rgba(0,0,0,0.40) 0%, rgba(0,0,0,0.00) 100%)`;
4542
+ container.style.transition = 'opacity 500ms ease-in-out, transform 500ms ease-in-out';
4543
+ container.style.opacity = '0';
4544
+ textDom.classList.add('fpm__guide-text');
4545
+ textDom.style.color = '#fff';
4546
+ textDom.style.fontSize = '20px';
4547
+ textDom.innerText = `点击下方“添加”开始测距`;
4548
+ container.appendChild(textDom);
4549
+ }
4550
+ onModelChange = (mode) => {
4551
+ if (mode === 'Watch') {
4552
+ this.textDom.innerText = ``;
4553
+ return;
4554
+ }
4555
+ this.textDom.innerText = `请选择第一个测量点,Esc或单击鼠标右键可取消选择`;
4556
+ };
4557
+ anchorChange = (anchor) => {
4558
+ if (!this.hasAnchor && !!anchor) {
4559
+ this.hasAnchor = true;
4560
+ this.textDom.innerText = `选择下一个测量点,Esc或单击鼠标右键取消选择`;
4561
+ }
4562
+ else if (!anchor) {
4563
+ this.hasAnchor = false;
4564
+ this.textDom.innerText = `请选择第一个测量点,Esc或单击鼠标右键可取消选择`;
4565
+ }
4566
+ };
4567
+ onEditedLineChange = (lines) => {
4568
+ if (lines.length === 1) {
4569
+ this.textDom.innerText = `可以连续选择测量点,或点击下方“完成”结束测量(Esc取消,Command+S保存)`;
4570
+ }
4571
+ };
4572
+ }
4573
+
4574
+ /** 快捷键控制器 */
4575
+ class ShortcutKeyController {
4576
+ five;
4577
+ measureController;
4578
+ constructor(measureController, five) {
4579
+ this.five = five;
4580
+ this.measureController = measureController;
4581
+ const fiveElement = this.five.getElement();
4582
+ if (!fiveElement)
4583
+ return;
4584
+ document.body.addEventListener('keydown', this.onKeyDown);
4585
+ fiveElement.addEventListener('mousedown', this.onMouseDown);
4586
+ }
4587
+ dispose() {
4588
+ const fiveElement = this.five.getElement();
4589
+ if (!fiveElement)
4590
+ return;
4591
+ document.body.removeEventListener('keydown', this.onKeyDown);
4592
+ fiveElement.removeEventListener('mousedown', this.onMouseDown);
4593
+ }
4594
+ escape() {
4595
+ if (this.measureController.getCurrentMode() === 'Watch')
4596
+ return this.measureController.disable();
4597
+ return this.measureController.changeMode('Watch');
4598
+ }
4599
+ onKeyDown = (e) => {
4600
+ // Command + S -> 保存 & 更改场景
4601
+ if (e.metaKey && e.code === 'KeyS') {
4602
+ this.measureController.save().changeMode('Watch');
4603
+ e.preventDefault();
4604
+ return;
4605
+ }
4606
+ // Escape -> 切换到观察模式 / 如果已经在观察模式,退出功能
4607
+ if (e.code === 'Escape')
4608
+ return this.escape();
4609
+ };
4610
+ onMouseDown = (e) => {
4611
+ // 鼠标右键取消
4612
+ if (e.button !== 2)
4613
+ return;
4614
+ e.preventDefault();
4615
+ this.escape();
4616
+ };
4617
+ }
4618
+
4619
+ class MeasureController {
4620
+ hasOpen = false;
4621
+ hook = new five.Subscribe();
4622
+ five;
4623
+ model;
4624
+ group;
4625
+ magnifier;
4626
+ fiveHelper;
4627
+ useUIController;
4628
+ params;
4629
+ useGuideController;
4630
+ container = document.createElement('div');
4631
+ shortcutKeyController;
4632
+ controller = null;
4633
+ controllerParams;
4634
+ constructor(five, params) {
4635
+ this.five = five;
4636
+ this.params = params;
4637
+ this.model = new Model({ userDistanceItemCreator: this.params.userDistanceItemCreator });
4638
+ this.fiveHelper = new FiveHelper(five);
4639
+ // magnifier
4640
+ const magnifierSize = 190;
4641
+ const magnifierScale = 2;
4642
+ this.magnifier = new Magnifier(five, { scale: magnifierScale, width: magnifierSize, height: magnifierSize });
4643
+ // ==================== Group ====================
4644
+ this.group = new three.Group();
4645
+ this.group.name = 'plugin-measure-group';
4646
+ this.container.classList.add('five-plugin-measure-container');
4647
+ this.container.style.position = 'relative';
4648
+ this.container.style.pointerEvents = 'none';
4649
+ this.container.style.width = '100%';
4650
+ this.container.style.height = '100%';
4651
+ this.container.style.background = 'rgba(0, 0, 0, 0.15)';
4652
+ this.controllerParams = {
4653
+ five: this.five,
4654
+ hook: this.hook,
4655
+ group: this.group,
4656
+ model: this.model,
4657
+ magnifier: this.magnifier,
4658
+ container: this.container,
4659
+ fiveHelper: this.fiveHelper,
4660
+ mouseGroup: getMouseGroup(),
4661
+ userDistanceItemCreator: this.params.userDistanceItemCreator,
4662
+ };
4663
+ if (this.params.useUIController !== false)
4664
+ this.useUIController = new UIController(this, this.controllerParams);
4665
+ if (this.params.useUIController !== false)
4666
+ this.useGuideController = new GuideController(this, this.controllerParams);
4667
+ }
4668
+ appendTo(parent) {
4669
+ parent.append(this.container);
4670
+ }
4671
+ dispose() {
4672
+ this.disable();
4673
+ this.useUIController?.dispose();
4674
+ this.magnifier?.dispose();
4675
+ this.five.needsRender = true;
4676
+ }
4677
+ /** 加载数据
4678
+ * @description 数据加载时会覆盖当前已保存的数据
4679
+ * @description 如果当前正在编辑中,会自动退出并保存编辑
4680
+ */
4681
+ load(data) {
4682
+ this.model.parse(data);
4683
+ this.save();
4684
+ }
4685
+ /** 插件功能入口
4686
+ * @description 会隐藏鼠标的默认聚焦环
4687
+ * @description 会隐藏当前 VR 内的点位展示
4688
+ */
4689
+ enable() {
4690
+ if (this.hasOpen)
4691
+ return;
4692
+ this.hasOpen = true;
4693
+ this.five.scene.add(this.group);
4694
+ // 隐藏点位和鼠标聚焦环
4695
+ this.five.helperVisible = false;
4696
+ this.controller = new WatchController(this.controllerParams);
4697
+ this.useUIController?.show();
4698
+ this.useGuideController?.show();
4699
+ this.shortcutKeyController = new ShortcutKeyController(this, this.five);
4700
+ this.hook.emit('enable', true);
4701
+ }
4702
+ /** 关闭插件功能
4703
+ * @description 清除标尺线条
4704
+ * @description 还原点位展示和默认鼠标 UI
4705
+ */
4706
+ disable() {
4707
+ this.hasOpen = false;
4708
+ // 展示点位和鼠标聚焦环
4709
+ this.controller?.dispose();
4710
+ this.useUIController?.hide();
4711
+ this.useGuideController?.hide();
4712
+ this.shortcutKeyController?.dispose();
4713
+ this.controller = null;
4714
+ this.five.helperVisible = true;
4715
+ this.five.scene.remove(this.group);
4716
+ this.five.needsRender = true;
4717
+ this.hook.emit('disable', true);
4718
+ }
4719
+ getCurrentMode = () => {
4720
+ if (this.controller instanceof EditController)
4721
+ return 'Edit';
4722
+ if (this.controller instanceof WatchController)
4723
+ return 'Watch';
4724
+ return null;
4725
+ };
4726
+ /** 变更场景
4727
+ * @description 如果从编辑场景改变到观看场景,不会自动保存,默认丢弃所有改动
4728
+ */
4729
+ changeMode = (mode) => {
4730
+ if (!this.hasOpen)
4731
+ return;
4732
+ if (this.getCurrentMode() === mode)
4733
+ return;
4734
+ this.controller?.dispose();
4735
+ const controllerMap = {
4736
+ Watch: WatchController,
4737
+ Edit: EditController,
4738
+ };
4739
+ if (!controllerMap[mode])
4740
+ throw new Error('不存在的 Mode');
4741
+ this.controller = new controllerMap[mode](this.controllerParams);
4742
+ this.hook.emit('modeChange', mode);
4743
+ };
4744
+ /** 撤销编辑 */
4745
+ revoke() {
4746
+ if (!(this.controller instanceof EditController))
4747
+ return;
4748
+ this.controller.revoke();
4749
+ return;
4750
+ }
4751
+ removeLineByID(lineID) {
4752
+ this.model.removeLineByID(lineID);
4753
+ }
4754
+ /**
4755
+ * 高亮当前线段
4756
+ */
4757
+ highlightLine(lineID) {
4758
+ if (this.getCurrentMode() !== 'Watch')
4759
+ return false;
4760
+ const line = this.model.getLineByID(lineID);
4761
+ if (!line)
4762
+ return false;
4763
+ this.controller.highlightLine(line);
4764
+ return true;
4765
+ }
4766
+ clearHighlightLines() {
4767
+ if (this.getCurrentMode() !== 'Watch')
4768
+ return false;
4769
+ this.controller.clearHighlightLines();
4770
+ return true;
4771
+ }
4772
+ /** 保存编辑 */
4773
+ save() {
4774
+ if (!(this.controller instanceof EditController))
4775
+ return this;
4776
+ this.model.mergeModel(this.controller.model);
4777
+ return this;
4778
+ }
4779
+ /** 把当前以保存的数据转换成 JSON 对象 */
4780
+ toJson() {
4781
+ return this.model.toJson();
4782
+ }
4783
+ }
4784
+
4785
+ const PanoMeasurePlugin = function MeasurePlugin(five, params) {
4786
+ return new MeasureController(five, params);
4787
+ };
4788
+
4789
+ module.exports = PanoMeasurePlugin;