@shijiu/jsview-vue-samples 2.3.151-test.0 → 2.3.728-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/ABImageAlt/App.vue +114 -0
  2. package/ABImageAlt/Item.vue +133 -0
  3. package/{MetroWidgetDemos/SkeletonDiagram/assets/imageList.json → ABImageAlt/assets/imageList.js} +9 -1
  4. package/ABImageAlt/data.js +17 -0
  5. package/AI_Check_Rules.txt +5 -0
  6. package/AnimPicture/App.vue +20 -10
  7. package/ApicSwitch/App.vue +90 -0
  8. package/ApicSwitch/TabItem.vue +65 -0
  9. package/ApicSwitch/WebpShow.vue +24 -0
  10. package/ApicSwitch/data.js +50 -0
  11. package/Basic/AI_skills_update.md +1 -0
  12. package/Basic/components/div/ColorFormatTest.vue +93 -0
  13. package/Basic/components/div/DivRadius.vue +97 -15
  14. package/Basic/components/div/DivTag3Group.vue +30 -0
  15. package/Basic/components/img/ImageType.vue +65 -0
  16. package/Basic/components/panel/Panel2.vue +13 -1
  17. package/Basic/components/text/TextAlign.vue +7 -1
  18. package/BlobLoadTest/App.vue +201 -0
  19. package/BreakLinesApi/App.vue +82 -0
  20. package/CanvasDrawChart/App.vue +11 -0
  21. package/CanvasDrawChart/Graph1.vue +104 -0
  22. package/CanvasDrawChart/Graph2.vue +115 -0
  23. package/DemoForOperator/Blur/Blur.vue +1 -1
  24. package/DemoForOperator/Blur/BlurInOut/BlurInOut.vue +49 -23
  25. package/DemoForOperator/Blur/BlurInOut/StaticBgSlide.vue +1 -1
  26. package/DemoForOperator/Blur/BlurPopup/BlurPopup.vue +156 -20
  27. package/DemoForOperator/BookFlip/App.vue +1 -1
  28. package/DemoForOperator/Bounce/FreeMoveBuilder.js +1 -1
  29. package/DemoForOperator/Firework1/App.vue +12 -1
  30. package/DemoForOperator/Firework1/Fireworks.vue +18 -0
  31. package/DemoForOperator/FlipPage/FlipPage/FlipPage.vue +1 -0
  32. package/DemoForOperator/Focus/Alpha/Item.vue +1 -0
  33. package/DemoForOperator/Focus/Light/Item.vue +1 -0
  34. package/DemoForOperator/Focus/Normal/Item.vue +1 -0
  35. package/DemoForOperator/Genie/App.vue +20 -6
  36. package/DemoForOperator/Genie/App2.vue +61 -0
  37. package/DemoForOperator/Genie/geniePakcer/GenieImage.vue +298 -0
  38. package/DemoForOperator/Genie/geniePakcer/GenieSlot.vue +292 -0
  39. package/DemoForOperator/Genie/geniePakcer/GenieTools.ts +463 -0
  40. package/DemoForOperator/Jigsaw/JigsawFull.vue +12 -7
  41. package/DemoForOperator/Jigsaw/JigsawSingle.vue +13 -7
  42. package/DemoForOperator/LongChatBox/App.vue +13 -13
  43. package/DemoForOperator/LongChatBox/Bubble.vue +78 -66
  44. package/DemoForOperator/LongChatBox/LongChat.vue +67 -36
  45. package/DemoForOperator/LongChatBox/testData.js +7 -44
  46. package/DemoForOperator/Sound/Bounce/FreeMoveBuilder.js +1 -1
  47. package/DemoForOperator/routeList.js +8 -2
  48. package/DemoHomepage/App.vue +74 -1
  49. package/DemoHomepage/components/BodyFrame.vue +5 -0
  50. package/DemoHomepage/components/TabFrame.vue +1 -1
  51. package/DemoHomepage/router.js +749 -165
  52. package/DemoHomepage/views/Homepage.vue +60 -2
  53. package/DemoHomepage/watchTest.vue +50 -0
  54. package/DomRenderer/App.vue +133 -0
  55. package/FilterDemo/AnimatePic.vue +63 -17
  56. package/FilterDemo/App.vue +3 -3
  57. package/FlexCellDemo/AI_skills_update.md +4 -0
  58. package/FlexCellDemo/TestFrame1.vue +12 -2
  59. package/FlexCellDemo/TestFrame2.vue +10 -1
  60. package/FlexCellDemo/TestFrame3.vue +114 -59
  61. package/FpsLimit/App.vue +102 -0
  62. package/FreeMove/App.vue +24 -279
  63. package/FreeMove/TestScene1.vue +260 -0
  64. package/FreeMove/TestScene3.vue +431 -0
  65. package/FreeMoveChildAttract/App.vue +18 -8
  66. package/FreeMoveLink/App.vue +51 -22
  67. package/Hover/App.vue +144 -0
  68. package/HttpRequestSSE/SSEReader.js +200 -0
  69. package/ImpactStop/App.vue +2 -2
  70. package/Input/FullKeyboard.vue +3 -3
  71. package/Input/InputPanel.vue +63 -3
  72. package/JsvLine/App.vue +53 -38
  73. package/LatexDemo/App.vue +3 -1
  74. package/LatexFormula/App.vue +196 -0
  75. package/LongImage/App.vue +1 -1
  76. package/LongImage/LongImageScroll.vue +111 -46
  77. package/LongImage/Scroll.vue +28 -9
  78. package/LongText/LongTextScroll.vue +14 -1
  79. package/Markdown/App.vue +36 -0
  80. package/Markdown/Bubble.vue +109 -0
  81. package/Markdown/LongChat.vue +216 -0
  82. package/Markdown/data.js +633 -0
  83. package/MetroWidgetDemos/AI_skills_update.md +2 -0
  84. package/MetroWidgetDemos/EpgFlowListType/App.vue +206 -0
  85. package/MetroWidgetDemos/EpgFlowListType/components/ContentCard.vue +105 -0
  86. package/MetroWidgetDemos/EpgFlowListType/components/FloorSection.vue +131 -0
  87. package/MetroWidgetDemos/EpgFlowListType/components/LeftTabItem.vue +41 -0
  88. package/MetroWidgetDemos/EpgFlowListType/data.js +78 -0
  89. package/MetroWidgetDemos/ListExpand/ChildItem.vue +130 -0
  90. package/MetroWidgetDemos/ListExpand/ExpandItem.vue +375 -0
  91. package/MetroWidgetDemos/ListExpand/ExpandItem1.vue +403 -0
  92. package/MetroWidgetDemos/ListExpand/assets/arrow-down.png +0 -0
  93. package/MetroWidgetDemos/ListExpand/assets/up-arrow.png +0 -0
  94. package/MetroWidgetDemos/ListExpand/components/WidgetListHandler.vue +150 -0
  95. package/MetroWidgetDemos/ListExpand/index.vue +88 -0
  96. package/MetroWidgetDemos/ListExpand/list.js +2421 -0
  97. package/MetroWidgetDemos/RefreshDemo/App.vue +14 -1
  98. package/MetroWidgetDemos/RenderAccelerate/App.vue +142 -0
  99. package/MetroWidgetDemos/RenderAccelerate/AppPage.vue +78 -0
  100. package/MetroWidgetDemos/RenderAccelerate/AppTab.vue +62 -0
  101. package/MetroWidgetDemos/RenderAccelerate/ContentItem.vue +409 -0
  102. package/MetroWidgetDemos/RenderAccelerate/Item.vue +67 -0
  103. package/MetroWidgetDemos/RenderAccelerate/TabItem.vue +100 -0
  104. package/MetroWidgetDemos/RenderAccelerate/ViewSwiper.vue +215 -0
  105. package/MetroWidgetDemos/RenderAccelerate/WidgetItem.vue +107 -0
  106. package/MetroWidgetDemos/SkeletonDiagram/App.vue +35 -8
  107. package/MetroWidgetDemos/SkeletonDiagram/Item.vue +11 -2
  108. package/MetroWidgetDemos/SkeletonDiagram/assets/imageList.js +245 -0
  109. package/MetroWidgetDemos/SkeletonDiagram/data.js +3 -3
  110. package/MetroWidgetDemos/SpatialNav/App.vue +177 -0
  111. package/MetroWidgetDemos/SpatialNav/Buttons.vue +83 -0
  112. package/MetroWidgetDemos/SpatialNav/CustomFocus.vue +57 -0
  113. package/MetroWidgetDemos/{TripleWidget → SpatialNav}/Item.vue +1 -8
  114. package/MetroWidgetDemos/{TripleWidget/WidgetItem.vue → SpatialNav/SimpleFloor.vue} +14 -45
  115. package/MetroWidgetDemos/SpatialNav/StepMw.vue +113 -0
  116. package/MetroWidgetDemos/SpatialNav/TabContent/TabContent.vue +185 -0
  117. package/MetroWidgetDemos/SpatialNav/TripleSection/TripleSection.vue +69 -0
  118. package/MetroWidgetDemos/SpatialNav/TripleSection/WidgetItem.vue +100 -0
  119. package/MetroWidgetDemos/SpatialNav/TvSection/List.vue +75 -0
  120. package/MetroWidgetDemos/SpatialNav/TvSection/TvSection.vue +91 -0
  121. package/MetroWidgetDemos/basic2/App.vue +407 -0
  122. package/MetroWidgetDemos/basic2/Item.vue +68 -0
  123. package/MetroWidgetDemos/direction/App.vue +22 -0
  124. package/MetroWidgetDemos/gazeFocusDiff/App.vue +126 -0
  125. package/MetroWidgetDemos/gazeFocusDiff/Item.vue +87 -0
  126. package/MetroWidgetDemos/minimalUsage/App.vue +66 -0
  127. package/MetroWidgetDemos/minimalUsage/Item.vue +54 -0
  128. package/MetroWidgetDemos/ninePatchFocusPage/App.vue +23 -7
  129. package/MetroWidgetDemos/ninePatchFocusPage/Item.vue +7 -5
  130. package/MetroWidgetDemos/ninePatchFocusPage/focusConstants.js +2 -0
  131. package/MetroWidgetDemos/routeList.js +216 -12
  132. package/MetroWidgetDemos/slideSetting/App.vue +288 -99
  133. package/MetroWidgetDemos/zIndex/App.vue +117 -0
  134. package/MetroWidgetDemos/zIndex/Item.vue +61 -0
  135. package/NinePatchTester/App.vue +24 -31
  136. package/PreDecode/App.vue +140 -0
  137. package/ReactiveTest/App.vue +115 -0
  138. package/ReactiveTest/Item.vue +92 -0
  139. package/ReactiveTest/assets/imageList.js +245 -0
  140. package/ReactiveTest/component/TestSmartDiv.vue +50 -0
  141. package/ReactiveTest/component/TestSmartDivSrcList.vue +74 -0
  142. package/ReactiveTest/component/TestSmartImage.vue +46 -0
  143. package/ReactiveTest/component/TestSmartImageSrcList.vue +90 -0
  144. package/ReactiveTest/component/TestSmartImageStyle.vue +41 -0
  145. package/ReactiveTest/data.js +49 -0
  146. package/ScreenToBlob/App.vue +250 -0
  147. package/ScrollBoxTest/App.vue +52 -28
  148. package/ScrollBoxTest/ClipBar.vue +64 -2
  149. package/ScrollBoxTest/NinePatchBar.vue +64 -2
  150. package/ScrollBoxTest/SizeDivBar.vue +64 -2
  151. package/SecTorTest/App.vue +9 -3
  152. package/SpringFestival/SpringFestivalScene/FreeMoveBuilder.js +3 -3
  153. package/SyncDecode/App.vue +137 -0
  154. package/TextSizeLimit/App.vue +211 -0
  155. package/TextureAnimation/App3.vue +11 -1
  156. package/TouchWidget/App.vue +90 -5
  157. package/TouchWidget/WidgetItem.vue +1 -0
  158. package/TransitPage/App.vue +2 -0
  159. package/assets/logo.png +0 -0
  160. package/package.json +1 -1
  161. package/DemoForOperator/BookFlip/BookFlip/FlipPage.vue +0 -179
  162. package/DemoForOperator/BookFlip/BookFlip/FlippingBook.vue +0 -310
  163. package/DemoForOperator/BookFlip/BookFlip/flip.glsl +0 -135
  164. package/DemoForOperator/Genie/geniePakcer/Genie.vue +0 -741
  165. package/DemoForOperator/LongChatBox/TextManager.ts +0 -147
  166. package/DemoForOperator/LongChatBox/VirtualList.vue +0 -298
  167. package/DemoForOperator/LongChatBox/utile.js +0 -331
  168. package/DivMetroPerformance/App.vue +0 -157
  169. package/DivMetroPerformance/Item.vue +0 -58
  170. package/DivMetroPerformance/assets/bg.jpg +0 -0
  171. package/DivMetroPerformance/assets/coupon_content.png +0 -0
  172. package/DivMetroPerformance/assets/coupon_left.png +0 -0
  173. package/DivMetroPerformance/assets/coupon_mid.png +0 -0
  174. package/DivMetroPerformance/assets/coupon_right.png +0 -0
  175. package/DivMetroPerformance/assets/focus_border.png +0 -0
  176. package/DivMetroPerformance/assets/holder_logo.png +0 -0
  177. package/DivMetroPerformance/assets/jrbm.png +0 -0
  178. package/DivMetroPerformance/assets/line_left.png +0 -0
  179. package/DivMetroPerformance/assets/line_mid.png +0 -0
  180. package/DivMetroPerformance/assets/line_right.png +0 -0
  181. package/DivMetroPerformance/assets/loading.png +0 -0
  182. package/DivMetroPerformance/assets/logo.png +0 -0
  183. package/DivMetroPerformance/assets/mcjx.png +0 -0
  184. package/DivMetroPerformance/assets/tao.png +0 -0
  185. package/DivMetroPerformance/assets/tmall.png +0 -0
  186. package/DivMetroPerformance/border.png +0 -0
  187. package/DivMetroPerformance/components/ContentItem.vue +0 -384
  188. package/DivMetroPerformance/components/MyTab.vue +0 -129
  189. package/DivMetroPerformance/data.js +0 -124
  190. package/DivMetroPerformance/utils/GridItem.vue +0 -28
  191. package/DivMetroPerformance/utils/GridPlate.vue +0 -85
  192. package/MediaDemo/App.vue +0 -127
  193. package/MediaDemo/assets/audio-poster.png +0 -0
  194. package/MediaDemo/components/Button.vue +0 -69
  195. package/MediaDemo/components/Controllor.vue +0 -286
  196. package/MediaDemo/components/StatusBar.vue +0 -100
  197. package/MediaDemo/components/frames/AudioFrame.vue +0 -39
  198. package/MediaDemo/components/frames/AudioPoster.vue +0 -48
  199. package/MediaDemo/components/frames/MediaFrame.vue +0 -153
  200. package/MediaDemo/components/frames/VideoFrame.vue +0 -39
  201. package/MetroWidgetDemos/TripleWidget/App.vue +0 -87
  202. package/MetroWidgetDemos/TripleWidget/SWidgetItem.vue +0 -99
  203. package/Parkour/App.vue +0 -13
  204. package/Parkour/Common/Context.js +0 -21
  205. package/Parkour/Common/MatchmanInfo.js +0 -62
  206. package/Parkour/Common/Random.js +0 -61
  207. package/Parkour/Common/Sound.js +0 -50
  208. package/Parkour/appConfig/HOW_TO_CONFIG.md +0 -20
  209. package/Parkour/appConfig/app.config.mjs +0 -5
  210. package/Parkour/appConfig/app_sign_private_key_sample.crt +0 -28
  211. package/Parkour/appConfig/app_sign_public_key_sample.pem +0 -9
  212. package/Parkour/appConfig/jsview.config.mjs +0 -39
  213. package/Parkour/assets/Bgimages/bg1.png +0 -0
  214. package/Parkour/assets/Bgimages/bg2.png +0 -0
  215. package/Parkour/assets/Bgimages/bg3.png +0 -0
  216. package/Parkour/assets/Bgimages/bg4.png +0 -0
  217. package/Parkour/assets/Bgimages/bg5.png +0 -0
  218. package/Parkour/assets/audio/jump.mp3 +0 -0
  219. package/Parkour/assets/audio/lose.mp3 +0 -0
  220. package/Parkour/assets/role_skin1/fail.json +0 -44
  221. package/Parkour/assets/role_skin1/fail.png +0 -0
  222. package/Parkour/assets/role_skin1/jump_down.json +0 -20
  223. package/Parkour/assets/role_skin1/jump_down.png +0 -0
  224. package/Parkour/assets/role_skin1/jump_up.json +0 -44
  225. package/Parkour/assets/role_skin1/jump_up.png +0 -0
  226. package/Parkour/assets/role_skin1/roll.json +0 -44
  227. package/Parkour/assets/role_skin1/roll.png +0 -0
  228. package/Parkour/assets/role_skin1/run.json +0 -52
  229. package/Parkour/assets/role_skin1/run.png +0 -0
  230. package/Parkour/components/Backdrop.vue +0 -61
  231. package/Parkour/components/GameSence.vue +0 -602
  232. package/Parkour/components/Matchman.vue +0 -85
  233. package/TextureAnimation/utils/FrameCanvasStore.ts +0 -68
  234. package/TextureAnimation/utils/RotateFrame.vue +0 -146
  235. package/TextureAnimation/utils/circleHaloMask.png +0 -0
  236. package/ThrowMoveDemo/AccelerateDemo.vue +0 -85
  237. package/ThrowMoveDemo/App.vue +0 -104
  238. package/ThrowMoveDemo/LRParabolicDemo.vue +0 -101
  239. package/ThrowMoveDemo/TargetDemo.vue +0 -87
  240. package/ThrowMoveDemo/UDParabolicDemo.vue +0 -92
  241. /package/{AnimPicture/assets → assets}/animated_webp.webp +0 -0
  242. /package/{AnimPicture/assets → assets}/ball_3.webp +0 -0
  243. /package/{AnimPicture/assets → assets}/girl_run.gif +0 -0
  244. /package/{AnimPicture/assets → assets}/quan.webp +0 -0
@@ -0,0 +1,250 @@
1
+ <script setup>
2
+ import { shallowRef, ref, onBeforeUnmount } from "vue";
3
+ import { JsvTextureStoreApi, JsvPreload, buildPreloadInfo, BlobApi } from "jsview";
4
+
5
+ // 与 DominantColor 示例保持一致的两张图片
6
+ const Image1 =
7
+ "https://cdn.release.qcast.cn/JsViewFrameworkTester/JsViewVueSampleResources/CustomShader/App/panda.jpeg";
8
+ const Image2 =
9
+ "https://cdn.release.qcast.cn/JsViewFrameworkTester/JsViewVueSampleResources/CustomShader/App/owl.jpeg";
10
+
11
+ // 需要截屏的区域
12
+ const vToCapture = shallowRef(null);
13
+
14
+ // 左侧资源统一收拢到一个非响应式对象中,便于集中管理回收逻辑
15
+ const cLeftResource = {
16
+ // Blob 显示用的 URL
17
+ blobUrl: ref(null),
18
+ // 当前 object URL,用于释放
19
+ currentObjectUrl: null,
20
+ // 全局 BitPalette 句柄,用于在 unmount 时统一回收
21
+ activeBitPalette: null,
22
+ };
23
+
24
+ // 截屏 cancel 句柄
25
+ let captureTextureHandle = null;
26
+
27
+ function handleLoadDone() {
28
+ console.log("图片预加载完成");
29
+ doCaptureAndToBlob();
30
+ }
31
+
32
+ async function doCaptureAndToBlob() {
33
+ try {
34
+ console.log("ScreenToBlob: doCaptureAndToBlob");
35
+
36
+ if (!vToCapture.value) {
37
+ console.warn("ScreenToBlob: vToCapture 为空");
38
+ return;
39
+ }
40
+
41
+ // 截屏生成 texture
42
+ captureTextureHandle = JsvTextureStoreApi.capture2Texture(
43
+ vToCapture.value,
44
+ async (textureName, autoRecycle, w, h) => {
45
+ console.log("ScreenToBlob capture2Texture", textureName, autoRecycle, w, h);
46
+ if (!textureName || textureName.length === 0) {
47
+ console.warn("ScreenToBlob: capture2Texture 返回空 textureName");
48
+ return;
49
+ }
50
+
51
+ const src = `jsvtexturestore://${textureName}`;
52
+ let bitPalette = null;
53
+ try {
54
+ // 若已有未完成的 BitPalette,先回收
55
+ cLeftResource.activeBitPalette?.recycle();
56
+
57
+ // 使用 getBitPalette 获取 BitPalette,并保存为全局句柄
58
+ bitPalette = JsvTextureStoreApi.getBitPalette(src);
59
+ cLeftResource.activeBitPalette = bitPalette;
60
+
61
+ await bitPalette.Ready;
62
+
63
+ // 通过 BitPaletteCtrl.toBlob 获得 Blob
64
+ const blob = await bitPalette.Ctrl?.toBlob();
65
+ if (!blob) {
66
+ console.warn("ScreenToBlob: toBlob 返回空 Blob");
67
+ return;
68
+ }
69
+
70
+ // 释放旧的 object URL
71
+ if (cLeftResource.currentObjectUrl) {
72
+ BlobApi.revokeObjectURL(cLeftResource.currentObjectUrl);
73
+ cLeftResource.currentObjectUrl = null;
74
+ }
75
+
76
+ // 创建新的 object URL,并用于展示
77
+ cLeftResource.currentObjectUrl = await BlobApi.createObjectURL(blob);
78
+ cLeftResource.blobUrl.value = cLeftResource.currentObjectUrl;
79
+ } catch (error) {
80
+ console.error("ScreenToBlob: BitPalette 处理失败", error);
81
+ } finally {
82
+ // 释放 BitPalette 资源,并清理全局句柄
83
+ if (cLeftResource.activeBitPalette === bitPalette) {
84
+ bitPalette?.recycle();
85
+ cLeftResource.activeBitPalette = null;
86
+ }
87
+ // 手动删除截图纹理,防止泄漏
88
+ JsvTextureStoreApi.deleteTexture(textureName);
89
+ }
90
+ },
91
+ false // 手动deleteTexture进行回收而非自动回收, JsvTextureStoreApi.getBitPalette 的需求
92
+ );
93
+ } catch (error) {
94
+ console.error("ScreenToBlob: capture2Texture 调用失败", error);
95
+ }
96
+ }
97
+
98
+ // 处理右边区域的Blob展示, 右边区域使用图片src直接展示
99
+ const cRightResource = {
100
+ // Blob 显示用的 URL
101
+ blobUrl: ref(null),
102
+ // 当前 object URL,用于释放
103
+ currentObjectUrl: null,
104
+ // 全局 BitPalette 句柄,用于在 unmount 时统一回收
105
+ activeBitPalette: null,
106
+ };
107
+ async function handleRightBlob(src) {
108
+ // 使用 getBitPalette 获取 BitPalette,并保存为全局句柄
109
+ const bitPalette = JsvTextureStoreApi.getBitPalette(src);
110
+ cRightResource.activeBitPalette = bitPalette;
111
+
112
+ await bitPalette.Ready;
113
+
114
+ // 通过 BitPaletteCtrl.toBlob 获得 Blob
115
+ const blob = await bitPalette.Ctrl?.toBlob();
116
+ if (!blob) {
117
+ console.warn("ScreenToBlob: toBlob 返回空 Blob");
118
+ return;
119
+ }
120
+
121
+ // 释放旧的 object URL
122
+ if (cRightResource.currentObjectUrl) {
123
+ BlobApi.revokeObjectURL(cRightResource.currentObjectUrl);
124
+ cRightResource.currentObjectUrl = null;
125
+ }
126
+
127
+ // 创建新的 object URL,并用于展示
128
+ cRightResource.currentObjectUrl = await BlobApi.createObjectURL(blob);
129
+ cRightResource.blobUrl.value = cRightResource.currentObjectUrl;
130
+ }
131
+ handleRightBlob(Image2);
132
+
133
+ onBeforeUnmount(() => {
134
+
135
+ // ------- 先处理左边资源的回收 -------
136
+
137
+ // 取消截屏, 回收resource
138
+ captureTextureHandle?.recycle();
139
+
140
+ // 回收仍在进行中的 BitPalette - 左侧
141
+ cLeftResource.activeBitPalette?.recycle();
142
+ cLeftResource.activeBitPalette = null;
143
+
144
+ // 释放 object URL - 左侧
145
+ if (cLeftResource.currentObjectUrl) {
146
+ BlobApi.revokeObjectURL(cLeftResource.currentObjectUrl);
147
+ cLeftResource.currentObjectUrl = null;
148
+ console.log("ScreenToBlob: 已释放 object URL (左侧)");
149
+ }
150
+
151
+ // ------- 再处理右边资源的回收 -------
152
+ // 回收仍在进行中的 BitPalette - 右侧
153
+ cRightResource.activeBitPalette?.recycle();
154
+ cRightResource.activeBitPalette = null;
155
+
156
+ // 释放 object URL - 右侧
157
+ if (cRightResource.currentObjectUrl) {
158
+ BlobApi.revokeObjectURL(cRightResource.currentObjectUrl);
159
+ cRightResource.currentObjectUrl = null;
160
+ console.log("ScreenToBlob: 已释放 object URL (右侧)");
161
+ }
162
+ });
163
+ </script>
164
+
165
+ <template>
166
+ <!-- 背景,与 DominantColor 保持一致 -->
167
+ <div
168
+ :style="{
169
+ left: 0,
170
+ top: 0,
171
+ width: 1280,
172
+ height: 720,
173
+ backgroundColor: '#FFFFFF',
174
+ }"
175
+ ></div>
176
+
177
+ <div
178
+ :style="{
179
+ textAlign: 'center',
180
+ fontSize: 30,
181
+ lineHeight: 50,
182
+ color: '#ffffff',
183
+ left: 140,
184
+ top: 20,
185
+ width: 1000,
186
+ height: 50,
187
+ backgroundColor: 'rgba(27,38,151,0.8)',
188
+ }"
189
+ >
190
+ 下方为blob显示,1为截图blob, 2为给定url的blob
191
+ </div>
192
+
193
+ <!-- 截屏区域, 等图片加载完成后进行截屏动作 -->
194
+ <div
195
+ ref="vToCapture"
196
+ :style="{
197
+ left: 0,
198
+ top: 80,
199
+ width: 640,
200
+ height: 360,
201
+ }"
202
+ >
203
+ <img
204
+ :style="{
205
+ width: 640,
206
+ height: 360,
207
+ }"
208
+ :onLoad="handleLoadDone"
209
+ :src="Image1"
210
+ />
211
+ <div
212
+ :style="{
213
+ width: 300,
214
+ height: 300,
215
+ backgroundColor: '#007788',
216
+ }"
217
+ ></div>
218
+ </div>
219
+
220
+
221
+ <!-- Blob 结果展示区域,仿照 BlobLoadTest,在绘制内容下方展示 -->
222
+ <div
223
+ v-if="cLeftResource.blobUrl.value"
224
+ :style="{
225
+ top: 450,
226
+ left: 0,
227
+ }"
228
+ >
229
+ <img
230
+ :src="cLeftResource.blobUrl.value"
231
+ :style="{
232
+ width: 640,
233
+ height: 250,
234
+ objectFit: 'contain',
235
+ }"
236
+ />
237
+ </div>
238
+
239
+ <!-- 右侧图片展示 -->
240
+ <div
241
+ :style="{
242
+ left: 640,
243
+ top: 450,
244
+ width: 320,
245
+ height: 180,
246
+ backgroundImage: `url(${cRightResource.blobUrl.value})`,
247
+ }"
248
+ />
249
+ </template>
250
+
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <jsv-focus-block autoFocus :onKeyDown="procKeyDown">
2
+ <jsv-focus-block autoFocus :onAction="onAction">
3
3
  <div class="bgSty">
4
4
  <!-- 提示 -->
5
5
  <div class="text" :style="{ left: 210, top: 20 }">
@@ -19,9 +19,9 @@
19
19
  <div class="bg2" />
20
20
  <div class="bg3" />
21
21
  <!-- 进度条 -->
22
- <SizeDivBar :top="80" :left="0" />
23
- <ClipBar :top="210" :left="0" />
24
- <NinePatchBar :top="340" :left="0" />
22
+ <SizeDivBar ref="sizeDivBarRef" :top="80" :left="0" />
23
+ <ClipBar ref="clipBarRef" :top="210" :left="0" />
24
+ <NinePatchBar ref="ninePatchBarRef" :top="340" :left="0" />
25
25
  <!-- 图1说明 -->
26
26
  <div :style="{ left: 0, top: 26 }" class="text">
27
27
  {{ "pin模式下拖拽(拖动点尺寸略大于进度条)" }}
@@ -32,35 +32,59 @@
32
32
  </template>
33
33
 
34
34
  <script setup>
35
- import { shallowRef, onMounted } from "vue";
35
+ import { ref, onMounted } from "vue";
36
36
  import NoBackgroundBar from "./NoBackgroundBar.vue";
37
37
  import ClipBar from "./ClipBar.vue";
38
38
  import NinePatchBar from "./NinePatchBar.vue";
39
39
  import SizeDivBar from "./SizeDivBar.vue";
40
40
 
41
- // //进度百分比
42
- // let myProgress = shallowRef(20);
43
- // //按键事件 控制进度条的width
44
- const procKeyDown = (ev) => {
45
- // switch (ev.keyCode) {
46
- // case 37:
47
- // myProgress.value -= 5;
48
- // if (myProgress.value <= 0) {
49
- // myProgress.value = 0;
50
- // }
51
- // break;
52
- // case 39:
53
- // myProgress.value += 5;
54
- // if (myProgress.value >= 100) {
55
- // myProgress.value = 100;
56
- // }
57
- // break;
58
- // case 13:
59
- // myProgress.value = 0;
60
- // break;
61
- // default:
62
- // break;
63
- // }
41
+ const sizeDivBarRef = ref(null);
42
+ const clipBarRef = ref(null);
43
+ const ninePatchBarRef = ref(null);
44
+
45
+ /**
46
+ * slideToPercentByKey / beginKeyOperation / endKeyOperation 用法说明
47
+ * (与 LongTextScroll 中 underKeyOperation 的语义一致)
48
+ *
49
+ * ┌─ onKeyDown(每次物理键按下,含长按连发)────────────────────────────┐
50
+ * │ 1. barRef.beginKeyOperation() // 进入按键驱动,屏蔽滞后 Sensor │
51
+ * │ 2. percent = clamp(bar.getCurrentPercent() ± step) │
52
+ * │ 3. barRef.slideToPercentByKey(percent) // 勿直接 updatePercent │
53
+ * │ 已到边界、本次不移动时也应 begin(与 LongTextScroll 一致) │
54
+ * └───────────────────────────────────────────────────────────────────────┘
55
+ *
56
+ * ┌─ onKeyUp(物理键抬起,一次按住只对应一次)──────────────────────────┐
57
+ * │ barRef.endKeyOperation() // 结束按键驱动,恢复 Sensor 同步 │
58
+ * │ 勿在 onKeyDown 末尾调用 end;勿在每次 slide 后调用 end │
59
+ * └───────────────────────────────────────────────────────────────────────┘
60
+ *
61
+ * 不需要 begin/end:触控拖拽、组件内 initPercent / onMounted 初始化。
62
+ *
63
+ * 取消下方注释即可启用左右键演示(需同时给 ref 的 bar 调用):
64
+ */
65
+ const onAction = {
66
+ // 再次只以控制SizeDivBar为例, 其他bar的按键驱动用法同理
67
+ onKeyDown: (ev) => {
68
+ const bar = sizeDivBarRef.value;
69
+ const step = 0.05;
70
+ switch (ev.keyCode) {
71
+ case 37: // Left
72
+ bar?.beginKeyOperation();
73
+ bar?.slideToPercentByKey(
74
+ Math.max(0, (bar.getCurrentPercent?.() ?? 0) - step)
75
+ );
76
+ break;
77
+ case 39: // Right
78
+ bar?.beginKeyOperation();
79
+ bar?.slideToPercentByKey(
80
+ Math.min(1, (bar.getCurrentPercent?.() ?? 0) + step)
81
+ );
82
+ break;
83
+ }
84
+ },
85
+ onKeyUp: () => {
86
+ sizeDivBarRef.value?.endKeyOperation();
87
+ },
64
88
  };
65
89
 
66
90
  onMounted(() => {});
@@ -125,10 +125,44 @@ let fncOnClick = () => {
125
125
  let rJsvScrollBox = shallowRef(null);
126
126
  let rPressDetectDiv = shallowRef(null);
127
127
  let rPercentDisp = shallowRef(0);
128
+ let currentPercent = 0;
129
+ let underKeyOperation = false; // 按键操作时, 忽略掉从Sensor反馈回来的位置同步信息
130
+
131
+ function recordPercent(percent) {
132
+ currentPercent = Math.floor(percent * 100) / 100;
133
+ }
134
+
135
+ /** @returns {number} 当前进度 0~1 */
136
+ function getCurrentPercent() {
137
+ return currentPercent;
138
+ }
139
+
140
+ /**
141
+ * 按键驱动进度:调用 updatePercent 并同步内部 currentPercent / 显示文案。
142
+ * @param {number} percent 0~1
143
+ * 须在 beginKeyOperation 与 endKeyOperation 之间由父组件 onKeyDown 调用;初始化请用 initPercent。
144
+ */
145
+ function slideToPercentByKey(percent) {
146
+ const clamped = Math.max(0, Math.min(1, percent));
147
+ rJsvScrollBox.value.updatePercent(clamped);
148
+ recordPercent(clamped);
149
+ rPercentDisp.value = currentPercent;
150
+ }
151
+
152
+ function initPercent(percent) {
153
+ slideToPercentByKey(percent);
154
+ }
128
155
 
129
156
  onMounted(() => {
130
157
  rJsvScrollBox.value.setSensor((percent, x, y) => {
131
- rPercentDisp.value = Math.floor(percent * 100) / 100;
158
+ if (!underKeyOperation) {
159
+ // 按键操作时, 忽略掉从Sensor反馈回来的位置同步信息
160
+ // 以规避, 当按键操作的设置动作频率快于渲染端响应调整值并通过Sensor反馈的频率时
161
+ // 例如当两次由按键发起的更新位置处理都执行后, 第一次的位置调整才被Sensor反馈, 导致第三次动作的位置基础会被回设为第一次的位置的问题
162
+ // 从而会引发进度条来回抖动
163
+ recordPercent(percent);
164
+ rPercentDisp.value = currentPercent;
165
+ }
132
166
  console.log(
133
167
  `onProgress dragged percent=${percent} \
134
168
  x=${Math.floor(x)} \
@@ -137,7 +171,7 @@ y=${Math.floor(y)}`
137
171
  }, 15);
138
172
 
139
173
  // 通过代码设计进度条位置, 同理按键操作下来的进度条调整也可以这么处理
140
- rJsvScrollBox.value.updatePercent(0.7);
174
+ initPercent(0.7);
141
175
 
142
176
  // 注册按下抬起的监听
143
177
  rPressDetectDiv.value.jsvSetTapListener({
@@ -149,6 +183,34 @@ y=${Math.floor(y)}`
149
183
  },
150
184
  });
151
185
  });
186
+
187
+ /**
188
+ * 父组件通过 ref 调用(见 ScrollBoxTest/App.vue 示例)。
189
+ *
190
+ * beginKeyOperation — 何时调用:
191
+ * onKeyDown 里,只要本次按键会驱动进度(左/右等),在调用 slideToPercentByKey 之前或之后调用一次。
192
+ * 标记进入「按键驱动」阶段,屏蔽滞后的 Sensor 回写,避免连按/快按时进度条抖动。
193
+ * 已到边界、本次 slide 不会改变进度时也应调用
194
+ *
195
+ * endKeyOperation — 何时调用:
196
+ * onKeyUp 里、物理键抬起时调用一次,与 begin 成对,表示本次按键会话结束。
197
+ * 不要在每次 onKeyDown 末尾调用;长按连发时多次 onKeyDown 只对应一次 onKeyUp,只 end 一次。
198
+ * 结束后恢复 Sensor 同步,拖拽/惯性滑动可再次更新 currentPercent。
199
+ *
200
+ * 勿对触控拖拽调用 begin/end;组件内 initPercent、onMounted 初始化也不需要。
201
+ *
202
+ * getCurrentPercent — 返回当前进度 0~1(按键、拖拽、初始化后均由 recordPercent 维护)。
203
+ */
204
+ defineExpose({
205
+ getCurrentPercent,
206
+ slideToPercentByKey,
207
+ beginKeyOperation: () => {
208
+ underKeyOperation = true;
209
+ },
210
+ endKeyOperation: () => {
211
+ underKeyOperation = false;
212
+ },
213
+ });
152
214
  </script>
153
215
 
154
216
  <style scoped></style>
@@ -145,10 +145,44 @@ let rJsvScrollBox = shallowRef(null);
145
145
  let rPressDetectDiv = shallowRef(null);
146
146
  let rPercentDisp = shallowRef(0);
147
147
  let rJsvScrollFlowA = shallowRef(null);
148
+ let currentPercent = 0;
149
+ let underKeyOperation = false; // 按键操作时, 忽略掉从Sensor反馈回来的位置同步信息
150
+
151
+ function recordPercent(percent) {
152
+ currentPercent = Math.floor(percent * 100) / 100;
153
+ }
154
+
155
+ /** @returns {number} 当前进度 0~1 */
156
+ function getCurrentPercent() {
157
+ return currentPercent;
158
+ }
159
+
160
+ /**
161
+ * 按键驱动进度:调用 updatePercent 并同步内部 currentPercent / 显示文案。
162
+ * @param {number} percent 0~1
163
+ * 须在 beginKeyOperation 与 endKeyOperation 之间由父组件 onKeyDown 调用;初始化请用 initPercent。
164
+ */
165
+ function slideToPercentByKey(percent) {
166
+ const clamped = Math.max(0, Math.min(1, percent));
167
+ rJsvScrollBox.value.updatePercent(clamped);
168
+ recordPercent(clamped);
169
+ rPercentDisp.value = currentPercent;
170
+ }
171
+
172
+ function initPercent(percent) {
173
+ slideToPercentByKey(percent);
174
+ }
148
175
 
149
176
  onMounted(() => {
150
177
  rJsvScrollBox.value.setSensor((percent, x, y) => {
151
- rPercentDisp.value = Math.floor(percent * 100) / 100;
178
+ if (!underKeyOperation) {
179
+ // 按键操作时, 忽略掉从Sensor反馈回来的位置同步信息
180
+ // 以规避, 当按键操作的设置动作频率快于渲染端响应调整值并通过Sensor反馈的频率时
181
+ // 例如当两次由按键发起的更新位置处理都执行后, 第一次的位置调整才被Sensor反馈, 导致第三次动作的位置基础会被回设为第一次的位置的问题
182
+ // 从而会引发进度条来回抖动
183
+ recordPercent(percent);
184
+ rPercentDisp.value = currentPercent;
185
+ }
152
186
  console.log(
153
187
  `onProgress dragged percent=${percent} \
154
188
  x=${Math.floor(x)} \
@@ -157,7 +191,7 @@ y=${Math.floor(y)}`
157
191
  }, 15);
158
192
 
159
193
  // 通过代码设计进度条位置, 同理按键操作下来的进度条调整也可以这么处理
160
- rJsvScrollBox.value.updatePercent(0.5);
194
+ initPercent(0.5);
161
195
 
162
196
  // 注册按下抬起的监听
163
197
  rPressDetectDiv.value.jsvSetTapListener({
@@ -178,6 +212,34 @@ y=${Math.floor(y)}`
178
212
  }, 15);
179
213
  });
180
214
 
215
+ /**
216
+ * 父组件通过 ref 调用(见 ScrollBoxTest/App.vue 示例)。
217
+ *
218
+ * beginKeyOperation — 何时调用:
219
+ * onKeyDown 里,只要本次按键会驱动进度(左/右等),在调用 slideToPercentByKey 之前或之后调用一次。
220
+ * 标记进入「按键驱动」阶段,屏蔽滞后的 Sensor 回写,避免连按/快按时进度条抖动。
221
+ * 已到边界、本次 slide 不会改变进度时也应调用
222
+ *
223
+ * endKeyOperation — 何时调用:
224
+ * onKeyUp 里、物理键抬起时调用一次,与 begin 成对,表示本次按键会话结束。
225
+ * 不要在每次 onKeyDown 末尾调用;长按连发时多次 onKeyDown 只对应一次 onKeyUp,只 end 一次。
226
+ * 结束后恢复 Sensor 同步,拖拽/惯性滑动可再次更新 currentPercent。
227
+ *
228
+ * 勿对触控拖拽调用 begin/end;组件内 initPercent、onMounted 初始化也不需要。
229
+ *
230
+ * getCurrentPercent — 返回当前进度 0~1(按键、拖拽、初始化后均由 recordPercent 维护)。
231
+ */
232
+ defineExpose({
233
+ getCurrentPercent,
234
+ slideToPercentByKey,
235
+ beginKeyOperation: () => {
236
+ underKeyOperation = true;
237
+ },
238
+ endKeyOperation: () => {
239
+ underKeyOperation = false;
240
+ },
241
+ });
242
+
181
243
  onUnmounted(() => {
182
244
  // 销毁记录在全局的texture
183
245
  cLeftBarTexture?.doRecycle();
@@ -110,10 +110,44 @@ let fncOnClick = () => {
110
110
  let rJsvScrollBox = shallowRef(null);
111
111
  let rPressDetectDiv = shallowRef(null);
112
112
  let rPercentDisp = shallowRef(0);
113
+ let currentPercent = 0;
114
+ let underKeyOperation = false; // 按键操作时, 忽略掉从Sensor反馈回来的位置同步信息
115
+
116
+ function recordPercent(percent) {
117
+ currentPercent = Math.floor(percent * 100) / 100;
118
+ }
119
+
120
+ /** @returns {number} 当前进度 0~1 */
121
+ function getCurrentPercent() {
122
+ return currentPercent;
123
+ }
124
+
125
+ /**
126
+ * 按键驱动进度:调用 updatePercent 并同步内部 currentPercent / 显示文案。
127
+ * @param {number} percent 0~1
128
+ * 须在 beginKeyOperation 与 endKeyOperation 之间由父组件 onKeyDown 调用;初始化请用 initPercent。
129
+ */
130
+ function slideToPercentByKey(percent) {
131
+ const clamped = Math.max(0, Math.min(1, percent));
132
+ rJsvScrollBox.value.updatePercent(clamped);
133
+ recordPercent(clamped);
134
+ rPercentDisp.value = currentPercent;
135
+ }
136
+
137
+ function initPercent(percent) {
138
+ slideToPercentByKey(percent);
139
+ }
113
140
 
114
141
  onMounted(() => {
115
142
  rJsvScrollBox.value.setSensor((percent, x, y) => {
116
- rPercentDisp.value = Math.floor(percent * 100) / 100;
143
+ if (!underKeyOperation) {
144
+ // 按键操作时, 忽略掉从Sensor反馈回来的位置同步信息
145
+ // 以规避, 当按键操作的设置动作频率快于渲染端响应调整值并通过Sensor反馈的频率时
146
+ // 例如当两次由按键发起的更新位置处理都执行后, 第一次的位置调整才被Sensor反馈, 导致第三次动作的位置基础会被回设为第一次的位置的问题
147
+ // 从而会引发进度条来回抖动
148
+ recordPercent(percent);
149
+ rPercentDisp.value = currentPercent;
150
+ }
117
151
  console.log(
118
152
  `onProgress dragged percent=${percent} \
119
153
  x=${Math.floor(x)} \
@@ -122,7 +156,7 @@ y=${Math.floor(y)}`
122
156
  }, 15);
123
157
 
124
158
  // 通过代码设计进度条位置, 同理按键操作下来的进度条调整也可以这么处理
125
- rJsvScrollBox.value.updatePercent(0.2);
159
+ initPercent(0.2);
126
160
 
127
161
  // 注册按下抬起的监听
128
162
  rPressDetectDiv.value.jsvSetTapListener({
@@ -134,6 +168,34 @@ y=${Math.floor(y)}`
134
168
  },
135
169
  });
136
170
  });
171
+
172
+ /**
173
+ * 父组件通过 ref 调用(见 ScrollBoxTest/App.vue 示例)。
174
+ *
175
+ * beginKeyOperation — 何时调用:
176
+ * onKeyDown 里,只要本次按键会驱动进度(左/右等),在调用 slideToPercentByKey 之前或之后调用一次。
177
+ * 标记进入「按键驱动」阶段,屏蔽滞后的 Sensor 回写,避免连按/快按时进度条抖动。
178
+ * 已到边界、本次 slide 不会改变进度时也应调用
179
+ *
180
+ * endKeyOperation — 何时调用:
181
+ * onKeyUp 里、物理键抬起时调用一次,与 begin 成对,表示本次按键会话结束。
182
+ * 不要在每次 onKeyDown 末尾调用;长按连发时多次 onKeyDown 只对应一次 onKeyUp,只 end 一次。
183
+ * 结束后恢复 Sensor 同步,拖拽/惯性滑动可再次更新 currentPercent。
184
+ *
185
+ * 勿对触控拖拽调用 begin/end;组件内 initPercent、onMounted 初始化也不需要。
186
+ *
187
+ * getCurrentPercent — 返回当前进度 0~1(按键、拖拽、初始化后均由 recordPercent 维护)。
188
+ */
189
+ defineExpose({
190
+ getCurrentPercent,
191
+ slideToPercentByKey,
192
+ beginKeyOperation: () => {
193
+ underKeyOperation = true;
194
+ },
195
+ endKeyOperation: () => {
196
+ underKeyOperation = false;
197
+ },
198
+ });
137
199
  </script>
138
200
 
139
201
  <style scoped></style>
@@ -4,13 +4,14 @@
4
4
  <JsvPieChart
5
5
  :centerPosition="center"
6
6
  :radius="360"
7
+ :subRadius="300"
7
8
  :data="data"
8
- :animationTime="0.5"
9
+ :animationTime="0.8"
9
10
  ></JsvPieChart>
10
11
  <!-- 文字说明 -->
11
12
  <div class="text">
12
13
  {{
13
- "图为圆心在(400,400)位置,半径为360的饼图。此样例限制最多六个扇形。"
14
+ "图为圆心在(400,400)位置,半径为360-300的环形图(300为0时则为扇形饼图)。此样例限制最多六个扇形。"
14
15
  }}
15
16
  </div>
16
17
  <!-- 操作说明 -->
@@ -34,22 +35,27 @@ const center = {
34
35
  let data = shallowRef([
35
36
  {
36
37
  percent: 23.33,
38
+ // color: "#0000FF7F",
37
39
  color: "#0000FF",
38
40
  },
39
41
  {
40
42
  percent: 24.67,
43
+ // color: "#FFFF007F",
41
44
  color: "#FFFF00",
42
45
  },
43
46
  {
44
47
  percent: 15,
48
+ // color: "#FF12FF7F",
45
49
  color: "#FF12FF",
46
50
  },
47
51
  {
48
52
  percent: 13,
53
+ // color: "#FF12137F",
49
54
  color: "#FF1213",
50
55
  },
51
56
  {
52
57
  percent: 24,
58
+ // color: "#6EFFE17F",
53
59
  color: "#6EFFE1",
54
60
  },
55
61
  ]);
@@ -209,7 +215,7 @@ let actionDefines = {
209
215
  }
210
216
  .text {
211
217
  width: 500;
212
- height: 60;
218
+ height: 90;
213
219
  left: 700;
214
220
  top: 300;
215
221
  background-color: rgba(255, 255, 255, 0.5);