@shijiu/jsview-vue 2.1.200 → 2.1.340-test.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 (120) hide show
  1. package/bin/browser/BrowserApic.vue.mjs +124 -0
  2. package/bin/browser/BrowserApic2.vue.mjs +118 -0
  3. package/bin/browser/BrowserApicLib.mjs +424 -0
  4. package/bin/browser/BrowserAudio.vue.mjs +263 -0
  5. package/bin/browser/BrowserJsvLatex.vue.mjs +110 -0
  6. package/bin/browser/BrowserJsvPlayer.vue.mjs +573 -0
  7. package/bin/browser/BrowserPreload.vue.mjs +154 -0
  8. package/bin/browser/BrowserQrcode.vue.mjs +178 -0
  9. package/bin/browser/BrowserSpray.vue.mjs +66 -0
  10. package/bin/browser/BrowserTextureAnim.vue.mjs +324 -0
  11. package/bin/export-sfc.mjs +12 -0
  12. package/bin/jsview-common.mjs +39 -0
  13. package/bin/jsview-vue.mjs +21106 -0
  14. package/index.js +3 -4
  15. package/package.json +1 -2
  16. package/tools/config/rollup.config.mjs +52 -0
  17. package/tools/config/tsconfig.json +18 -0
  18. package/tools/config/vite.config.ts +60 -0
  19. package/tools/jsview-vue-build.mjs +125 -0
  20. package/utils/JsViewEngineWidget/{JsvFocusBlock.vue → JsvFocus/JsvFocusBlock.vue} +11 -11
  21. package/utils/JsViewEngineWidget/{JsvFocusHub.ts → JsvFocus/JsvFocusHub.ts} +9 -3
  22. package/utils/JsViewEngineWidget/{JsvFocusManager.js → JsvFocus/JsvFocusManager.js} +6 -5
  23. package/utils/JsViewEngineWidget/MetroWidget/AnimationManager.ts +33 -10
  24. package/utils/JsViewEngineWidget/MetroWidget/ListWidget.vue +89 -57
  25. package/utils/JsViewEngineWidget/MetroWidget/MetroWidget.vue +118 -62
  26. package/utils/JsViewEngineWidget/MetroWidget/MetroWidgetSetup.js +504 -60
  27. package/utils/JsViewEngineWidget/MetroWidget/RenderItem.ts +11 -1
  28. package/utils/JsViewEngineWidget/MetroWidget/SlotComponent.vue +13 -0
  29. package/utils/JsViewEngineWidget/TemplateParser/CommonMetroTemplate.ts +1 -1
  30. package/utils/JsViewEngineWidget/TemplateParser/ListMetroTemplate.ts +1 -1
  31. package/utils/JsViewEngineWidget/TemplateParser/MetroTemplate.ts +34 -1
  32. package/utils/JsViewEngineWidget/TemplateParser/TemplateItemAdder.ts +52 -11
  33. package/utils/JsViewEngineWidget/index.js +3 -3
  34. package/utils/JsViewPlugin/JsvAudio/AudioProxy.js +9 -0
  35. package/utils/JsViewPlugin/JsvAudio/BrowserAudio/BrowserAudio.vue +11 -3
  36. package/utils/JsViewPlugin/JsvAudio/JsvAudio.vue +1 -0
  37. package/utils/JsViewPlugin/JsvAudio/JsvAudioBridgeProxy.js +8 -0
  38. package/utils/JsViewPlugin/JsvAudio/ScreenLockManager.js +16 -0
  39. package/utils/JsViewPlugin/JsvAudio/version.js +3 -3
  40. package/utils/JsViewPlugin/JsvAudio/version.mjs +3 -3
  41. package/utils/JsViewPlugin/JsvLatex/index.js +1 -1
  42. package/utils/JsViewPlugin/JsvPlayer/JsvPlayer.vue +1 -1
  43. package/utils/JsViewPlugin/JsvPlayer/index-0.9.js +3 -3
  44. package/utils/JsViewPlugin/JsvPlayer/index.js +2 -2
  45. package/utils/JsViewVueTools/DebugTool.js +2 -2
  46. package/utils/JsViewVueTools/DefaultKeyMap.js +1 -1
  47. package/utils/JsViewVueTools/JsvDynamicCssStyle.js +1 -1
  48. package/utils/JsViewVueTools/JsvDynamicKeyFrames.js +2 -2
  49. package/utils/JsViewVueTools/JsvImpactTracer.js +7 -7
  50. package/utils/JsViewVueTools/JsvPreDownloader.ts +1 -1
  51. package/utils/JsViewVueTools/JsvRefTaker.js +2 -1
  52. package/utils/JsViewVueTools/JsvRuntimeBridge.js +29 -29
  53. package/utils/JsViewVueTools/JsvStyleClass.js +3 -3
  54. package/utils/JsViewVueTools/JsvStyleSheetsDeclarer.js +1 -1
  55. package/utils/JsViewVueTools/JsvTextTools.js +4 -4
  56. package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/CanvasTexture.ts +29 -1
  57. package/utils/JsViewVueTools/JsvTextureStore/CanvasTexture/CommandList.ts +6 -5
  58. package/utils/JsViewVueTools/JsvTextureStore/JsvTextureStore.ts +60 -2
  59. package/utils/JsViewVueTools/NinePatchHelper.js +1 -1
  60. package/utils/JsViewVueWidget/JsvActorMove/ActorControlBase.js +1 -1
  61. package/utils/JsViewVueWidget/JsvActorMove/JsvActorMoveControl.js +1 -1
  62. package/utils/JsViewVueWidget/JsvApic/{BrowserApic → JsvApic}/BrowserApic.vue +20 -23
  63. package/utils/JsViewVueWidget/JsvApic/{JsvApic.vue → JsvApic/JsvApic.vue} +3 -14
  64. package/utils/JsViewVueWidget/JsvApic/{index.js → JsvApic/index.js} +2 -4
  65. package/utils/JsViewVueWidget/JsvApic/JsvApic2/BrowserApic2.vue +116 -0
  66. package/utils/JsViewVueWidget/JsvApic/JsvApic2/JsvApic2.vue +137 -0
  67. package/utils/JsViewVueWidget/JsvApic/JsvApic2/index.js +17 -0
  68. package/utils/JsViewVueWidget/JsvApic/JsvBrowserApicLib/BrowserApicLib.js +4 -0
  69. package/utils/JsViewVueWidget/JsvApic/{BrowserApic → JsvBrowserApicLib}/NormalLoopTool.js +16 -18
  70. package/utils/JsViewVueWidget/JsvApic/JsvBrowserApicLib/PartLoopTool.js +90 -0
  71. package/utils/JsViewVueWidget/JsvApic/JsvBrowserApicLib/SingleLoopTool.js +17 -0
  72. package/utils/JsViewVueWidget/JsvApic/JsvBrowserApicLib/Viewer.js +111 -0
  73. package/utils/JsViewVueWidget/JsvApic/JsvCommonLoopToolBase.js +48 -0
  74. package/utils/JsViewVueWidget/JsvConnectLine/ArcLineManager.js +71 -0
  75. package/utils/JsViewVueWidget/JsvConnectLine/JsvConnectLine.vue +354 -0
  76. package/utils/JsViewVueWidget/JsvConnectLine/index.js +2 -0
  77. package/utils/JsViewVueWidget/JsvFreeMoveActor/ActorControl.ts +37 -18
  78. package/utils/JsViewVueWidget/JsvFreeMoveActor/ForgeTypeDefine.ts +7 -3
  79. package/utils/JsViewVueWidget/JsvFreeMoveActor/FreeMoveActor.vue +28 -2
  80. package/utils/JsViewVueWidget/JsvFreeMoveActor/JsvEnvBlocker.vue +12 -5
  81. package/utils/JsViewVueWidget/JsvFreeMoveActor/NexusNode.ts +21 -0
  82. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetAction.ts +47 -59
  83. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetCondition.ts +129 -12
  84. package/utils/JsViewVueWidget/JsvFreeMoveActor/SetState.ts +45 -0
  85. package/utils/JsViewVueWidget/JsvFreeMoveActor/index.js +10 -2
  86. package/utils/JsViewVueWidget/JsvGrid.vue +1 -1
  87. package/utils/JsViewVueWidget/JsvHole.js +1 -1
  88. package/utils/JsViewVueWidget/JsvInput/JsvInput.vue +1 -1
  89. package/utils/JsViewVueWidget/JsvLine/JsvLine.vue +2 -2
  90. package/utils/JsViewVueWidget/JsvLine/LineManager.js +6 -4
  91. package/utils/JsViewVueWidget/JsvMarquee.vue +7 -4
  92. package/utils/JsViewVueWidget/JsvPieChart.vue +1 -1
  93. package/utils/JsViewVueWidget/JsvPreload/JsvPreload.vue +1 -1
  94. package/utils/JsViewVueWidget/JsvPreload/index.js +1 -1
  95. package/utils/JsViewVueWidget/JsvProgressBar.vue +172 -0
  96. package/utils/JsViewVueWidget/JsvQrcode/JsvQrcode.vue +0 -1
  97. package/utils/JsViewVueWidget/JsvQrcode/index.js +1 -1
  98. package/utils/JsViewVueWidget/JsvRadarChart.vue +1 -1
  99. package/utils/JsViewVueWidget/JsvScaleTextBox.vue +0 -2
  100. package/utils/JsViewVueWidget/JsvSector.vue +1 -1
  101. package/utils/JsViewVueWidget/JsvSoundPool.js +1 -1
  102. package/utils/JsViewVueWidget/JsvSpray/index.js +1 -1
  103. package/utils/JsViewVueWidget/JsvSpriteAnim/FrameBuidler.ts +235 -0
  104. package/utils/JsViewVueWidget/JsvSpriteAnim/JsvSpriteAnim.vue +433 -401
  105. package/utils/JsViewVueWidget/JsvSpriteAnim/JsvSpriteLoader.vue +120 -0
  106. package/utils/JsViewVueWidget/JsvSpriteAnim/index.js +2 -2
  107. package/utils/JsViewVueWidget/JsvSwiper/JsvSwiper.vue +5 -5
  108. package/utils/JsViewVueWidget/JsvSwiper3D/JsvSwiper.vue +425 -422
  109. package/utils/JsViewVueWidget/JsvVisibleSensor/index.js +1 -1
  110. package/utils/JsViewVueWidget/index.js +7 -3
  111. package/utils/index.js +4 -0
  112. package/utils/JsViewVueWidget/JsvApic/BrowserApic/LoopToolBase.js +0 -25
  113. package/utils/JsViewVueWidget/JsvApic/BrowserApic/PartLoopTool.js +0 -119
  114. package/utils/JsViewVueWidget/JsvApic/BrowserApic/Viewer.js +0 -106
  115. /package/utils/JsViewPlugin/JsvLatex/{JsvLatexBrowser.vue → BrowserJsvLatex.vue} +0 -0
  116. /package/utils/JsViewPlugin/JsvPlayer/{JsvPlayerBrowser-0.9.vue → BrowserJsvPlayer-0.9.vue} +0 -0
  117. /package/utils/JsViewPlugin/JsvPlayer/{JsvPlayerBrowser.vue → BrowserJsvPlayer.vue} +0 -0
  118. /package/utils/JsViewVueWidget/JsvApic/{BrowserApic → JsvBrowserApicLib}/ApicDataBase.js +0 -0
  119. /package/utils/JsViewVueWidget/JsvApic/{BrowserApic → JsvBrowserApicLib}/GifData.js +0 -0
  120. /package/utils/JsViewVueWidget/JsvApic/{BrowserApic → JsvBrowserApicLib}/WebpData.js +0 -0
@@ -5,421 +5,453 @@
5
5
  * spriteInfo {object} (必需)精灵图配置信息
6
6
  * { frames: [
7
7
  * {
8
- * source:{w,h},
9
- * target:{w,h},
8
+ * source:{x, y, w, h},
9
+ * target:{x, y, w, h},
10
10
  * },
11
11
  * ...
12
12
  * ],
13
13
  * meta:{w,h}
14
14
  * }
15
- * viewSize {object} (必需){w:0, h:0}
15
+ * viewSize {object} (可选){w:0, h:0}, 从SpriteInfo中提炼的最大子图内容显示尺寸
16
16
  * imageUrl {string} (必需)图片地址,另外,为了减小无效的解析处理,规定只有image的URL变更时才重新解析spriteInfo
17
17
  * duration {float} (动图必需)动图的时间
18
18
  * onAnimEnd {function} 动图结束回调
19
19
  * autostart {string} 启动动图,默认none,
20
- * 传入为bool类型时,兼容老版本:truestart、false为none
21
- * 自动启动模式:start:精灵图自动启动,结束后显示第一帧内容、
22
- * end:精灵图自动启动,结束后显示最后一帧内容,
20
+ * 自动启动模式:true/start:精灵图自动启动
23
21
  * none:不自动启动
24
- * loop {string或number} 动图的循环次数 infinite/数字,默认为infinite
25
- * spriteName {string} 动图的名称,默认为null
22
+ * loop {string或number} 动图的循环次数 infinite/数字,默认为单次
26
23
  * controller {SpriteController} 控制动图start,stop的对象
27
24
  *
28
- * SpriteController: 面向对象类,精灵图动作控制器
25
+ * SpriteController/或者本组件的ref: 面向对象类,精灵图动作控制器
29
26
  * 功能函数:(参数说明见函数本体)
30
27
  * start()
31
28
  * 功能: 启动精灵图动画
32
- * stop(end_frame)
29
+ * 参数表:
30
+ * indexArray : 帧数组/"all", 展示帧的序列
31
+ * endFrame : 取值"start"/"end", 动画的结束帧内容
32
+ * duration : 单次生效, 临时覆盖prop中设置的duration
33
+ * loopSet : 单次生效, 临时覆盖prop中设置的loop, 次数或者infinite
34
+ * animateEnd : 单次回调, 另外prop的onAnimEnd仍然会触发
35
+ *
36
+ * stop()
33
37
  * 功能: 停止精灵图动画,可选择静止在第一帧或最后一帧
38
+ * 参数表:
39
+ * index : 目标帧index/"start"/"end"
34
40
  -->
35
- <script setup>
36
- import { getKeyFramesGroup } from '../../JsViewVueTools/JsvDynamicKeyFrames.js'
37
- import { reactive, shallowRef, onUnmounted, watch } from 'vue';
38
- import {getsAnimationToken} from "./sAnimationToken.js"
39
-
40
- const _getTransformInfo = (source_obj, target_obj, canvas_width, canvas_height) => {
41
- const result = { csw: 1, csh: 1, cx: 0, cy: 0, sw: 1, sh: 1, x: 0, y: 0 };
42
-
43
- // Clip在Canvas div之内,以Canvas为基准进行缩放和平移
44
- // 图形左上角远离原点后再缩放,所以需要进行缩放补偿
45
- const clip_scale_w = target_obj.w / canvas_width;
46
- const clip_scale_h = target_obj.h / canvas_height;
47
- result.csw = clip_scale_w;
48
- result.csh = clip_scale_h;
49
- result.cx = target_obj.x / clip_scale_w;
50
- result.cy = target_obj.y / clip_scale_h;
51
-
52
- // Image在Clip div之内,所以以Clip为基准进行缩放和平移, 对clip的缩放进行反处理以还原尺寸
53
- // 将子图左上角对齐原点后再缩放,所以x,y不需要进行举例缩放补偿
54
- result.sw = source_obj.w / target_obj.w / clip_scale_w;
55
- result.sh = source_obj.h / target_obj.h / clip_scale_h;
56
- result.x = -source_obj.x;
57
- result.y = -source_obj.y;
58
-
59
- return result;
60
- }
61
-
62
- const _createTransformStyle = (w_scale, h_scale, x, y) => {
63
- let output = "";
64
- output = `${output}scale3d(${parseFloat(w_scale).toPrecision(5)},${parseFloat(h_scale).toPrecision(5)},1) `
65
- + `translate3d(${parseFloat(x).toPrecision(5)}px,${parseFloat(y).toPrecision(5)}px,0)`;
66
- return output;
67
- }
68
-
69
- const props = defineProps({
70
- spriteInfo: Object,
71
- viewSize: Object,
72
- imageUrl: String,
73
- duration: Number,
74
- onAnimEnd: Function,
75
- autostart: [Boolean, String],
76
- loop: [String, Number],
77
- spriteName: String,
78
- controller: Object,
79
- })
80
-
81
-
82
- let stopFrame = shallowRef("start");
83
- let TRANSFORM_ORIGIN_LEFT_TOP = shallowRef("left top")
84
- let keyFrameNames = reactive({
85
- clip: null,
86
- image: null,
87
- valid: false
88
- });
89
- let frozeFrameCache = reactive({
90
- clipStyle: {},
91
- transStyle: {},
92
- imageStyle: {
93
- backgroundImage: null,
94
- }
95
- });
96
- let animateFrameCache = reactive({
97
- clipStyle: {},
98
- transStyle: {},
99
- imageStyle: {
100
- backgroundImage: null,
101
- },
102
- clipAnimName: null,
103
- imageAnimName: null,
104
- });
105
- let keyFrameStyleSheet = getKeyFramesGroup(null);
106
- let innerId = shallowRef(0);
107
- let stopped = shallowRef(false);
108
- let spriteDuration = shallowRef(props.duration);
109
- let blinkAnim = shallowRef(null);
110
- let blinkAnimCache = reactive({});
111
-
112
- const _removeKeyFrame = (names_array) => {
113
- if (keyFrameStyleSheet) {
114
- keyFrameStyleSheet.removeMultiRules(names_array);
115
- }
116
- }
117
-
118
- const _clearExpiredKeyFrames = () => {
119
- if (keyFrameNames.valid) {
120
- _removeKeyFrame([keyFrameNames.clip, keyFrameNames.image]);
121
- keyFrameNames.valid = false;
122
- }
123
- }
124
-
125
- onUnmounted(() => {
126
- _clearExpiredKeyFrames()
127
- })
128
-
129
- const _getAnimNameBase = () => {
130
- return props.spriteName ? props.spriteName : `sprite-anim-name-${getsAnimationToken()}`;
131
- }
132
-
133
- const _updateFrozeFrameCache = (image_url, frame_info_list,
134
- canvas_width, canvas_height,
135
- source_width, source_height) => {
136
- const cache = frozeFrameCache;
137
-
138
- const index = stopFrame.value === "start" ? 0 : frame_info_list.length - 1;
139
- const tr = _getTransformInfo(
140
- frame_info_list[index].source,
141
- frame_info_list[index].target,
142
- canvas_width,
143
- canvas_height
144
- );
145
-
146
- cache.clipStyle = {
147
- transform: _createTransformStyle(tr.csw, tr.csh, tr.cx, tr.cy),
148
- transformOrigin: TRANSFORM_ORIGIN_LEFT_TOP.value,
149
- overflow: "hidden",
150
- left: 0,
151
- top: 0,
152
- width: canvas_width,
153
- height: canvas_height,
154
- };
155
-
156
- cache.transStyle = {
157
- transformOrigin: TRANSFORM_ORIGIN_LEFT_TOP.value,
158
- transform: _createTransformStyle(tr.sw, tr.sh, tr.x, tr.y),
159
- width: source_width,
160
- height: source_height,
161
- };
162
-
163
- cache.imageStyle = {
164
- backgroundImage: image_url,
165
- width: source_width,
166
- height: source_height,
167
- };
168
- }
169
-
170
- const _updateAnimateFrameCache = (image_url, frame_info_list,
171
- canvas_width, canvas_height,
172
- source_width, source_height) => {
173
- _clearExpiredKeyFrames();
174
-
175
- if (!frame_info_list) { return; }
176
- const anim_name_base = _getAnimNameBase();
177
- const frame_percent = 1 / (frame_info_list.length);
178
- const anim_name_clip = `${anim_name_base}-clip`;
179
- const anim_name_image = `${anim_name_base}-image`;
180
- let image_keyframs = `@keyframes ${anim_name_image} {`;
181
- let clip_keyframs = `@keyframes ${anim_name_clip} {`;
182
-
183
- for (let i = 0; i < frame_info_list.length + 1; i++) {
184
- let item;
185
- if (i !== frame_info_list.length) {
186
- item = frame_info_list[i];
187
- } else {
188
- // 追加一个最后一帧以保证最后一帧可见
189
- item = frame_info_list[frame_info_list.length - 1];
190
- }
191
-
192
- // Header
193
- let header;
194
- if (i !== frame_info_list.length) {
195
- header = `${parseFloat(frame_percent * i * 100).toFixed(2)}% {`;
196
- } else {
197
- header = '100% {';
198
- }
199
- image_keyframs += header;
200
- clip_keyframs += header;
201
-
202
- if (item.source) {
203
- const tr = _getTransformInfo(item.source, item.target, canvas_width, canvas_height);
204
- const clip_trans = _createTransformStyle(tr.csw, tr.csh, tr.cx, tr.cy);
205
- const image_trans = _createTransformStyle(tr.sw, tr.sh, tr.x, tr.y);
206
-
207
- let tr_str = "";
208
- tr_str = `${tr_str}transform:${clip_trans};transform-origin:left top;`;
209
- clip_keyframs += tr_str;
210
-
211
- tr_str = "";
212
- tr_str = `${tr_str}transform:${image_trans};transform-origin:left top;`;
213
- image_keyframs += tr_str;
214
- }
215
-
216
- image_keyframs += '}';
217
- clip_keyframs += '}';
218
- }
219
-
220
- image_keyframs += '}';
221
- clip_keyframs += '}';
222
-
223
- if (keyFrameStyleSheet) {
224
- keyFrameStyleSheet.insertRule(image_keyframs);
225
- keyFrameStyleSheet.insertRule(clip_keyframs);
226
-
227
- // 记录Keyframe设置,以便于界面关闭时进行清理
228
- keyFrameNames.clip = anim_name_clip;
229
- keyFrameNames.image = anim_name_image;
230
- keyFrameNames.valid = true;
231
- }
232
- const cache = animateFrameCache;
233
-
234
- cache.clipAnimName = `${anim_name_base}-clip`;
235
- cache.imageAnimName = `${anim_name_base}-image`;
236
-
237
- cache.clipStyle = {
238
- overflow: "hidden",
239
- width: canvas_width,
240
- height: canvas_height,
241
- transform: null, // 重置 transform,以免影响keyframe动画
242
- transformOrigin: TRANSFORM_ORIGIN_LEFT_TOP.value,
243
- animation: null, // 外部设置,需要时间和loop信息
244
- };
245
-
246
- cache.transStyle = {
247
- transform: null, // 重置 transform,以免影响keyframe动画
248
- transformOrigin: TRANSFORM_ORIGIN_LEFT_TOP.value,
249
- animation: null, // 外部设置,需要时间和loop信息
250
- width: source_width,
251
- height: source_height,
252
- };
253
-
254
- cache.imageStyle = {
255
- backgroundImage: image_url,
256
- width: source_width,
257
- height: source_height,
258
- };
259
- }
260
-
261
- const _IsAutoStart = () => {
262
- let autoStart = false;
263
- if (typeof props.autostart === "boolean") {
264
- autoStart = props.autostart;
265
- } if (typeof props.autostart === "string" && props.autostart !== "none") {
266
- autoStart = true;
267
- }
268
- return autoStart;
269
- }
270
-
271
-
272
- const _AnalyzeProp = () => {
273
- const used = props.controller && props.controller.Used;
274
- if (props.spriteInfo.frames.length === 1 || (!used && !_IsAutoStart()) || stopped.value) {
275
- // 单图模式
276
- // 解析图片信息
277
- _updateFrozeFrameCache(
278
- props.imageUrl,
279
- props.spriteInfo.frames,
280
- props.viewSize.w,
281
- props.viewSize.h,
282
- props.spriteInfo.meta.size.w,
283
- props.spriteInfo.meta.size.h
284
- );
285
-
286
- return {
287
- clipStyle: frozeFrameCache.clipStyle,
288
- transStyle: frozeFrameCache.transStyle,
289
- imageStyle: frozeFrameCache.imageStyle,
290
- };
291
- }
292
-
293
-
294
- // 动画模式
295
- if (animateFrameCache.imageStyle.backgroundImage !== props.imageUrl) {
296
- // 解析图片信息
297
- _updateAnimateFrameCache(
298
- props.imageUrl,
299
- props.spriteInfo.frames,
300
- props.viewSize.w,
301
- props.viewSize.h,
302
- props.spriteInfo.meta.size.w,
303
- props.spriteInfo.meta.size.h
304
- );
305
- }
306
-
307
- // 使用duration和loop信息更新动画设定
308
- animateFrameCache.clipStyle.animation =
309
- `${animateFrameCache.clipAnimName} ${spriteDuration.value}s steps(1,end) ${props.loop}`;
310
- animateFrameCache.transStyle.animation =
311
- `${animateFrameCache.imageAnimName} ${spriteDuration.value}s steps(1,end) ${props.loop}`;
312
-
313
- return {
314
- clipStyle: animateFrameCache.clipStyle,
315
- transStyle: animateFrameCache.transStyle,
316
- imageStyle: animateFrameCache.imageStyle,
317
- };
318
- }
319
- let transform_style = reactive(_AnalyzeProp());
320
-
321
- watch(props, (n, o) => {
322
- transform_style = _AnalyzeProp();
323
- })
324
- const onAnimEndDelegate = () => {
325
- // 在onAnimEnd之前进行Stop,以防onAnimEnd内部继续发生别的操作
326
- if (props.onAnimEnd) {
327
- props.onAnimEnd();
328
- }
329
- }
330
-
331
- const onBlinkAnimEnd = () => {
332
- // 在onAnimEnd之前进行Stop,以防onAnimEnd内部继续发生别的操作
333
- blinkAnim.value = null;
334
- }
335
-
336
- const op = {
337
- start: (end_frame, duration) => {
338
- if (props.spriteInfo.frames && props.spriteInfo.frames.length === 1) {
339
- return;
340
- }
341
- innerId.value += 1;
342
- stopped.value = false;
343
- spriteDuration.value = duration || props.duration;
344
- stopFrame.value = end_frame || stopFrame.value;
345
- },
346
- stop: (end_frame) => {
347
- if (props.spriteInfo.frames && props.spriteInfo.frames.length === 1) {
348
- return;
349
- }
350
- stopped.value = true;
351
- stopFrame.value = end_frame || stopFrame.value;
352
- },
353
- blink: (alphas, duration, ease, delay, repeat) => {
354
- // 注意:比较数组是否相同仅在此场景下使用toString,其他场景
355
- if (!blinkAnimCache
356
- || (blinkAnimCache.alphas.toString() !== alphas.toString()
357
- || blinkAnimCache.duration !== duration
358
- || blinkAnimCache.ease !== ease
359
- || blinkAnimCache.delay !== delay
360
- || blinkAnimCache.repeat !== repeat)) {
361
- const anim_name_base = _getAnimNameBase();
362
- const anim_name_blink = `${anim_name_base}-blink`;
363
- let image_keyframs = `@keyframes ${anim_name_blink} {`;
364
- const frame_percent = 1 / (alphas.length);
365
- for (let i = 0; i < alphas.length; i++) {
366
- const alpha = alphas[i];
367
- let header;
368
- if (i !== alphas.length - 1) {
369
- header = `${parseFloat(frame_percent * i * 100).toFixed(2)}% {`;
370
- } else {
371
- header = '100% {';
372
- }
373
- image_keyframs += header;
374
-
375
- if (alpha) {
376
- const tr_str = ` opacity:${alpha};`;
377
- image_keyframs += tr_str;
378
- }
379
-
380
- image_keyframs += '}';
381
- image_keyframs += "\n";
382
- }
383
- image_keyframs += '}';
384
- if (keyFrameStyleSheet) {
385
- keyFrameStyleSheet.insertRule(image_keyframs);
386
- }
387
- blinkAnimCache = {
388
- alphas,
389
- duration,
390
- ease,
391
- delay,
392
- repeat,
393
- blinkAnimName: anim_name_blink
394
- };
395
- }
396
-
397
- // 参数格式化
398
- ease = ease || "";
399
- delay = delay || 0;
400
- repeat = (repeat === -1) ? "infinite" : (repeat || 1);
401
-
402
- const animName = `${blinkAnimCache.blinkAnimName} ${duration}s ${ease} ${delay}s ${repeat}`;
403
- blinkAnim.value = animName;
404
- stopped.value = true;
405
- }
406
-
407
- };
408
- //TODO:
409
- props.controller?._setSpriteImg(op);
410
- </script>
411
-
412
- <template>
413
- <div id="canvas">
414
- <div id="clip" :style="{ ...transform_style.clipStyle }" :key="innerId">
415
- <div id="trans" :style="{ ...transform_style.transStyle }" @animationend="onAnimEndDelegate" :key="innerId">
416
- <div id="image" :style="{ ...transform_style.imageStyle, animation: blinkAnim }" :key="innerId"
417
- @animationend="onBlinkAnimEnd"></div>
418
- </div>
419
- </div>
420
- </div>
421
- </template>
422
-
423
- <style scoped>
424
- @keyframes sprite-tag {}
425
- </style>
41
+ <script setup>
42
+ import { reactive, shallowRef, onUnmounted, watch, defineExpose } from "vue";
43
+ import * as FBuilder from "./FrameBuidler";
44
+
45
+ const props = defineProps({
46
+ spriteInfo: Object,
47
+ viewSize: Object,
48
+ imageUrl: String,
49
+ duration: { type: Number, default: 1 },
50
+ onAnimEnd: Function,
51
+ autostart: { type: [Boolean, String], default: false },
52
+ loop: { type: [String, Number], default: "" },
53
+ controller: Object,
54
+ spriteName: String, // 废弃(Deprecated)
55
+ });
56
+
57
+ // ******** 内部状态 ********
58
+ let innerId = shallowRef(0);
59
+ let spriteDuration = shallowRef(props.duration);
60
+ let apiStartEndCallback = null;
61
+ let canvasSize = { width: 0, height: 0 };
62
+ // 直接影响div的做step动画的style
63
+ let transformStyle = {
64
+ clipStyle: shallowRef({}),
65
+ transStyle: shallowRef({}),
66
+ imageStyle: shallowRef({}),
67
+ };
68
+ // 静态图的缓存
69
+ let staticFrameCachedInfo = null;
70
+ // 动态图的缓存
71
+ let animFrameCachedInfo = null;
72
+ // watch时的比较缓存
73
+ let cachedProps = {
74
+ spriteInfo: props.spriteInfo,
75
+ };
76
+
77
+ // ******** private function ********
78
+ const _IsAutoStart = () => {
79
+ let autoStart = false;
80
+ if (typeof props.autostart === "boolean") {
81
+ autoStart = props.autostart;
82
+ }
83
+ if (typeof props.autostart === "string" && props.autostart !== "none") {
84
+ autoStart = true;
85
+ }
86
+ return autoStart;
87
+ };
88
+ // 创建静态图
89
+ const _BuildStaticFrame = (targetIndex) => {
90
+ if (!staticFrameCachedInfo) {
91
+ // 初始化静态图缓存
92
+ staticFrameCachedInfo = {
93
+ props: {
94
+ frameIndex: undefined,
95
+ },
96
+ result: null,
97
+ };
98
+ }
99
+
100
+ if (
101
+ staticFrameCachedInfo.result == null ||
102
+ staticFrameCachedInfo.props.frameIndex != targetIndex
103
+ ) {
104
+ // 缓存需要变化时,重算单图信息
105
+ let framesLength = props.spriteInfo.frames.length;
106
+ if (targetIndex < 0 || targetIndex >= framesLength) {
107
+ console.error(
108
+ `Error: static out of range idx=${targetIndex} len=${framesLength}`
109
+ );
110
+ targetIndex = 0;
111
+ }
112
+
113
+ // 解析图片信息
114
+ let spriteInfo = FBuilder.newFrozeFrame(
115
+ props.imageUrl,
116
+ props.spriteInfo.frames,
117
+ targetIndex,
118
+ canvasSize.width,
119
+ canvasSize.height,
120
+ props.spriteInfo.meta.size.w,
121
+ props.spriteInfo.meta.size.h
122
+ );
123
+
124
+ staticFrameCachedInfo.props.frameIndex = targetIndex;
125
+ staticFrameCachedInfo.result = spriteInfo;
126
+ }
127
+
128
+ return staticFrameCachedInfo.result;
129
+ };
130
+ // 创建动图
131
+ const _BuildAnimateFrame = (indexArray) => {
132
+ if (props.spriteInfo.frames == 1) {
133
+ // 单帧内容,始终使用静态图
134
+ return _BuildStaticFrame(0);
135
+ }
136
+
137
+ if (!animFrameCachedInfo) {
138
+ // 初始化动态图缓存
139
+ animFrameCachedInfo = {
140
+ props: {
141
+ indexArray: "all",
142
+ },
143
+ result: null,
144
+ };
145
+ }
146
+
147
+ let arrayMatch = true;
148
+ if (animFrameCachedInfo.result == null) {
149
+ arrayMatch = false;
150
+ } else {
151
+ // 遍历比较indexArray
152
+ let originArray = animFrameCachedInfo.props.indexArray;
153
+ if (indexArray != originArray) {
154
+ if (typeof indexArray == "string" || typeof originArray == "string") {
155
+ // String区别则必定为不同
156
+ arrayMatch = false;
157
+ }
158
+ if (indexArray.length == originArray.length) {
159
+ for (let i = 0; i < indexArray.length; i++) {
160
+ if (indexArray[i] != originArray[i]) {
161
+ arrayMatch = false;
162
+ break;
163
+ }
164
+ }
165
+ } else {
166
+ arrayMatch = false;
167
+ }
168
+ }
169
+ }
170
+
171
+ if (!arrayMatch) {
172
+ // 解析图片信息
173
+ let newFramesArray;
174
+ if (indexArray == "all") {
175
+ // 全序列
176
+ newFramesArray = props.spriteInfo.frames;
177
+ } else {
178
+ newFramesArray = [];
179
+ let lastFrameIndex = 0;
180
+ let framesLength = props.spriteInfo.frames.length;
181
+ for (const frameIndex of indexArray) {
182
+ let targetIndex = frameIndex;
183
+ if (frameIndex < 0 || frameIndex >= framesLength) {
184
+ console.warn(`out of range ${frameIndex} of len=${framesLength}`);
185
+ targetIndex = lastFrameIndex; // 使用上一帧
186
+ }
187
+ newFramesArray.push(props.spriteInfo.frames[targetIndex]);
188
+ }
189
+ }
190
+
191
+ if (animFrameCachedInfo.result != null) {
192
+ // 清理残留的内容
193
+ FBuilder.expireAnimates(animFrameCachedInfo.result);
194
+ animFrameCachedInfo.result = null;
195
+ }
196
+
197
+ let spriteInfo = FBuilder.newAnimateFrames(
198
+ props.imageUrl,
199
+ newFramesArray,
200
+ canvasSize.width,
201
+ canvasSize.height,
202
+ props.spriteInfo.meta.size.w,
203
+ props.spriteInfo.meta.size.h
204
+ );
205
+
206
+ animFrameCachedInfo.props.indexArray = indexArray;
207
+ animFrameCachedInfo.result = spriteInfo;
208
+ }
209
+
210
+ return animFrameCachedInfo.result;
211
+ };
212
+ // 设置给div
213
+ const _ApplySpriteInfo = (spriteInfo) => {
214
+ transformStyle.clipStyle.value = spriteInfo.clipStyle;
215
+ transformStyle.transStyle.value = spriteInfo.transStyle;
216
+ transformStyle.imageStyle.value = spriteInfo.imageStyle;
217
+ innerId.value += 1; // 通过key触发控制体刷新
218
+ };
219
+
220
+ // 重置内容处理
221
+ const _OnReset = () => {
222
+ let spriteInfo;
223
+ if (_IsAutoStart()) {
224
+ // 启动动画
225
+ spriteInfo = _BuildAnimateFrame("all");
226
+ // 注入animation属性
227
+ spriteInfo.clipStyle.animation = `${spriteInfo.clipKeyFrameName} ${spriteDuration.value}s steps(1,end) ${props.loop}`;
228
+ spriteInfo.transStyle.animation = `${spriteInfo.transKeyFrameName} ${spriteDuration.value}s steps(1,end) ${props.loop}`;
229
+ } else {
230
+ // 展示静图
231
+ spriteInfo = _BuildStaticFrame(0);
232
+ }
233
+ _ApplySpriteInfo(spriteInfo);
234
+
235
+ // 更新缓存
236
+ cachedProps.spriteInfo = props.spriteInfo;
237
+ };
238
+
239
+ // ******** 初始化处理 ********
240
+ // 获取viewSize
241
+ if (props.viewSize) {
242
+ canvasSize.width = props.viewSize.w;
243
+ canvasSize.height = props.viewSize.h;
244
+ } else {
245
+ // 从frame中提取canvasSize
246
+ let max_width = 0;
247
+ let max_height = 0;
248
+ for (let i = 0; i < props.spriteInfo.frames.length; i++) {
249
+ const target = props.spriteInfo.frames[i].target;
250
+ const sprite_with = target.x + target.w;
251
+ const sprite_height = target.y + target.h;
252
+ if (sprite_with > max_width) {
253
+ max_width = sprite_with;
254
+ }
255
+ if (sprite_height > max_height) {
256
+ max_height = sprite_height;
257
+ }
258
+ }
259
+ canvasSize.width = max_width;
260
+ canvasSize.height = max_height;
261
+ }
262
+
263
+ // 注册prop变化的内容重置
264
+ watch(props, (newProps) => {
265
+ // 属性变化重置缓存
266
+ if (newProps.spriteInfo != cachedProps.spriteInfo) {
267
+ console.log("Sprite reset for spriteInfo changed");
268
+ _OnReset();
269
+ }
270
+ });
271
+
272
+ // 首次启动处理
273
+ _OnReset();
274
+
275
+ let blinkAnim = shallowRef(null);
276
+ let blinkAnimCache = reactive({});
277
+
278
+ onUnmounted(() => {
279
+ if (animFrameCachedInfo?.result != null) {
280
+ // 清理残留的内容
281
+ FBuilder.expireAnimates(animFrameCachedInfo.result);
282
+ animFrameCachedInfo.result = null;
283
+ }
284
+ });
285
+
286
+ const onAnimEndDelegate = () => {
287
+ // 在onAnimEnd之前进行Stop,以防onAnimEnd内部继续发生别的操作
288
+ if (props.onAnimEnd) {
289
+ props.onAnimEnd();
290
+ }
291
+
292
+ // 一次性临时回调
293
+ if (apiStartEndCallback) {
294
+ let cb = apiStartEndCallback;
295
+ apiStartEndCallback = null;
296
+ cb();
297
+ }
298
+ };
299
+
300
+ const onBlinkAnimEnd = () => {
301
+ // 在onAnimEnd之前进行Stop,以防onAnimEnd内部继续发生别的操作
302
+ blinkAnim.value = null;
303
+ };
304
+
305
+ const op = {
306
+ start: (
307
+ indexArray /* 帧数组/"all" */,
308
+ endFrame /* 取值"start"/"end" */,
309
+ duration /* 覆盖prop中设置的duration */,
310
+ loopSet /* 覆盖prop中设置的loop */,
311
+ animateEnd /* 单次回调 */
312
+ ) => {
313
+ if (props.spriteInfo.frames && props.spriteInfo.frames.length === 1) {
314
+ console.error(
315
+ `Error: start failed for frames not enough len=${props.spriteInfo.frames.length}`
316
+ );
317
+ return;
318
+ }
319
+
320
+ // 规范化入参
321
+ if (!indexArray) {
322
+ indexArray = "all"; // 默认为全展示
323
+ }
324
+ if (!loopSet) {
325
+ loopSet = "";
326
+ }
327
+ if (!duration) {
328
+ duration = props.duration;
329
+ }
330
+
331
+ // 设置回调处理
332
+ apiStartEndCallback = () => {
333
+ // 控制结束帧
334
+ let endIndex = 0;
335
+ if (indexArray instanceof Array) {
336
+ endIndex =
337
+ endFrame == "start"
338
+ ? indexArray[0]
339
+ : indexArray[indexArray.length - 1];
340
+ } else {
341
+ endIndex = endFrame == "start" ? 0 : props.spriteInfo.frames.length - 1;
342
+ }
343
+ let endSpriteInfo = _BuildStaticFrame(endIndex);
344
+ _ApplySpriteInfo(endSpriteInfo);
345
+
346
+ if (animateEnd) {
347
+ animateEnd();
348
+ }
349
+ };
350
+
351
+ let spriteInfo = _BuildAnimateFrame(indexArray);
352
+ // 注入animation属性
353
+ spriteInfo.clipStyle.animation = `${spriteInfo.clipKeyFrameName} ${duration}s steps(1,end) ${loopSet}`;
354
+ spriteInfo.transStyle.animation = `${spriteInfo.transKeyFrameName} ${duration}s steps(1,end) ${loopSet}`;
355
+
356
+ // 设置界面
357
+ _ApplySpriteInfo(spriteInfo);
358
+ },
359
+ stop: (index /* 目标帧index/"start"/"end" */) => {
360
+ // 清理start临时处理
361
+ apiStartEndCallback = null;
362
+
363
+ let targetIndex;
364
+ if (typeof index == "undefined") {
365
+ targetIndex = 0; // 默认停止在第一帧
366
+ } else if (typeof index == "string") {
367
+ // 停在首帧或者最后一帧
368
+ targetIndex = index == "start" ? 0 : props.spriteInfo.frames.length - 1;
369
+ } else {
370
+ targetIndex = index;
371
+ }
372
+
373
+ let spriteInfo = _BuildStaticFrame(targetIndex);
374
+ _ApplySpriteInfo(spriteInfo);
375
+ },
376
+
377
+ // 含有透明度的transform变化
378
+ blink: (alphas, duration, ease, delay, repeat) => {
379
+ // TODO: 暂时不做alpha变化的需求
380
+ // 注意:比较数组是否相同仅在此场景下使用toString,其他场景
381
+ // if (
382
+ // !blinkAnimCache ||
383
+ // blinkAnimCache.alphas.toString() !== alphas.toString() ||
384
+ // blinkAnimCache.duration !== duration ||
385
+ // blinkAnimCache.ease !== ease ||
386
+ // blinkAnimCache.delay !== delay ||
387
+ // blinkAnimCache.repeat !== repeat
388
+ // ) {
389
+ // const anim_name_base = _getAnimNameBase();
390
+ // const anim_name_blink = `${anim_name_base}-blink`;
391
+ // let image_keyframs = `@keyframes ${anim_name_blink} {`;
392
+ // const frame_percent = 1 / alphas.length;
393
+ // for (let i = 0; i < alphas.length; i++) {
394
+ // const alpha = alphas[i];
395
+ // let header;
396
+ // if (i !== alphas.length - 1) {
397
+ // header = `${parseFloat(frame_percent * i * 100).toFixed(2)}% {`;
398
+ // } else {
399
+ // header = "100% {";
400
+ // }
401
+ // image_keyframs += header;
402
+ // if (alpha) {
403
+ // const tr_str = ` opacity:${alpha};`;
404
+ // image_keyframs += tr_str;
405
+ // }
406
+ // image_keyframs += "}";
407
+ // image_keyframs += "\n";
408
+ // }
409
+ // image_keyframs += "}";
410
+ // if (keyFrameStyleSheet) {
411
+ // keyFrameStyleSheet.insertRule(image_keyframs);
412
+ // }
413
+ // blinkAnimCache = {
414
+ // alphas,
415
+ // duration,
416
+ // ease,
417
+ // delay,
418
+ // repeat,
419
+ // blinkAnimName: anim_name_blink,
420
+ // };
421
+ // }
422
+ // // 参数格式化
423
+ // ease = ease || "";
424
+ // delay = delay || 0;
425
+ // repeat = repeat === -1 ? "infinite" : repeat || 1;
426
+ // const animName = `${blinkAnimCache.blinkAnimName} ${duration}s ${ease} ${delay}s ${repeat}`;
427
+ // blinkAnim.value = animName;
428
+ // stopped.value = true;
429
+ },
430
+ };
431
+
432
+ // 兼容老版本的control控制处理
433
+ props.controller?._setSpriteImg(op);
434
+
435
+ defineExpose(op);
436
+ </script>
437
+
438
+ <template>
439
+ <div id="clip" :style="transformStyle.clipStyle.value" :key="innerId">
440
+ <div
441
+ id="trans"
442
+ :style="transformStyle.transStyle.value"
443
+ @animationend="onAnimEndDelegate"
444
+ >
445
+ <div
446
+ id="image"
447
+ :style="{ ...transformStyle.imageStyle.value, animation: blinkAnim }"
448
+ @animationend="onBlinkAnimEnd"
449
+ ></div>
450
+ </div>
451
+ </div>
452
+ </template>
453
+
454
+ <style scoped>
455
+ @keyframes sprite-tag {
456
+ }
457
+ </style>