lido-player 0.0.1 → 0.0.2-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/app-col_12.cjs.entry.js +1256 -0
- package/dist/cjs/app-col_12.cjs.entry.js.map +1 -0
- package/dist/cjs/app-globals-3a1e7e63.js +7 -0
- package/dist/cjs/app-globals-3a1e7e63.js.map +1 -0
- package/dist/cjs/index-0d28e716.js +1466 -0
- package/dist/cjs/index-0d28e716.js.map +1 -0
- package/dist/cjs/index.cjs.js +11 -0
- package/dist/cjs/index.cjs.js.map +1 -0
- package/dist/cjs/lido-player.cjs.js +27 -0
- package/dist/cjs/lido-player.cjs.js.map +1 -0
- package/dist/cjs/loader.cjs.js +17 -0
- package/dist/cjs/loader.cjs.js.map +1 -0
- package/dist/cjs/utils-8ac0e3b7.js +597 -0
- package/dist/cjs/utils-8ac0e3b7.js.map +1 -0
- package/dist/collection/collection-manifest.json +23 -0
- package/dist/collection/components/column/AppCol.js +430 -0
- package/dist/collection/components/column/AppCol.js.map +1 -0
- package/dist/collection/components/column/app-col.css +19 -0
- package/dist/collection/components/container/AppContainer.js +495 -0
- package/dist/collection/components/container/AppContainer.js.map +1 -0
- package/dist/collection/components/container/app-container.css +10 -0
- package/dist/collection/components/home/AppHome.js +261 -0
- package/dist/collection/components/home/AppHome.js.map +1 -0
- package/dist/collection/components/home/app-home.css +48 -0
- package/dist/collection/components/image/AppImage.js +431 -0
- package/dist/collection/components/image/AppImage.js.map +1 -0
- package/dist/collection/components/image/app-image.css +9 -0
- package/dist/collection/components/position/AppPos.js +428 -0
- package/dist/collection/components/position/AppPos.js.map +1 -0
- package/dist/collection/components/position/app-pos.css +16 -0
- package/dist/collection/components/random/AppRandom.js +435 -0
- package/dist/collection/components/random/AppRandom.js.map +1 -0
- package/dist/collection/components/random/app-random.css +10 -0
- package/dist/collection/components/root/AppRoot.js +83 -0
- package/dist/collection/components/root/AppRoot.js.map +1 -0
- package/dist/collection/components/root/assets/Audio/goodJob.mp3 +0 -0
- package/dist/collection/components/root/assets/Audio/tryAgain.mp3 +0 -0
- package/dist/collection/components/root/assets/Audio/wellDone.mp3 +0 -0
- package/dist/collection/components/root/assets/images/HIimage.png +0 -0
- package/dist/collection/components/root/assets/images/VIimage.png +0 -0
- package/dist/collection/components/root/assets/images/animals/giraffe.png +0 -0
- package/dist/collection/components/root/assets/images/animals/leopard.png +0 -0
- package/dist/collection/components/root/assets/images/animals/lion.png +0 -0
- package/dist/collection/components/root/assets/images/animals/tiger.png +0 -0
- package/dist/collection/components/root/assets/images/bodyParts/ear.png +0 -0
- package/dist/collection/components/root/assets/images/bodyParts/eyes.png +0 -0
- package/dist/collection/components/root/assets/images/bodyParts/nose.png +0 -0
- package/dist/collection/components/root/assets/images/girl.png +0 -0
- package/dist/collection/components/root/assets/images/icons/access.png +0 -0
- package/dist/collection/components/root/assets/images/icons/brightness.png +0 -0
- package/dist/collection/components/root/assets/images/icons/cancel.png +0 -0
- package/dist/collection/components/root/assets/images/icons/contrast.png +0 -0
- package/dist/collection/components/root/assets/images/icons/dropDown.png +0 -0
- package/dist/collection/components/root/assets/images/icons/exit.png +0 -0
- package/dist/collection/components/root/assets/images/icons/hide.png +0 -0
- package/dist/collection/components/root/assets/images/icons/invert.png +0 -0
- package/dist/collection/components/root/assets/images/icons/lineSpacing.png +0 -0
- package/dist/collection/components/root/assets/images/icons/sound.png +0 -0
- package/dist/collection/components/root/assets/images/icons/zoom.png +0 -0
- package/dist/collection/components/root/assets/images/truck/blueTruck.png +0 -0
- package/dist/collection/components/root/assets/images/truck/dashedBox.png +0 -0
- package/dist/collection/components/root/assets/images/truck/face.png +0 -0
- package/dist/collection/components/root/assets/images/truck/road.jpg +0 -0
- package/dist/collection/components/root/assets/images/truck/seeing.png +0 -0
- package/dist/collection/components/root/assets/images/truck/truck.png +0 -0
- package/dist/collection/components/root/assets/images/twoColorBg.jpg +0 -0
- package/dist/collection/components/root/assets/xmlData.xml +121 -0
- package/dist/collection/components/row/AppRow.js +409 -0
- package/dist/collection/components/row/AppRow.js.map +1 -0
- package/dist/collection/components/row/app-row.css +10 -0
- package/dist/collection/components/shape/AppShape.js +446 -0
- package/dist/collection/components/shape/AppShape.js.map +1 -0
- package/dist/collection/components/shape/app-shape.css +96 -0
- package/dist/collection/components/text/AppText.js +521 -0
- package/dist/collection/components/text/AppText.js.map +1 -0
- package/dist/collection/components/text/app-text.css +16 -0
- package/dist/collection/components/trace/app-trace.css +71 -0
- package/dist/collection/components/trace/app-trace.js +707 -0
- package/dist/collection/components/trace/app-trace.js.map +1 -0
- package/dist/collection/components/wrap/AppWrap.js +428 -0
- package/dist/collection/components/wrap/AppWrap.js.map +1 -0
- package/dist/collection/components/wrap/app-wrap.css +11 -0
- package/dist/collection/index.css +6 -0
- package/dist/collection/index.js +11 -0
- package/dist/collection/index.js.map +1 -0
- package/dist/{lido-player/constants-f484fcec.js → collection/utils/constants.js} +4 -7
- package/dist/collection/utils/constants.js.map +1 -0
- package/dist/collection/utils/css/animation.css +97 -0
- package/dist/{lido-player/utils-291495a4.js → collection/utils/utils.js} +6 -10
- package/dist/collection/utils/utils.js.map +1 -0
- package/dist/components/app-col.js +8 -0
- package/dist/components/app-col.js.map +1 -0
- package/dist/components/app-container.js +8 -0
- package/dist/components/app-container.js.map +1 -0
- package/dist/components/app-home.js +8 -0
- package/dist/components/app-home.js.map +1 -0
- package/dist/components/app-image.js +8 -0
- package/dist/components/app-image.js.map +1 -0
- package/dist/components/app-pos.js +8 -0
- package/dist/components/app-pos.js.map +1 -0
- package/dist/components/app-random.js +8 -0
- package/dist/components/app-random.js.map +1 -0
- package/dist/components/app-root.js +141 -0
- package/dist/components/app-root.js.map +1 -0
- package/dist/components/app-row.js +8 -0
- package/dist/components/app-row.js.map +1 -0
- package/dist/components/app-shape.js +8 -0
- package/dist/components/app-shape.js.map +1 -0
- package/dist/components/app-text.js +8 -0
- package/dist/components/app-text.js.map +1 -0
- package/dist/components/app-trace.js +8 -0
- package/dist/components/app-trace.js.map +1 -0
- package/dist/components/app-wrap.js +8 -0
- package/dist/components/app-wrap.js.map +1 -0
- package/dist/components/index.js +4 -0
- package/dist/components/index.js.map +1 -0
- package/dist/{lido-player/app-image.entry.js → components/p-34c825bf.js} +48 -11
- package/dist/components/p-34c825bf.js.map +1 -0
- package/dist/{lido-player/app-wrap.entry.js → components/p-350205d5.js} +48 -11
- package/dist/components/p-350205d5.js.map +1 -0
- package/dist/components/p-44db2553.js +1295 -0
- package/dist/components/p-44db2553.js.map +1 -0
- package/dist/components/p-4db699ee.js +591 -0
- package/dist/components/p-4db699ee.js.map +1 -0
- package/dist/{lido-player/app-shape.entry.js → components/p-639f58cb.js} +49 -11
- package/dist/components/p-639f58cb.js.map +1 -0
- package/dist/{lido-player/app-pos.entry.js → components/p-8bc122ff.js} +48 -11
- package/dist/components/p-8bc122ff.js.map +1 -0
- package/dist/{lido-player/app-trace.entry.js → components/p-aa381e73.js} +41 -10
- package/dist/components/p-aa381e73.js.map +1 -0
- package/dist/{lido-player/app-row.entry.js → components/p-bb0a3ffa.js} +47 -11
- package/dist/components/p-bb0a3ffa.js.map +1 -0
- package/dist/{lido-player/app-container.entry.js → components/p-c0c3e960.js} +50 -13
- package/dist/components/p-c0c3e960.js.map +1 -0
- package/dist/{lido-player/app-text.entry.js → components/p-c9a89df3.js} +53 -11
- package/dist/components/p-c9a89df3.js.map +1 -0
- package/dist/{lido-player/app-home.entry.js → components/p-dee011ef.js} +94 -9
- package/dist/components/p-dee011ef.js.map +1 -0
- package/dist/{lido-player/app-col.entry.js → components/p-e509500a.js} +48 -11
- package/dist/components/p-e509500a.js.map +1 -0
- package/dist/{lido-player/app-random.entry.js → components/p-f8bcec19.js} +47 -9
- package/dist/components/p-f8bcec19.js.map +1 -0
- package/dist/esm/app-col_12.entry.js +1241 -0
- package/dist/esm/app-col_12.entry.js.map +1 -0
- package/dist/esm/index-00663f21.js +1437 -0
- package/dist/esm/index-00663f21.js.map +1 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/lido-player.js +22 -0
- package/dist/esm/lido-player.js.map +1 -0
- package/dist/esm/loader.js +13 -0
- package/dist/esm/loader.js.map +1 -0
- package/dist/esm/utils-cbfaa4d8.js +591 -0
- package/dist/esm/utils-cbfaa4d8.js.map +1 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/lido-player/index.esm.js +1 -13
- package/dist/lido-player/index.esm.js.map +1 -1
- package/dist/lido-player/lido-player.css +1 -6
- package/dist/lido-player/lido-player.esm.js +1 -48
- package/dist/lido-player/lido-player.esm.js.map +1 -1
- package/dist/lido-player/p-160313d2.js +3 -0
- package/dist/lido-player/p-160313d2.js.map +1 -0
- package/dist/lido-player/p-4db699ee.js +2 -0
- package/dist/lido-player/p-4db699ee.js.map +1 -0
- package/dist/lido-player/p-c87e2f20.entry.js +2 -0
- package/dist/lido-player/p-c87e2f20.entry.js.map +1 -0
- package/dist/lido-player/p-e1255160.js +2 -0
- package/dist/lido-player/p-e1255160.js.map +1 -0
- package/dist/types/components/root/AppRoot.d.ts +8 -4
- package/dist/types/components.d.ts +16 -8
- package/package.json +1 -1
- package/dist/lido-player/app-col.entry.js.map +0 -1
- package/dist/lido-player/app-container.entry.js.map +0 -1
- package/dist/lido-player/app-home.entry.js.map +0 -1
- package/dist/lido-player/app-image.entry.js.map +0 -1
- package/dist/lido-player/app-pos.entry.js.map +0 -1
- package/dist/lido-player/app-random.entry.js.map +0 -1
- package/dist/lido-player/app-root.entry.js +0 -34
- package/dist/lido-player/app-root.entry.js.map +0 -1
- package/dist/lido-player/app-row.entry.js.map +0 -1
- package/dist/lido-player/app-shape.entry.js.map +0 -1
- package/dist/lido-player/app-text.entry.js.map +0 -1
- package/dist/lido-player/app-trace.entry.js.map +0 -1
- package/dist/lido-player/app-wrap.entry.js.map +0 -1
- package/dist/lido-player/constants-f484fcec.js.map +0 -1
- package/dist/lido-player/index-9624adf5.js +0 -3013
- package/dist/lido-player/index-9624adf5.js.map +0 -1
- package/dist/lido-player/shadow-css-7ad5caf8.js +0 -334
- package/dist/lido-player/shadow-css-7ad5caf8.js.map +0 -1
- package/dist/lido-player/utils-291495a4.js.map +0 -1
- /package/dist/{lido-player → esm}/app-globals-0f993ce5.js +0 -0
- /package/dist/{lido-player → esm}/app-globals-0f993ce5.js.map +0 -0
|
@@ -0,0 +1,1256 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
const index = require('./index-0d28e716.js');
|
|
6
|
+
const utils = require('./utils-8ac0e3b7.js');
|
|
7
|
+
|
|
8
|
+
const appColCss = ".col{top:var(--y, 0);left:var(--x, 0);height:var(--height, 100%);width:var(--width, 100%);background-color:var(--bgColor, #eeeeee);padding:15px;border-radius:10px;display:flex;justify-content:space-around;flex-direction:column;align-items:center}.col>*{}";
|
|
9
|
+
const AppColStyle0 = appColCss;
|
|
10
|
+
|
|
11
|
+
const AppCol = class {
|
|
12
|
+
constructor(hostRef) {
|
|
13
|
+
index.registerInstance(this, hostRef);
|
|
14
|
+
this.id = undefined;
|
|
15
|
+
this.value = undefined;
|
|
16
|
+
this.height = undefined;
|
|
17
|
+
this.width = undefined;
|
|
18
|
+
this.ariaLabel = undefined;
|
|
19
|
+
this.ariaHidden = undefined;
|
|
20
|
+
this.x = undefined;
|
|
21
|
+
this.y = undefined;
|
|
22
|
+
this.z = undefined;
|
|
23
|
+
this.bgColor = undefined;
|
|
24
|
+
this.type = undefined;
|
|
25
|
+
this.tabIndex = undefined;
|
|
26
|
+
this.visible = undefined;
|
|
27
|
+
this.audio = undefined;
|
|
28
|
+
this.onTouch = undefined;
|
|
29
|
+
this.onCorrectTouch = undefined;
|
|
30
|
+
this.onInCorrectTouch = undefined;
|
|
31
|
+
this.onCorrectMatch = undefined;
|
|
32
|
+
this.onMatch = undefined;
|
|
33
|
+
this.onWrong = undefined;
|
|
34
|
+
this.onEntry = undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* This lifecycle hook is called after the component is rendered in the DOM.
|
|
38
|
+
* It initializes events for the column based on the provided type.
|
|
39
|
+
*/
|
|
40
|
+
componentDidLoad() {
|
|
41
|
+
utils.initEventsForElement(this.el, this.type);
|
|
42
|
+
}
|
|
43
|
+
render() {
|
|
44
|
+
// Inline styles applied to the column, mainly for positioning and background.
|
|
45
|
+
const style = {
|
|
46
|
+
height: this.height,
|
|
47
|
+
width: this.width,
|
|
48
|
+
backgroundColor: this.bgColor,
|
|
49
|
+
top: this.y,
|
|
50
|
+
left: this.x,
|
|
51
|
+
display: this.visible ? 'flex' : 'none',
|
|
52
|
+
zIndex: this.z,
|
|
53
|
+
};
|
|
54
|
+
return (index.h(index.Host, { key: '3cd3b141cf167e7c43132fc0f28fe049765e3e68', id: this.id, class: "col", type: this.type, tabindex: this.tabIndex, value: this.value, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, audio: this.audio, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onInCorrectTouch: this.onInCorrectTouch, onEntry: this.onEntry }, index.h("slot", { key: 'fecc9cdf6b7204461c07e89de0ebec35559f8daf' })));
|
|
55
|
+
}
|
|
56
|
+
get el() { return index.getElement(this); }
|
|
57
|
+
};
|
|
58
|
+
AppCol.style = AppColStyle0;
|
|
59
|
+
|
|
60
|
+
const appContainerCss = ".container{position:relative;height:100%;width:100%;background-color:var(--bgColor, #ffffff);display:flex;flex-direction:column;justify-content:center;align-items:center}";
|
|
61
|
+
const AppContainerStyle0 = appContainerCss;
|
|
62
|
+
|
|
63
|
+
const AppContainer = class {
|
|
64
|
+
constructor(hostRef) {
|
|
65
|
+
index.registerInstance(this, hostRef);
|
|
66
|
+
this.id = undefined;
|
|
67
|
+
this.objective = undefined;
|
|
68
|
+
this.value = undefined;
|
|
69
|
+
this.height = undefined;
|
|
70
|
+
this.width = undefined;
|
|
71
|
+
this.ariaLabel = undefined;
|
|
72
|
+
this.ariaHidden = undefined;
|
|
73
|
+
this.x = undefined;
|
|
74
|
+
this.y = undefined;
|
|
75
|
+
this.z = undefined;
|
|
76
|
+
this.bgColor = undefined;
|
|
77
|
+
this.type = undefined;
|
|
78
|
+
this.tabIndex = undefined;
|
|
79
|
+
this.visible = undefined;
|
|
80
|
+
this.audio = undefined;
|
|
81
|
+
this.onTouch = undefined;
|
|
82
|
+
this.onCorrectTouch = undefined;
|
|
83
|
+
this.onCorrectMatch = undefined;
|
|
84
|
+
this.onMatch = undefined;
|
|
85
|
+
this.onWrong = undefined;
|
|
86
|
+
this.onIncorrectTouch = undefined;
|
|
87
|
+
this.onEntry = undefined;
|
|
88
|
+
this.canplay = true;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Scales the container based on the window or screen size, maintaining the aspect ratio.
|
|
92
|
+
* The container scales according to the minimum dimension of the screen.
|
|
93
|
+
*
|
|
94
|
+
* @param container The container element to be scaled.
|
|
95
|
+
*/
|
|
96
|
+
scaleContainer(container) {
|
|
97
|
+
var _a;
|
|
98
|
+
const widths = [window.innerWidth];
|
|
99
|
+
if ((_a = window.screen) === null || _a === void 0 ? void 0 : _a.width) {
|
|
100
|
+
widths.push(window.screen.width);
|
|
101
|
+
}
|
|
102
|
+
const width = Math.min(...widths);
|
|
103
|
+
const height = document.documentElement.clientHeight;
|
|
104
|
+
const scaleX = width / 1600; // Scale based on a reference width of 1600px
|
|
105
|
+
const scaleY = height / 900; // Scale based on a reference height of 900px
|
|
106
|
+
const scale = Math.min(scaleX, scaleY);
|
|
107
|
+
// Center the container and apply scaling
|
|
108
|
+
container.style.transform = `translate(-50%, -50%) scale(${scale})`;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Lifecycle hook that runs after the component is loaded.
|
|
112
|
+
* - It scales the container.
|
|
113
|
+
* - It sets the background color of the body.
|
|
114
|
+
* - Adds event listeners for `resize` and `load` to rescale the container on window size changes.
|
|
115
|
+
*/
|
|
116
|
+
componentDidLoad() {
|
|
117
|
+
this.scaleContainer(this.el);
|
|
118
|
+
document.body.style.backgroundColor = this.bgColor;
|
|
119
|
+
// Re-scale the container on window resize or load events
|
|
120
|
+
window.addEventListener('resize', () => this.scaleContainer(this.el));
|
|
121
|
+
window.addEventListener('load', () => this.scaleContainer(this.el));
|
|
122
|
+
utils.initEventsForElement(this.el, this.type);
|
|
123
|
+
}
|
|
124
|
+
render() {
|
|
125
|
+
// Define the styles for the container element
|
|
126
|
+
const style = {
|
|
127
|
+
backgroundColor: this.bgColor,
|
|
128
|
+
width: '1600px', // Fixed width of the container
|
|
129
|
+
height: '900px', // Fixed height of the container
|
|
130
|
+
position: 'absolute',
|
|
131
|
+
top: '50%',
|
|
132
|
+
left: '50%',
|
|
133
|
+
transform: 'translate(-50%, -50%)', // Centering the container
|
|
134
|
+
};
|
|
135
|
+
console.log('🚀 ~ AppContainer ~ canplay:', this.canplay);
|
|
136
|
+
return (index.h(index.Host, { key: '3de4da721c5eb3dcdd9b29e01cfcc7968d40a761', id: "container", tabindex: 0, class: "container", objective: this.objective, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onIncorrectTouch: this.onIncorrectTouch, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onEntry: this.onEntry }, index.h("slot", { key: 'bd4abd0fd97b92a6f942554be26a28d3948f7a5d' })));
|
|
137
|
+
}
|
|
138
|
+
get el() { return index.getElement(this); }
|
|
139
|
+
};
|
|
140
|
+
AppContainer.style = AppContainerStyle0;
|
|
141
|
+
|
|
142
|
+
const indexCss = "@import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); body{overflow:hidden}";
|
|
143
|
+
const AppHomeStyle0 = indexCss;
|
|
144
|
+
|
|
145
|
+
const animationCss = "@keyframes rightToPlace{from{transform:translateX(2000px)}to{left:0}}@keyframes placeToLeft{from{}to{transform:translateX(-2000px)}}@keyframes shake{0%{transform:translateX(0);color:red;outline:4px solid red}10%{transform:translateX(-5px);color:red;outline:4px solid red}20%{transform:translateX(5px);color:red;outline:4px solid red}30%{transform:translateX(-5px);color:red;outline:4px solid red}40%{transform:translateX(5px);color:red;outline:4px solid red}50%{transform:translateX(-5px);color:red;outline:4px solid red}60%{transform:translateX(5px);color:red;outline:4px solid red}70%{transform:translateX(-5px);color:red;outline:4px solid red}80%{transform:translateX(5px);color:red;outline:4px solid red}90%{transform:translateX(-5px);color:red;outline:4px solid red}100%{transform:translateX(0);color:red;outline:4px solid red}}@keyframes fallAndBounce{0%{transform:translateY(-1000px)}25%{transform:translateY(0px)}50%{transform:translateY(-200px)}75%{transform:translateY(0)}90%{transform:translateY(-100px)}100%{transform:translateY(0)}}";
|
|
146
|
+
const AppHomeStyle1 = animationCss;
|
|
147
|
+
|
|
148
|
+
const appHomeCss = ".snackbar{visibility:visible;min-width:250px;background-color:#333;color:#fff;text-align:center;border-radius:2px;padding:16px;position:fixed;z-index:1;bottom:30px;left:50%;transform:translateX(-50%);font-size:17px}.dot-container{text-align:center;position:fixed;z-index:1;width:fit-content;top:1%;left:50%;transform:translate(-50%)}.dot{height:15px;width:15px;margin:0 4px;background-color:#bbb;border-radius:50%;display:inline-block;transition:background-color 0.3s;cursor:pointer}.dot.completed{background-color:grey}.dot.current{background-color:green}.dot:not(.completed):not(.current){background-color:#bbb}";
|
|
149
|
+
const AppHomeStyle2 = appHomeCss;
|
|
150
|
+
|
|
151
|
+
const AppHome = class {
|
|
152
|
+
constructor(hostRef) {
|
|
153
|
+
index.registerInstance(this, hostRef);
|
|
154
|
+
/**
|
|
155
|
+
* Event handler for transitioning to the next container in the sequence.
|
|
156
|
+
* If the last container is reached, it shows a completion message.
|
|
157
|
+
*/
|
|
158
|
+
this.nextContainer = (index) => {
|
|
159
|
+
if (index != undefined && index == this.currentContainerIndex)
|
|
160
|
+
return;
|
|
161
|
+
// Clear selected values from localStorage on container transition
|
|
162
|
+
localStorage.removeItem(utils.SelectedValuesKey);
|
|
163
|
+
localStorage.removeItem(utils.DragSelectedMapKey);
|
|
164
|
+
if (index != undefined && index < this.containers.length) {
|
|
165
|
+
// Move to the next container
|
|
166
|
+
this.currentContainerIndex = index;
|
|
167
|
+
window.dispatchEvent(new CustomEvent('activityChange', { detail: { index: this.currentContainerIndex } }));
|
|
168
|
+
}
|
|
169
|
+
else if (this.currentContainerIndex < this.containers.length - 1) {
|
|
170
|
+
// Move to the next container
|
|
171
|
+
this.currentContainerIndex++;
|
|
172
|
+
window.dispatchEvent(new CustomEvent('activityChange', { detail: { index: this.currentContainerIndex } }));
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
// Show the completion message if all containers have been viewed
|
|
176
|
+
this.showCompletionMessage = true;
|
|
177
|
+
const event = new CustomEvent('gameCompleted');
|
|
178
|
+
window.dispatchEvent(event);
|
|
179
|
+
// Hide the completion message after 3 seconds
|
|
180
|
+
setTimeout(() => {
|
|
181
|
+
this.showCompletionMessage = false;
|
|
182
|
+
}, 3000);
|
|
183
|
+
}
|
|
184
|
+
// Reset the containers array to trigger a re-render
|
|
185
|
+
this.containers = [...this.containers];
|
|
186
|
+
};
|
|
187
|
+
this.xmlData = undefined;
|
|
188
|
+
this.initialIndex = 0;
|
|
189
|
+
this.canplay = true;
|
|
190
|
+
this.currentContainerIndex = this.initialIndex;
|
|
191
|
+
this.showCompletionMessage = false;
|
|
192
|
+
this.containers = [];
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Lifecycle method that runs before the component is loaded. It sets up event listeners for transitioning
|
|
196
|
+
* between containers and parses the XML data into containers.
|
|
197
|
+
*/
|
|
198
|
+
componentWillLoad() {
|
|
199
|
+
// Listen for 'nextContainer' event to transition between containers
|
|
200
|
+
window.addEventListener('nextContainer', () => {
|
|
201
|
+
this.nextContainer();
|
|
202
|
+
});
|
|
203
|
+
window.addEventListener('changeContainer', (e) => {
|
|
204
|
+
this.nextContainer(e.detail.index);
|
|
205
|
+
});
|
|
206
|
+
// Parse the provided XML data
|
|
207
|
+
this.parseXMLData(this.xmlData);
|
|
208
|
+
// Remove stored values in localStorage when the page is about to be unloaded
|
|
209
|
+
window.addEventListener('beforeunload', () => {
|
|
210
|
+
localStorage.removeItem(utils.SelectedValuesKey);
|
|
211
|
+
localStorage.removeItem(utils.DragSelectedMapKey);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Lifecycle method that cleans up event listeners when the component is removed from the DOM.
|
|
216
|
+
*/
|
|
217
|
+
disconnectedCallback() {
|
|
218
|
+
window.removeEventListener('nextContainer', () => {
|
|
219
|
+
this.nextContainer();
|
|
220
|
+
});
|
|
221
|
+
window.removeEventListener('changeContainer', (e) => {
|
|
222
|
+
this.nextContainer(e.detail.index);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Parses the provided XML string into an XML DOM object and extracts the containers from it.
|
|
227
|
+
*
|
|
228
|
+
* @param xmlData - The XML data as a string.
|
|
229
|
+
*/
|
|
230
|
+
parseXMLData(xmlData) {
|
|
231
|
+
if (xmlData) {
|
|
232
|
+
const parser = new DOMParser();
|
|
233
|
+
const xmlDoc = parser.parseFromString(xmlData, 'text/xml');
|
|
234
|
+
const rootElement = xmlDoc.documentElement;
|
|
235
|
+
// Parse containers from the root XML element
|
|
236
|
+
this.parseContainers(rootElement);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Recursively parses an XML element and its children, converting them into corresponding Stencil components.
|
|
241
|
+
*
|
|
242
|
+
* @param element - The XML element to parse.
|
|
243
|
+
* @returns The corresponding Stencil component with parsed props and children.
|
|
244
|
+
*/
|
|
245
|
+
parseElement(element) {
|
|
246
|
+
const tagName = element.nodeName.toLowerCase();
|
|
247
|
+
const props = {};
|
|
248
|
+
// Extract attributes from the element and map them to props
|
|
249
|
+
Array.from(element.attributes).forEach(attr => {
|
|
250
|
+
props[attr.name] = attr.value;
|
|
251
|
+
});
|
|
252
|
+
// Recursively parse child elements
|
|
253
|
+
const children = Array.from(element.childNodes)
|
|
254
|
+
.map(child => {
|
|
255
|
+
if (child.nodeType === 1) {
|
|
256
|
+
return this.parseElement(child);
|
|
257
|
+
}
|
|
258
|
+
else if (child.nodeType === 3 && child.textContent.trim() !== '') {
|
|
259
|
+
return child.textContent;
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
})
|
|
263
|
+
.filter(Boolean);
|
|
264
|
+
// Map XML tags to Stencil components
|
|
265
|
+
const componentMapping = {
|
|
266
|
+
'app-container': (index.h("app-container", Object.assign({}, props, { canplay: this.canplay }), children)),
|
|
267
|
+
'app-col': index.h("app-col", Object.assign({}, props), children),
|
|
268
|
+
'app-trace': index.h("app-trace", Object.assign({}, props), children),
|
|
269
|
+
'app-image': index.h("app-image", Object.assign({}, props), children),
|
|
270
|
+
'app-row': index.h("app-row", Object.assign({}, props), children),
|
|
271
|
+
'app-text': index.h("app-text", Object.assign({}, props), children),
|
|
272
|
+
'app-pos': index.h("app-pos", Object.assign({}, props), children),
|
|
273
|
+
'app-shape': index.h("app-shape", Object.assign({}, props), children),
|
|
274
|
+
'app-wrap': index.h("app-wrap", Object.assign({}, props), children),
|
|
275
|
+
'app-random': index.h("app-random", Object.assign({}, props), children),
|
|
276
|
+
};
|
|
277
|
+
// If the tag is known, return the corresponding Stencil component, otherwise log a warning
|
|
278
|
+
if (componentMapping[tagName]) {
|
|
279
|
+
return componentMapping[tagName];
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
console.warn(`Unknown tag: ${tagName}`);
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Parses the `app-container` elements from the XML root element and stores them in the `containers` state.
|
|
288
|
+
*
|
|
289
|
+
* @param rootElement - The root element of the parsed XML document.
|
|
290
|
+
*/
|
|
291
|
+
parseContainers(rootElement) {
|
|
292
|
+
const containers = [];
|
|
293
|
+
const containerElements = rootElement.querySelectorAll('app-container');
|
|
294
|
+
// Parse each container and add it to the array
|
|
295
|
+
containerElements.forEach(container => {
|
|
296
|
+
const parsedElement = this.parseElement(container);
|
|
297
|
+
if (parsedElement) {
|
|
298
|
+
containers.push(parsedElement);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
this.containers = containers;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Renders navigation dots for each container, indicating the progress of the user.
|
|
305
|
+
* Clicking on a dot allows the user to jump to a specific container.
|
|
306
|
+
*/
|
|
307
|
+
renderDots() {
|
|
308
|
+
return (index.h("div", { id: "dot-indicator", class: "dot-container" }, this.containers.map((_, index$1) => (index.h("span", { class: `dot ${index$1 < this.currentContainerIndex ? 'completed' : index$1 === this.currentContainerIndex ? 'current' : ''}`, onClick: () => this.jumpToContainer(index$1) })))));
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Jumps to a specific container based on the index of the dot clicked.
|
|
312
|
+
*
|
|
313
|
+
* @param index - The index of the container to jump to.
|
|
314
|
+
*/
|
|
315
|
+
jumpToContainer(index) {
|
|
316
|
+
this.nextContainer(index);
|
|
317
|
+
// this.currentContainerIndex = index;
|
|
318
|
+
// this.containers = [...this.containers]; // Trigger re-render
|
|
319
|
+
}
|
|
320
|
+
render() {
|
|
321
|
+
if (!this.xmlData) {
|
|
322
|
+
// If no XML data is provided, prompt the user to provide it
|
|
323
|
+
return index.h("div", null, "Please provide XML data.");
|
|
324
|
+
}
|
|
325
|
+
return (index.h("div", null, index.h("div", { key: this.currentContainerIndex }, this.containers[this.currentContainerIndex]), this.renderDots(), this.showCompletionMessage && index.h("div", { class: "snackbar" }, "All containers have been displayed!")));
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
AppHome.style = AppHomeStyle0 + (AppHomeStyle1 + AppHomeStyle2);
|
|
329
|
+
|
|
330
|
+
const appImageCss = ".image{user-select:none;-webkit-user-drag:none;object-fit:contain;max-width:100%;max-height:100%;aspect-ratio:1 / 1;}";
|
|
331
|
+
const AppImageStyle0 = appImageCss;
|
|
332
|
+
|
|
333
|
+
const AppImage = class {
|
|
334
|
+
constructor(hostRef) {
|
|
335
|
+
index.registerInstance(this, hostRef);
|
|
336
|
+
this.value = undefined;
|
|
337
|
+
this.height = undefined;
|
|
338
|
+
this.width = undefined;
|
|
339
|
+
this.ariaLabel = undefined;
|
|
340
|
+
this.ariaHidden = undefined;
|
|
341
|
+
this.x = undefined;
|
|
342
|
+
this.y = undefined;
|
|
343
|
+
this.z = undefined;
|
|
344
|
+
this.bgColor = undefined;
|
|
345
|
+
this.type = undefined;
|
|
346
|
+
this.tabIndex = undefined;
|
|
347
|
+
this.visible = undefined;
|
|
348
|
+
this.audio = undefined;
|
|
349
|
+
this.onTouch = undefined;
|
|
350
|
+
this.onCorrectTouch = undefined;
|
|
351
|
+
this.onInCorrectTouch = undefined;
|
|
352
|
+
this.onCorrectMatch = undefined;
|
|
353
|
+
this.onMatch = undefined;
|
|
354
|
+
this.onWrong = undefined;
|
|
355
|
+
this.onEntry = undefined;
|
|
356
|
+
this.src = undefined;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Lifecycle method that runs after the component has been loaded into the DOM.
|
|
360
|
+
* It initializes custom events based on the `type` of the image component.
|
|
361
|
+
*/
|
|
362
|
+
componentDidLoad() {
|
|
363
|
+
utils.initEventsForElement(this.el, this.type);
|
|
364
|
+
}
|
|
365
|
+
render() {
|
|
366
|
+
// Inline styles for the image, including dimensions, positioning, and visibility
|
|
367
|
+
const style = {
|
|
368
|
+
height: this.height,
|
|
369
|
+
width: this.width,
|
|
370
|
+
backgroundColor: this.bgColor,
|
|
371
|
+
top: this.y,
|
|
372
|
+
left: this.x,
|
|
373
|
+
zIndex: this.z,
|
|
374
|
+
display: this.visible ? 'flex' : 'none',
|
|
375
|
+
alignItems: 'center', // Vertically center the image
|
|
376
|
+
justifyContent: 'center', // Horizontally center the image
|
|
377
|
+
};
|
|
378
|
+
return (index.h(index.Host, { key: 'bc0557fa586341933b698df56ecc5929b4185a58', type: this.type, tabindex: this.tabIndex, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, value: this.value, audio: this.audio, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onInCorrectTouch: this.onInCorrectTouch, onEntry: this.onEntry }, index.h("img", { key: 'fa5cc8aacf12b26625b4bc68a52f19144bc82f99', class: "image", src: this.src, alt: "", style: style })));
|
|
379
|
+
}
|
|
380
|
+
get el() { return index.getElement(this); }
|
|
381
|
+
};
|
|
382
|
+
AppImage.style = AppImageStyle0;
|
|
383
|
+
|
|
384
|
+
const appPosCss = ".pos{top:var(--y, 0);left:var(--x, 0);height:var(--height, 100%);width:var(--width, 100%);background-color:var(--bgColor, #eeeeee);display:flex;justify-content:space-around;flex-direction:column;position:fixed}.pos>*{position:absolute}";
|
|
385
|
+
const AppPosStyle0 = appPosCss;
|
|
386
|
+
|
|
387
|
+
const AppPos = class {
|
|
388
|
+
constructor(hostRef) {
|
|
389
|
+
index.registerInstance(this, hostRef);
|
|
390
|
+
this.id = undefined;
|
|
391
|
+
this.value = undefined;
|
|
392
|
+
this.height = undefined;
|
|
393
|
+
this.width = undefined;
|
|
394
|
+
this.ariaLabel = undefined;
|
|
395
|
+
this.ariaHidden = undefined;
|
|
396
|
+
this.x = undefined;
|
|
397
|
+
this.y = undefined;
|
|
398
|
+
this.z = undefined;
|
|
399
|
+
this.bgColor = undefined;
|
|
400
|
+
this.type = undefined;
|
|
401
|
+
this.tabIndex = undefined;
|
|
402
|
+
this.visible = undefined;
|
|
403
|
+
this.audio = undefined;
|
|
404
|
+
this.onTouch = undefined;
|
|
405
|
+
this.onCorrectTouch = undefined;
|
|
406
|
+
this.onInCorrectTouch = undefined;
|
|
407
|
+
this.onCorrectMatch = undefined;
|
|
408
|
+
this.onMatch = undefined;
|
|
409
|
+
this.onWrong = undefined;
|
|
410
|
+
this.onEntry = undefined;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Lifecycle hook that is called after the component has been rendered in the DOM.
|
|
414
|
+
* It initializes custom events based on the `type` of the component.
|
|
415
|
+
*/
|
|
416
|
+
componentDidLoad() {
|
|
417
|
+
utils.initEventsForElement(this.el, this.type);
|
|
418
|
+
}
|
|
419
|
+
render() {
|
|
420
|
+
// Inline styles to position and size the component
|
|
421
|
+
const style = {
|
|
422
|
+
height: this.height,
|
|
423
|
+
width: this.width,
|
|
424
|
+
backgroundColor: this.bgColor,
|
|
425
|
+
top: this.y,
|
|
426
|
+
left: this.x,
|
|
427
|
+
zIndex: this.z,
|
|
428
|
+
display: this.visible ? 'block' : 'none', // Toggle visibility
|
|
429
|
+
};
|
|
430
|
+
return (index.h(index.Host, { key: 'c63889200e5b87ccddf17f236898df959b643aee', id: this.id, class: "pos", type: this.type, tabindex: this.tabIndex, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, value: this.value, audio: this.audio, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onInCorrectTouch: this.onInCorrectTouch, onEntry: this.onEntry }, index.h("slot", { key: '09b1a03217ffc2c02836f4ac6f61f0887b8445cb' })));
|
|
431
|
+
}
|
|
432
|
+
get el() { return index.getElement(this); }
|
|
433
|
+
};
|
|
434
|
+
AppPos.style = AppPosStyle0;
|
|
435
|
+
|
|
436
|
+
const appRandomCss = ".random{display:flex;justify-content:space-between;align-items:center;position:absolute;}.random>*{position:absolute}";
|
|
437
|
+
const AppRandomStyle0 = appRandomCss;
|
|
438
|
+
|
|
439
|
+
const AppRandom = class {
|
|
440
|
+
constructor(hostRef) {
|
|
441
|
+
index.registerInstance(this, hostRef);
|
|
442
|
+
this.id = undefined;
|
|
443
|
+
this.value = undefined;
|
|
444
|
+
this.height = undefined;
|
|
445
|
+
this.width = undefined;
|
|
446
|
+
this.ariaLabel = undefined;
|
|
447
|
+
this.ariaHidden = undefined;
|
|
448
|
+
this.x = undefined;
|
|
449
|
+
this.y = undefined;
|
|
450
|
+
this.z = undefined;
|
|
451
|
+
this.bgColor = undefined;
|
|
452
|
+
this.type = undefined;
|
|
453
|
+
this.tabIndex = undefined;
|
|
454
|
+
this.visible = undefined;
|
|
455
|
+
this.audio = undefined;
|
|
456
|
+
this.onTouch = undefined;
|
|
457
|
+
this.onCorrectTouch = undefined;
|
|
458
|
+
this.onInCorrectTouch = undefined;
|
|
459
|
+
this.onCorrectMatch = undefined;
|
|
460
|
+
this.onMatch = undefined;
|
|
461
|
+
this.onWrong = undefined;
|
|
462
|
+
this.onEntry = undefined;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Lifecycle hook that runs after the component is rendered in the DOM.
|
|
466
|
+
* It randomly positions all child elements within the container using CSS `top` and `left` percentages.
|
|
467
|
+
*/
|
|
468
|
+
componentDidLoad() {
|
|
469
|
+
// Select all direct child elements of the component
|
|
470
|
+
const slotElements = this.el.querySelectorAll('.random > *');
|
|
471
|
+
// Iterate over each child and apply random positions
|
|
472
|
+
slotElements.forEach((child) => {
|
|
473
|
+
const randomTop = Math.random() * 100; // Random value between 0 and 100 for vertical position
|
|
474
|
+
const randomLeft = Math.random() * 100; // Random value between 0 and 100 for horizontal position
|
|
475
|
+
child.style.top = `${randomTop}%`;
|
|
476
|
+
child.style.left = `${randomLeft}%`;
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
render() {
|
|
480
|
+
// Inline styles for the container, including dimensions, positioning, and visibility
|
|
481
|
+
const style = {
|
|
482
|
+
height: this.height,
|
|
483
|
+
width: this.width,
|
|
484
|
+
top: this.y,
|
|
485
|
+
left: this.x,
|
|
486
|
+
display: this.visible ? 'block' : 'none', // Toggle visibility
|
|
487
|
+
zIndex: this.z,
|
|
488
|
+
backgroundColor: this.bgColor,
|
|
489
|
+
};
|
|
490
|
+
return (index.h(index.Host, { key: '66b661510df51498d8aaeaa3b8c43d7caf3ab6d1', class: "random", type: this.type, tabindex: this.tabIndex, value: this.value, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, audio: this.audio, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onInCorrectTouch: this.onInCorrectTouch, onEntry: this.onEntry }, index.h("slot", { key: '70b2819af97f7d1f85de0ea1161ae95014e427f4' })));
|
|
491
|
+
}
|
|
492
|
+
get el() { return index.getElement(this); }
|
|
493
|
+
};
|
|
494
|
+
AppRandom.style = AppRandomStyle0;
|
|
495
|
+
|
|
496
|
+
const AppRoot = class {
|
|
497
|
+
constructor(hostRef) {
|
|
498
|
+
index.registerInstance(this, hostRef);
|
|
499
|
+
this.xmlPath = undefined;
|
|
500
|
+
this.xmlData = undefined;
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Lifecycle method that runs before the component is loaded.
|
|
504
|
+
* It fetches the XML data from the specified path or URL and sets it to the component's state.
|
|
505
|
+
*/
|
|
506
|
+
async componentWillLoad() {
|
|
507
|
+
// Validate the xmlPath prop
|
|
508
|
+
if (!this.xmlPath) {
|
|
509
|
+
console.error('XML path is not provided.');
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
// Fetch the XML data
|
|
513
|
+
try {
|
|
514
|
+
const resolvedPath = this.xmlPath.startsWith('http')
|
|
515
|
+
? this.xmlPath // Use the provided URL if it's an HTTP/HTTPS link
|
|
516
|
+
: index.getAssetPath(this.xmlPath); // Otherwise, resolve it as an asset path
|
|
517
|
+
const response = await fetch(resolvedPath);
|
|
518
|
+
if (!response.ok) {
|
|
519
|
+
throw new Error(`Failed to fetch XML data: ${response.statusText}`);
|
|
520
|
+
}
|
|
521
|
+
const data = await response.text();
|
|
522
|
+
// Store the XML data in the component's state
|
|
523
|
+
this.xmlData = data;
|
|
524
|
+
}
|
|
525
|
+
catch (error) {
|
|
526
|
+
console.error('Error fetching XML data:', error);
|
|
527
|
+
this.xmlData = null;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
render() {
|
|
531
|
+
// Show a loading message until the XML data is fetched
|
|
532
|
+
if (this.xmlData === undefined) {
|
|
533
|
+
return index.h("div", null, "Loading...");
|
|
534
|
+
}
|
|
535
|
+
// Show an error message if the XML data could not be fetched
|
|
536
|
+
if (this.xmlData === null) {
|
|
537
|
+
return index.h("div", null, "Error loading XML data. Please check the path or URL.");
|
|
538
|
+
}
|
|
539
|
+
// Once the XML data is loaded, pass it to the `app-home` component
|
|
540
|
+
return index.h("app-home", { initialIndex: 0, canplay: true, xmlData: this.xmlData });
|
|
541
|
+
}
|
|
542
|
+
static get assetsDirs() { return ["assets"]; }
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
const appRowCss = ".row{display:flex;justify-content:space-between;align-items:center;}.row>*{}";
|
|
546
|
+
const AppRowStyle0 = appRowCss;
|
|
547
|
+
|
|
548
|
+
const AppRow = class {
|
|
549
|
+
constructor(hostRef) {
|
|
550
|
+
index.registerInstance(this, hostRef);
|
|
551
|
+
this.value = undefined;
|
|
552
|
+
this.height = undefined;
|
|
553
|
+
this.width = undefined;
|
|
554
|
+
this.ariaLabel = undefined;
|
|
555
|
+
this.ariaHidden = undefined;
|
|
556
|
+
this.x = undefined;
|
|
557
|
+
this.y = undefined;
|
|
558
|
+
this.z = undefined;
|
|
559
|
+
this.bgColor = undefined;
|
|
560
|
+
this.type = undefined;
|
|
561
|
+
this.tabIndex = undefined;
|
|
562
|
+
this.visible = undefined;
|
|
563
|
+
this.audio = undefined;
|
|
564
|
+
this.onTouch = undefined;
|
|
565
|
+
this.onCorrectTouch = undefined;
|
|
566
|
+
this.onInCorrectTouch = undefined;
|
|
567
|
+
this.onCorrectMatch = undefined;
|
|
568
|
+
this.onMatch = undefined;
|
|
569
|
+
this.onWrong = undefined;
|
|
570
|
+
this.onEntry = undefined;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Lifecycle hook that runs after the component is loaded into the DOM.
|
|
574
|
+
* It initializes custom events based on the `type` of the row component.
|
|
575
|
+
*/
|
|
576
|
+
componentDidLoad() {
|
|
577
|
+
utils.initEventsForElement(this.el, this.type);
|
|
578
|
+
}
|
|
579
|
+
render() {
|
|
580
|
+
// Inline styles to position and size the row component
|
|
581
|
+
const style = {
|
|
582
|
+
height: this.height,
|
|
583
|
+
width: this.width,
|
|
584
|
+
top: this.y,
|
|
585
|
+
left: this.x,
|
|
586
|
+
display: this.visible ? 'flex' : 'none', // Flexbox for row layout
|
|
587
|
+
zIndex: this.z,
|
|
588
|
+
backgroundColor: this.bgColor, // Apply background color if provided
|
|
589
|
+
};
|
|
590
|
+
return (index.h(index.Host, { key: 'fc3153fcef0ccc98d99afd2e93607e8c71c0a591', class: "row", type: this.type, tabindex: this.tabIndex, value: this.value, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, audio: this.audio, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onInCorrectTouch: this.onInCorrectTouch, onEntry: this.onEntry }, index.h("slot", { key: 'b28ce98adfc7ad7c9ac191eae523b974f9bb97f6' })));
|
|
591
|
+
}
|
|
592
|
+
get el() { return index.getElement(this); }
|
|
593
|
+
};
|
|
594
|
+
AppRow.style = AppRowStyle0;
|
|
595
|
+
|
|
596
|
+
const appShapeCss = ".shape{position:absolute;top:var(--y);left:var(--x);display:var(--display);z-index:var(--z)}.rectangle{border-radius:0}.circle{width:var(--width);height:var(--width);border-radius:50%;background-color:var(--bgColor)}.ellipse{width:var(--width);height:var(--height);border-radius:50%;background-color:var(--bgColor)}.triangle{width:var(--triangleWidth);height:var(--triangleHeight);background-color:var(--bgColor);clip-path:polygon(50% 0%, 100% 100%, 0% 100%)}.rightTriangle{width:var(--triangleWidth);height:var(--triangleHeight);background-color:var(--bgColor);clip-path:polygon(100% 0%, 100% 100%, 0% 100%)}.leftTriangle{width:var(--triangleWidth);height:var(--triangleHeight);background-color:var(--triangleBgColor);clip-path:polygon(0% 0%, 100% 100%, 0% 100%)}.parallelogram{width:var(--paralleWidth);height:var(--paralleHeight);transform:skew(20deg)}.star{width:var(--starWidth);height:var(--starHeight);background-color:var(--starBgColor);clip-path:polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)}.pentagon{width:var(--pentagonWidth);height:var(--pentagonHeight);background-color:var(--pentagonBgColor);clip-path:polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%)}.heptagon{width:var(--heptagonWidth);height:var(--heptagonHeight);background-color:var(--heptagonBgColor);clip-path:polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%)}.octagon{width:var(--octagonWidth);height:var(--octagonHeight);background-color:var(--octagonBgColor);clip-path:polygon(25% 0%, 75% 0%, 100% 25%, 100% 75%, 75% 100%, 25% 100%, 0% 75%, 0% 25%)}.rhombus{width:var(--rhombusWidth);height:var(--rhombusHeight);background-color:var(--rhombusBgColor);clip-path:polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)}.heart{height:var(--heartHeight);width:var(--heartWidth);border-image:radial-gradient(var(--heartBgColor) 69%, #0000 70%) 84.5%/50%;clip-path:polygon(-41% 0, 50% 91%, 141% 0)}";
|
|
597
|
+
const AppShapeStyle0 = appShapeCss;
|
|
598
|
+
|
|
599
|
+
const AppShape = class {
|
|
600
|
+
constructor(hostRef) {
|
|
601
|
+
index.registerInstance(this, hostRef);
|
|
602
|
+
this.id = undefined;
|
|
603
|
+
this.value = undefined;
|
|
604
|
+
this.height = undefined;
|
|
605
|
+
this.width = undefined;
|
|
606
|
+
this.ariaLabel = undefined;
|
|
607
|
+
this.ariaHidden = undefined;
|
|
608
|
+
this.x = undefined;
|
|
609
|
+
this.y = undefined;
|
|
610
|
+
this.z = undefined;
|
|
611
|
+
this.bgColor = undefined;
|
|
612
|
+
this.type = undefined;
|
|
613
|
+
this.tabIndex = undefined;
|
|
614
|
+
this.shapeType = undefined;
|
|
615
|
+
this.visible = undefined;
|
|
616
|
+
this.audio = undefined;
|
|
617
|
+
this.onTouch = undefined;
|
|
618
|
+
this.onCorrectTouch = undefined;
|
|
619
|
+
this.onInCorrectTouch = undefined;
|
|
620
|
+
this.onCorrectMatch = undefined;
|
|
621
|
+
this.onMatch = undefined;
|
|
622
|
+
this.onWrong = undefined;
|
|
623
|
+
this.onEntry = undefined;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Lifecycle hook that runs after the component is loaded into the DOM.
|
|
627
|
+
* It initializes custom events based on the `type` of the shape component.
|
|
628
|
+
*/
|
|
629
|
+
componentDidLoad() {
|
|
630
|
+
utils.initEventsForElement(this.el, this.type);
|
|
631
|
+
}
|
|
632
|
+
render() {
|
|
633
|
+
// Inline styles to position and size the shape component
|
|
634
|
+
const style = {
|
|
635
|
+
height: this.shapeType !== 'polygon' ? this.height : undefined, // Set height unless it's a polygon
|
|
636
|
+
width: this.shapeType !== 'polygon' ? this.width : undefined, // Set width unless it's a polygon
|
|
637
|
+
top: this.y,
|
|
638
|
+
left: this.x,
|
|
639
|
+
display: this.visible ? 'block' : 'none', // Toggle visibility
|
|
640
|
+
zIndex: this.z,
|
|
641
|
+
backgroundColor: this.shapeType !== 'polygon' ? this.bgColor : 'transparent', // Apply background only if not a polygon
|
|
642
|
+
};
|
|
643
|
+
return (index.h(index.Host, { key: '64db966fc0a1f601fd0002d0f71de3ec3aae241a', class: `shape ${this.shapeType}`, value: this.value, type: this.type, tabindex: this.tabIndex, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, audio: this.audio, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onInCorrectTouch: this.onInCorrectTouch, onEntry: this.onEntry }));
|
|
644
|
+
}
|
|
645
|
+
get el() { return index.getElement(this); }
|
|
646
|
+
};
|
|
647
|
+
AppShape.style = AppShapeStyle0;
|
|
648
|
+
|
|
649
|
+
const appTextCss = ".text{background-color:#fff;box-shadow:0 2px 4px rgba(0, 0, 0, 0.1);transition:background-color 0.3s ease;user-select:none;align-items:center;justify-content:center;text-align:center;border-radius:8px;color:#333;cursor:pointer}.text:hover{background-color:#f0f0f0}";
|
|
650
|
+
const AppTextStyle0 = appTextCss;
|
|
651
|
+
|
|
652
|
+
const AppText = class {
|
|
653
|
+
constructor(hostRef) {
|
|
654
|
+
index.registerInstance(this, hostRef);
|
|
655
|
+
this.id = undefined;
|
|
656
|
+
this.value = undefined;
|
|
657
|
+
this.string = undefined;
|
|
658
|
+
this.font = undefined;
|
|
659
|
+
this.fontSize = undefined;
|
|
660
|
+
this.fontColor = undefined;
|
|
661
|
+
this.highlightWhileSpeaking = undefined;
|
|
662
|
+
this.height = undefined;
|
|
663
|
+
this.width = undefined;
|
|
664
|
+
this.ariaLabel = undefined;
|
|
665
|
+
this.ariaHidden = undefined;
|
|
666
|
+
this.x = undefined;
|
|
667
|
+
this.y = undefined;
|
|
668
|
+
this.z = undefined;
|
|
669
|
+
this.bgColor = undefined;
|
|
670
|
+
this.type = undefined;
|
|
671
|
+
this.tabIndex = undefined;
|
|
672
|
+
this.visible = undefined;
|
|
673
|
+
this.audio = undefined;
|
|
674
|
+
this.onTouch = undefined;
|
|
675
|
+
this.onCorrectTouch = undefined;
|
|
676
|
+
this.onInCorrectTouch = undefined;
|
|
677
|
+
this.onCorrectMatch = undefined;
|
|
678
|
+
this.onMatch = undefined;
|
|
679
|
+
this.onWrong = undefined;
|
|
680
|
+
this.onEntry = undefined;
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Lifecycle hook that runs after the component is rendered in the DOM.
|
|
684
|
+
* It initializes custom events based on the `type` of the text component.
|
|
685
|
+
*/
|
|
686
|
+
componentDidLoad() {
|
|
687
|
+
utils.initEventsForElement(this.el, this.type);
|
|
688
|
+
}
|
|
689
|
+
render() {
|
|
690
|
+
// Inline styles to customize the appearance and positioning of the text component
|
|
691
|
+
const style = {
|
|
692
|
+
height: this.height,
|
|
693
|
+
width: this.width,
|
|
694
|
+
backgroundColor: this.bgColor,
|
|
695
|
+
top: this.y,
|
|
696
|
+
left: this.x,
|
|
697
|
+
zIndex: this.z,
|
|
698
|
+
fontSize: this.fontSize,
|
|
699
|
+
fontFamily: this.font,
|
|
700
|
+
color: this.fontColor,
|
|
701
|
+
display: this.visible ? 'flex' : 'none', // Show or hide based on visibility prop
|
|
702
|
+
};
|
|
703
|
+
return (index.h(index.Host, { key: '06c76433420706301a70a892a9081dfea480167e', class: "text", value: this.value, type: this.type, tabindex: this.tabIndex, audio: this.audio, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onInCorrectTouch: this.onInCorrectTouch, onEntry: this.onEntry, id: this.id, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden }, this.string));
|
|
704
|
+
}
|
|
705
|
+
get el() { return index.getElement(this); }
|
|
706
|
+
};
|
|
707
|
+
AppText.style = AppTextStyle0;
|
|
708
|
+
|
|
709
|
+
const appTraceCss = ":host{display:block;position:relative}#svgContainer{position:absolute;top:0;left:0;right:0;bottom:50px;display:flex;justify-content:center;align-items:center;overflow:hidden}svg{width:100%;height:100%;max-height:calc(100vh - 50px);touch-action:none}#draggableCircle{cursor:pointer;fill:red;transition:fill 0.2s, r 0.2s}.blindTracing{stroke:none !important}.blindFreeTrace{stroke:none !important}.hovered{cursor:grab;fill:darkred}#controls{position:fixed;bottom:0;left:0;right:0;display:flex;justify-content:space-between;padding:10px;background-color:#f0f0f0;border-top:1px solid #ccc}button{padding:10px;font-size:16px}@media (max-width: 600px){button{padding:8px;font-size:14px}}.trace-path-green{stroke:green !important}";
|
|
710
|
+
const AppTraceStyle0 = appTraceCss;
|
|
711
|
+
|
|
712
|
+
const AppTrace = class {
|
|
713
|
+
constructor(hostRef) {
|
|
714
|
+
index.registerInstance(this, hostRef);
|
|
715
|
+
this.id = undefined;
|
|
716
|
+
this.svgSource = undefined;
|
|
717
|
+
this.value = undefined;
|
|
718
|
+
this.height = undefined;
|
|
719
|
+
this.width = undefined;
|
|
720
|
+
this.x = undefined;
|
|
721
|
+
this.y = undefined;
|
|
722
|
+
this.z = undefined;
|
|
723
|
+
this.ariaLabel = undefined;
|
|
724
|
+
this.ariaHidden = undefined;
|
|
725
|
+
this.tabIndex = undefined;
|
|
726
|
+
this.mode = undefined;
|
|
727
|
+
this.fileIndex = -1;
|
|
728
|
+
this.isDragging = false;
|
|
729
|
+
this.activePointerId = null;
|
|
730
|
+
}
|
|
731
|
+
// MODES = ['noFlow', 'showFlow', 'freeTrace', 'blindTracing', 'blindFreeTrace'];
|
|
732
|
+
// Handle the pointermove event with optimizations
|
|
733
|
+
// Update the path trace as the red circle moves
|
|
734
|
+
async initializeSVG() {
|
|
735
|
+
let state = {
|
|
736
|
+
fileIndex: -1,
|
|
737
|
+
currentPathIndex: 0,
|
|
738
|
+
lastLength: 0,
|
|
739
|
+
totalPathLength: 0,
|
|
740
|
+
isDragging: false,
|
|
741
|
+
circle: null,
|
|
742
|
+
paths: [],
|
|
743
|
+
svg: null,
|
|
744
|
+
proximityThreshold: 100, // General proximity threshold
|
|
745
|
+
freeTraceProximityThreshold: 50, // Reduced proximity threshold for free trace
|
|
746
|
+
rafId: null,
|
|
747
|
+
pointerMoveEvent: null,
|
|
748
|
+
activePointerId: null,
|
|
749
|
+
mode: this.mode,
|
|
750
|
+
flowMarkers: [],
|
|
751
|
+
freeTraceLines: [],
|
|
752
|
+
};
|
|
753
|
+
await this.loadAnotherSVG(state, true); // Load the first SVG
|
|
754
|
+
}
|
|
755
|
+
componentWillLoad() {
|
|
756
|
+
this.initializeSVG();
|
|
757
|
+
}
|
|
758
|
+
// Fetch the SVG file asynchronously
|
|
759
|
+
async fetchSVG(url) {
|
|
760
|
+
const response = await fetch(url);
|
|
761
|
+
if (!response.ok) {
|
|
762
|
+
throw new Error(`Failed to fetch SVG (${url}): ${response.statusText}`);
|
|
763
|
+
}
|
|
764
|
+
return await response.text();
|
|
765
|
+
}
|
|
766
|
+
// to calculate the bounding box of all paths
|
|
767
|
+
calculateBoundingBox(paths, padding = 22) {
|
|
768
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
769
|
+
paths.forEach(path => {
|
|
770
|
+
const length = path.getTotalLength();
|
|
771
|
+
const numPoints = 100; // Number of points to sample along the path
|
|
772
|
+
for (let i = 0; i <= numPoints; i++) {
|
|
773
|
+
const point = path.getPointAtLength((i / numPoints) * length);
|
|
774
|
+
if (point.x < minX)
|
|
775
|
+
minX = point.x;
|
|
776
|
+
if (point.y < minY)
|
|
777
|
+
minY = point.y;
|
|
778
|
+
if (point.x > maxX)
|
|
779
|
+
maxX = point.x;
|
|
780
|
+
if (point.y > maxY)
|
|
781
|
+
maxY = point.y;
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
// Apply padding
|
|
785
|
+
minX -= padding;
|
|
786
|
+
minY -= padding;
|
|
787
|
+
maxX += padding;
|
|
788
|
+
maxY += padding;
|
|
789
|
+
return { minX, minY, maxX, maxY };
|
|
790
|
+
}
|
|
791
|
+
// Insert the fetched SVG into the container and adjust viewBox
|
|
792
|
+
insertSVG(svgText) {
|
|
793
|
+
const svgContainer = document.getElementById('svgContainer');
|
|
794
|
+
svgContainer.innerHTML = svgText;
|
|
795
|
+
// After inserting, get the SVG element
|
|
796
|
+
const svgElement = svgContainer.querySelector('svg');
|
|
797
|
+
// Remove the width and height attributes from the SVG element
|
|
798
|
+
svgElement.removeAttribute('width');
|
|
799
|
+
svgElement.removeAttribute('height');
|
|
800
|
+
// Get all paths
|
|
801
|
+
const paths = svgElement.querySelectorAll('path, line');
|
|
802
|
+
// Calculate bounding box
|
|
803
|
+
const bbox = this.calculateBoundingBox(Array.from(paths));
|
|
804
|
+
// Set the viewBox to the bounding box
|
|
805
|
+
const viewBoxWidth = bbox.maxX - bbox.minX;
|
|
806
|
+
const viewBoxHeight = bbox.maxY - bbox.minY;
|
|
807
|
+
svgElement.setAttribute('viewBox', `${bbox.minX} ${bbox.minY} ${viewBoxWidth} ${viewBoxHeight}`);
|
|
808
|
+
}
|
|
809
|
+
// Retrieve the SVG element from the container
|
|
810
|
+
getSVGElement() {
|
|
811
|
+
const svgContainer = document.getElementById('svgContainer');
|
|
812
|
+
return svgContainer.querySelector('svg');
|
|
813
|
+
}
|
|
814
|
+
// Get all path and line elements from the SVG
|
|
815
|
+
getPaths(svg) {
|
|
816
|
+
return Array.from(svg.querySelectorAll('path, line'));
|
|
817
|
+
}
|
|
818
|
+
// Create flow markers along the path to guide the user
|
|
819
|
+
createFlowMarkersForPath(path, markerCount = 10) {
|
|
820
|
+
var _a;
|
|
821
|
+
const totalLength = path.getTotalLength();
|
|
822
|
+
const interval = totalLength / (markerCount + 1); // Space markers evenly
|
|
823
|
+
const markers = [];
|
|
824
|
+
for (let i = 1; i <= markerCount; i++) {
|
|
825
|
+
const point = path.getPointAtLength(i * interval);
|
|
826
|
+
const nextPoint = path.getPointAtLength((i + 0.5) * interval); // Slightly ahead point for direction
|
|
827
|
+
// Create an arrow marker
|
|
828
|
+
const angle = Math.atan2(nextPoint.y - point.y, nextPoint.x - point.x);
|
|
829
|
+
const arrowMarker = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
|
|
830
|
+
arrowMarker.setAttribute('points', '-5,-5 0,0 -5,5');
|
|
831
|
+
arrowMarker.setAttribute('fill', 'blue');
|
|
832
|
+
arrowMarker.setAttribute('transform', `translate(${point.x},${point.y}) rotate(${(angle * 180) / Math.PI})`);
|
|
833
|
+
arrowMarker.setAttribute('class', 'flow-indicator');
|
|
834
|
+
markers.push(arrowMarker);
|
|
835
|
+
(_a = path.parentNode) === null || _a === void 0 ? void 0 : _a.appendChild(arrowMarker); // Append to the same SVG container
|
|
836
|
+
}
|
|
837
|
+
return markers;
|
|
838
|
+
}
|
|
839
|
+
// Show or hide flow indicators based on mode
|
|
840
|
+
updateFlowIndicators(state) {
|
|
841
|
+
const indicators = state.svg.querySelectorAll('.flow-indicator');
|
|
842
|
+
indicators.forEach(indicator => {
|
|
843
|
+
if (state.mode === utils.TraceMode.NoFlow) {
|
|
844
|
+
indicator.style.display = 'none';
|
|
845
|
+
}
|
|
846
|
+
else if (state.mode === utils.TraceMode.ShowFlow) {
|
|
847
|
+
indicator.style.display = 'block';
|
|
848
|
+
}
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
// Create a new path element for the drawing effect
|
|
852
|
+
setupDrawingPath(state) {
|
|
853
|
+
state.paths.forEach((path, index) => {
|
|
854
|
+
const pathLength = path.getTotalLength();
|
|
855
|
+
// Create green path for tracing effect
|
|
856
|
+
const greenPath = path.cloneNode();
|
|
857
|
+
greenPath.setAttribute('stroke', 'green');
|
|
858
|
+
greenPath.setAttribute('stroke-width', '13');
|
|
859
|
+
greenPath.setAttribute('stroke-dasharray', pathLength.toString());
|
|
860
|
+
greenPath.setAttribute('stroke-dashoffset', pathLength.toString()); // Hidden initially
|
|
861
|
+
path.parentNode.appendChild(greenPath, path);
|
|
862
|
+
path.setAttribute('class', 'trace-path'); // Add class for easier reference
|
|
863
|
+
greenPath.setAttribute('class', 'trace-path-green'); // Add class for easier reference
|
|
864
|
+
path.greenPath = greenPath;
|
|
865
|
+
path.classList.add(state.mode);
|
|
866
|
+
// Conditionally hide or show the black path based on blind tracing mode
|
|
867
|
+
if (state.mode === utils.TraceMode.BlindTracing || state.mode === utils.TraceMode.BlindFreeTrace) {
|
|
868
|
+
// In blind tracing or blind free trace mode, hide the black path
|
|
869
|
+
path.setAttribute('stroke', 'none');
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
872
|
+
// In other modes, show the black path
|
|
873
|
+
path.setAttribute('stroke', '#000');
|
|
874
|
+
path.setAttribute('stroke-width', '10');
|
|
875
|
+
path.setAttribute('fill', 'none');
|
|
876
|
+
path.setAttribute('stroke-dasharray', pathLength.toString());
|
|
877
|
+
path.setAttribute('stroke-dashoffset', '0'); // Fully visible initially
|
|
878
|
+
}
|
|
879
|
+
// Only create flow markers for the current path in normal modes
|
|
880
|
+
if (index === state.currentPathIndex && state.mode === utils.TraceMode.ShowFlow) {
|
|
881
|
+
state.flowMarkers = this.createFlowMarkersForPath(path);
|
|
882
|
+
}
|
|
883
|
+
});
|
|
884
|
+
state.totalPathLength = state.paths[state.currentPathIndex].getTotalLength();
|
|
885
|
+
}
|
|
886
|
+
// Set up the draggable circle at the start of the first path
|
|
887
|
+
setupDraggableCircle(state) {
|
|
888
|
+
var _a;
|
|
889
|
+
const firstPathStart = state.paths[0].getPointAtLength(0);
|
|
890
|
+
const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
|
|
891
|
+
circle.setAttribute('id', 'draggableCircle');
|
|
892
|
+
circle.setAttribute('cx', firstPathStart.x.toString());
|
|
893
|
+
circle.setAttribute('cy', firstPathStart.y.toString());
|
|
894
|
+
circle.setAttribute('r', '20'); // Radius of the draggable circle
|
|
895
|
+
circle.setAttribute('fill', 'red');
|
|
896
|
+
(_a = state.svg) === null || _a === void 0 ? void 0 : _a.appendChild(circle);
|
|
897
|
+
state.circle = circle;
|
|
898
|
+
}
|
|
899
|
+
// Add necessary event listeners using Pointer Events
|
|
900
|
+
addEventListeners(state) {
|
|
901
|
+
var _a, _b, _c, _d;
|
|
902
|
+
// Ensure the circle exists before adding events
|
|
903
|
+
if (!state.circle || !state.paths || state.paths.length === 0)
|
|
904
|
+
return;
|
|
905
|
+
// Handle pointerdown on the circle to start dragging
|
|
906
|
+
state.circle.addEventListener('pointerdown', (evt) => {
|
|
907
|
+
evt.preventDefault(); // Prevent default actions like text selection
|
|
908
|
+
const pointerPos = this.getPointerPosition(evt, state.svg);
|
|
909
|
+
const circlePos = {
|
|
910
|
+
x: parseFloat(state.circle.getAttribute('cx')),
|
|
911
|
+
y: parseFloat(state.circle.getAttribute('cy')),
|
|
912
|
+
};
|
|
913
|
+
const distance = this.getDistanceSquared(pointerPos, circlePos);
|
|
914
|
+
if (distance <= state.proximityThreshold * state.proximityThreshold) {
|
|
915
|
+
state.isDragging = true;
|
|
916
|
+
state.activePointerId = evt.pointerId;
|
|
917
|
+
// Capture the pointer to continue receiving events even if it leaves the element
|
|
918
|
+
state.circle.setPointerCapture(evt.pointerId);
|
|
919
|
+
}
|
|
920
|
+
});
|
|
921
|
+
// Handle pointermove on the SVG to update the circle position
|
|
922
|
+
(_a = state.svg) === null || _a === void 0 ? void 0 : _a.addEventListener('pointermove', (evt) => {
|
|
923
|
+
if (!state.isDragging || evt.pointerId !== state.activePointerId)
|
|
924
|
+
return;
|
|
925
|
+
state.pointerMoveEvent = evt;
|
|
926
|
+
if (!state.rafId) {
|
|
927
|
+
state.rafId = requestAnimationFrame(() => {
|
|
928
|
+
this.handlePointerMove(state);
|
|
929
|
+
state.rafId = null;
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
// Handle pointerup and pointercancel on the SVG to stop dragging
|
|
934
|
+
(_b = state.svg) === null || _b === void 0 ? void 0 : _b.addEventListener('pointerup', (evt) => {
|
|
935
|
+
if (evt.pointerId === state.activePointerId) {
|
|
936
|
+
state.isDragging = false;
|
|
937
|
+
state.activePointerId = null;
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
(_c = state.svg) === null || _c === void 0 ? void 0 : _c.addEventListener('pointercancel', (evt) => {
|
|
941
|
+
if (evt.pointerId === state.activePointerId) {
|
|
942
|
+
state.isDragging = false;
|
|
943
|
+
state.activePointerId = null;
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
// Optional: Prevent context menu on long press
|
|
947
|
+
(_d = state.svg) === null || _d === void 0 ? void 0 : _d.addEventListener('contextmenu', (evt) => {
|
|
948
|
+
evt.preventDefault();
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
// Modified handlePointerMove function
|
|
952
|
+
handlePointerMove(state) {
|
|
953
|
+
var _a, _b, _c, _d;
|
|
954
|
+
if (!state.isDragging)
|
|
955
|
+
return;
|
|
956
|
+
if (!state.circle || !state.paths || state.paths.length === 0)
|
|
957
|
+
return;
|
|
958
|
+
const evt = state.pointerMoveEvent;
|
|
959
|
+
const pointerPos = this.getPointerPosition(evt, state.svg);
|
|
960
|
+
const circlePos = {
|
|
961
|
+
x: parseFloat(state.circle.getAttribute('cx')),
|
|
962
|
+
y: parseFloat(state.circle.getAttribute('cy')),
|
|
963
|
+
};
|
|
964
|
+
const currentPath = state.paths[state.currentPathIndex];
|
|
965
|
+
if (!currentPath) {
|
|
966
|
+
console.error('No valid path found at the current index');
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
// Use a reduced proximity threshold for free trace mode
|
|
970
|
+
let proximitySquared;
|
|
971
|
+
if (state.mode === utils.TraceMode.FreeTrace || state.mode === utils.TraceMode.BlindFreeTrace) {
|
|
972
|
+
proximitySquared = state.freeTraceProximityThreshold * state.freeTraceProximityThreshold;
|
|
973
|
+
}
|
|
974
|
+
else {
|
|
975
|
+
proximitySquared = state.proximityThreshold * state.proximityThreshold;
|
|
976
|
+
}
|
|
977
|
+
// Calculate the distance between the pointer and the draggable circle
|
|
978
|
+
const distanceSquared = this.getDistanceSquared(pointerPos, circlePos);
|
|
979
|
+
// If the pointer is outside the proximity threshold, do not proceed with drawing or moving
|
|
980
|
+
if (distanceSquared > proximitySquared) {
|
|
981
|
+
return; // Skip any further actions
|
|
982
|
+
}
|
|
983
|
+
const closestPoint = this.getClosestPointOnPath(currentPath, pointerPos);
|
|
984
|
+
// Ensure drawing happens only within proximity threshold
|
|
985
|
+
const distanceToPathSquared = this.getDistanceSquared(pointerPos, closestPoint);
|
|
986
|
+
if (distanceToPathSquared > proximitySquared) {
|
|
987
|
+
return; // Skip drawing if too far from the path
|
|
988
|
+
}
|
|
989
|
+
// For free trace mode and blind free trace mode, allow free drawing only if within the reduced proximity threshold
|
|
990
|
+
if (state.mode === utils.TraceMode.FreeTrace || state.mode === utils.TraceMode.BlindFreeTrace) {
|
|
991
|
+
// Initialize the currentFreePath array if it's not created
|
|
992
|
+
if (!state.currentFreePath) {
|
|
993
|
+
state.currentFreePath = [];
|
|
994
|
+
}
|
|
995
|
+
// Create a new path element if it's the first trace for the current path index
|
|
996
|
+
if (!state.currentFreePath[state.currentPathIndex]) {
|
|
997
|
+
const newPath = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
998
|
+
newPath.setAttribute('stroke', 'green');
|
|
999
|
+
newPath.setAttribute('stroke-width', '8');
|
|
1000
|
+
newPath.setAttribute('fill', 'none');
|
|
1001
|
+
// Start the new path at the current pointer position
|
|
1002
|
+
newPath.setAttribute('d', `M${pointerPos.x},${pointerPos.y}`);
|
|
1003
|
+
(_a = state.svg) === null || _a === void 0 ? void 0 : _a.appendChild(newPath);
|
|
1004
|
+
state.currentFreePath[state.currentPathIndex] = newPath;
|
|
1005
|
+
// Reset lastPointerPos for the new path
|
|
1006
|
+
state.lastPointerPos = pointerPos;
|
|
1007
|
+
}
|
|
1008
|
+
// Get the previous position to draw a smooth curve
|
|
1009
|
+
const previousPos = state.lastPointerPos || pointerPos;
|
|
1010
|
+
// Create a quadratic curve from the previous point to the current point
|
|
1011
|
+
const newPathData = state.currentFreePath[state.currentPathIndex].getAttribute('d');
|
|
1012
|
+
const midPointX = (previousPos.x + pointerPos.x) / 2;
|
|
1013
|
+
const midPointY = (previousPos.y + pointerPos.y) / 2;
|
|
1014
|
+
const updatedPathData = `${newPathData} Q ${previousPos.x},${previousPos.y} ${midPointX},${midPointY}`;
|
|
1015
|
+
// Update the path's 'd' attribute with the new curve
|
|
1016
|
+
state.currentFreePath[state.currentPathIndex].setAttribute('d', updatedPathData);
|
|
1017
|
+
// Move the draggable circle with the freehand trace
|
|
1018
|
+
state.circle.setAttribute('cx', pointerPos.x.toString());
|
|
1019
|
+
state.circle.setAttribute('cy', pointerPos.y.toString());
|
|
1020
|
+
// Make sure the red dot (circle) is always on top
|
|
1021
|
+
(_b = state.svg) === null || _b === void 0 ? void 0 : _b.appendChild(state.circle); // This moves the circle to the last child, making it the topmost
|
|
1022
|
+
// Update the last pointer position
|
|
1023
|
+
state.lastPointerPos = pointerPos;
|
|
1024
|
+
const currentPathLength = currentPath.getTotalLength();
|
|
1025
|
+
const distanceToEnd = currentPathLength - closestPoint.length;
|
|
1026
|
+
// If close to the end of the path, move to the next path
|
|
1027
|
+
if (distanceToEnd < 5) {
|
|
1028
|
+
this.moveToNextPath(state);
|
|
1029
|
+
state.currentFreePath[state.currentPathIndex] = null; // Reset free path for next path
|
|
1030
|
+
}
|
|
1031
|
+
return; // Exit early since we're in free trace or blind free trace mode
|
|
1032
|
+
}
|
|
1033
|
+
// In normal modes, allow movement and drawing only within the general proximity threshold
|
|
1034
|
+
if (state.isDragging && closestPoint.length >= state.lastLength) {
|
|
1035
|
+
state.lastLength = closestPoint.length;
|
|
1036
|
+
state.circle.setAttribute('cx', closestPoint.x.toString());
|
|
1037
|
+
state.circle.setAttribute('cy', closestPoint.y.toString());
|
|
1038
|
+
// Make sure the red dot (circle) is always on top
|
|
1039
|
+
(_c = state.svg) === null || _c === void 0 ? void 0 : _c.appendChild(state.circle); // This moves the circle to the last child, making it the topmost
|
|
1040
|
+
(_d = currentPath.greenPath) === null || _d === void 0 ? void 0 : _d.setAttribute('stroke-dashoffset', (state.totalPathLength - state.lastLength).toString());
|
|
1041
|
+
}
|
|
1042
|
+
// Check if the current path is completed
|
|
1043
|
+
if (state.totalPathLength - 1 - state.lastLength < 5 && state.currentPathIndex < state.paths.length - 1) {
|
|
1044
|
+
this.moveToNextPath(state);
|
|
1045
|
+
}
|
|
1046
|
+
else if (state.totalPathLength - 1 - state.lastLength < 5 && state.currentPathIndex === state.paths.length - 1) {
|
|
1047
|
+
// this.loadAnotherSVG(state, true);
|
|
1048
|
+
utils.triggerNextContainer();
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
// Get the pointer position relative to the SVG
|
|
1052
|
+
getPointerPosition(evt, svg) {
|
|
1053
|
+
var _a;
|
|
1054
|
+
const svgPoint = svg.createSVGPoint();
|
|
1055
|
+
svgPoint.x = evt.clientX;
|
|
1056
|
+
svgPoint.y = evt.clientY;
|
|
1057
|
+
const ctm = (_a = svg.getScreenCTM()) === null || _a === void 0 ? void 0 : _a.inverse();
|
|
1058
|
+
return ctm ? svgPoint.matrixTransform(ctm) : { x: evt.clientX, y: evt.clientY };
|
|
1059
|
+
}
|
|
1060
|
+
// Calculate the squared Euclidean distance between two points
|
|
1061
|
+
getDistanceSquared(p1, p2) {
|
|
1062
|
+
const dx = p1.x - p2.x;
|
|
1063
|
+
const dy = p1.y - p2.y;
|
|
1064
|
+
return dx * dx + dy * dy;
|
|
1065
|
+
}
|
|
1066
|
+
// Find the closest point on the given path to the specified point using two-pass sampling
|
|
1067
|
+
getClosestPointOnPath(pathNode, point) {
|
|
1068
|
+
const pathLength = pathNode.getTotalLength();
|
|
1069
|
+
let closestPoint = { x: 0, y: 0, length: 0 };
|
|
1070
|
+
let minDistanceSquared = Infinity;
|
|
1071
|
+
// First pass: coarse sampling
|
|
1072
|
+
const coarseStep = 20; // Increased step for better performance
|
|
1073
|
+
let coarseClosestPoint = { x: 0, y: 0, length: 0 };
|
|
1074
|
+
let coarseMinDistanceSquared = Infinity;
|
|
1075
|
+
for (let i = 0; i <= pathLength; i += coarseStep) {
|
|
1076
|
+
const pointOnPath = pathNode.getPointAtLength(i);
|
|
1077
|
+
const distanceSquared = this.getDistanceSquared(point, pointOnPath);
|
|
1078
|
+
if (distanceSquared < coarseMinDistanceSquared) {
|
|
1079
|
+
coarseMinDistanceSquared = distanceSquared;
|
|
1080
|
+
coarseClosestPoint = {
|
|
1081
|
+
x: pointOnPath.x,
|
|
1082
|
+
y: pointOnPath.y,
|
|
1083
|
+
length: i,
|
|
1084
|
+
};
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
// Second pass: fine sampling around coarseClosestPoint
|
|
1088
|
+
const fineStep = 2; // Increased step to reduce computations
|
|
1089
|
+
const searchStart = Math.max(coarseClosestPoint.length - coarseStep, 0);
|
|
1090
|
+
const searchEnd = Math.min(coarseClosestPoint.length + coarseStep, pathLength);
|
|
1091
|
+
for (let i = searchStart; i <= searchEnd; i += fineStep) {
|
|
1092
|
+
const pointOnPath = pathNode.getPointAtLength(i);
|
|
1093
|
+
const distanceSquared = this.getDistanceSquared(point, pointOnPath);
|
|
1094
|
+
if (distanceSquared < minDistanceSquared) {
|
|
1095
|
+
minDistanceSquared = distanceSquared;
|
|
1096
|
+
closestPoint = { x: pointOnPath.x, y: pointOnPath.y, length: i };
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return closestPoint;
|
|
1100
|
+
}
|
|
1101
|
+
// Load the next or previous SVG based on the isNext flag
|
|
1102
|
+
async loadAnotherSVG(state, isNext) {
|
|
1103
|
+
state.isDragging = false;
|
|
1104
|
+
// Update fileIndex based on whether isNext is true or false
|
|
1105
|
+
// if (isNext) {
|
|
1106
|
+
// state.fileIndex++;
|
|
1107
|
+
// if (state.fileIndex >= this.svgFiles.length) {
|
|
1108
|
+
// state.fileIndex = this.svgFiles.length - 1; // Stay at the last file
|
|
1109
|
+
// return;
|
|
1110
|
+
// }
|
|
1111
|
+
// } else {
|
|
1112
|
+
// state.fileIndex--;
|
|
1113
|
+
// if (state.fileIndex < 0) {
|
|
1114
|
+
// state.fileIndex = 0; // Stay at the first file
|
|
1115
|
+
// return;
|
|
1116
|
+
// }
|
|
1117
|
+
// }
|
|
1118
|
+
try {
|
|
1119
|
+
if (state.svg) {
|
|
1120
|
+
this.cleanupPreviousSVG(state);
|
|
1121
|
+
}
|
|
1122
|
+
// const svgText = await this.fetchSVG(this.svgSource ?? this.svgFiles[state.fileIndex]);
|
|
1123
|
+
const svgText = await this.fetchSVG(this.svgSource);
|
|
1124
|
+
this.insertSVG(svgText);
|
|
1125
|
+
state.svg = this.getSVGElement();
|
|
1126
|
+
state.paths = this.getPaths(state.svg);
|
|
1127
|
+
this.setupDrawingPath(state);
|
|
1128
|
+
this.setupDraggableCircle(state);
|
|
1129
|
+
this.addEventListeners(state);
|
|
1130
|
+
}
|
|
1131
|
+
catch (error) {
|
|
1132
|
+
console.error(`Error loading SVG (${this.svgSource}):`, error);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
// Cleanup previous SVG's elements and state
|
|
1136
|
+
cleanupPreviousSVG(state) {
|
|
1137
|
+
var _a, _b;
|
|
1138
|
+
if (state.circle) {
|
|
1139
|
+
(_a = state.svg) === null || _a === void 0 ? void 0 : _a.removeChild(state.circle);
|
|
1140
|
+
state.circle = null;
|
|
1141
|
+
}
|
|
1142
|
+
const indicators = (_b = state.svg) === null || _b === void 0 ? void 0 : _b.querySelectorAll('.flow-indicator');
|
|
1143
|
+
indicators.forEach(indicator => {
|
|
1144
|
+
indicator.remove(); // Remove all previous flow indicators
|
|
1145
|
+
});
|
|
1146
|
+
state.currentPathIndex = 0;
|
|
1147
|
+
state.lastLength = 0;
|
|
1148
|
+
state.totalPathLength = state.paths[0].getTotalLength();
|
|
1149
|
+
}
|
|
1150
|
+
// Move to the next path in the SVG
|
|
1151
|
+
moveToNextPath(state) {
|
|
1152
|
+
var _a, _b;
|
|
1153
|
+
state.isDragging = false;
|
|
1154
|
+
state.currentPathIndex++;
|
|
1155
|
+
state.lastLength = 0;
|
|
1156
|
+
if (state.currentPathIndex >= state.paths.length) {
|
|
1157
|
+
// this.loadAnotherSVG(state, true);
|
|
1158
|
+
utils.triggerNextContainer();
|
|
1159
|
+
return;
|
|
1160
|
+
}
|
|
1161
|
+
const nextPath = state.paths[state.currentPathIndex];
|
|
1162
|
+
if (!nextPath) {
|
|
1163
|
+
console.error('No valid path found at the next index');
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
state.totalPathLength = nextPath.getTotalLength();
|
|
1167
|
+
const startPoint = nextPath.getPointAtLength(0);
|
|
1168
|
+
(_a = state.circle) === null || _a === void 0 ? void 0 : _a.setAttribute('cx', startPoint.x.toString());
|
|
1169
|
+
(_b = state.circle) === null || _b === void 0 ? void 0 : _b.setAttribute('cy', startPoint.y.toString());
|
|
1170
|
+
if (state.mode === utils.TraceMode.ShowFlow) {
|
|
1171
|
+
state.flowMarkers = this.createFlowMarkersForPath(nextPath);
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
render() {
|
|
1175
|
+
const style = {
|
|
1176
|
+
height: this.height,
|
|
1177
|
+
width: this.width,
|
|
1178
|
+
top: this.y,
|
|
1179
|
+
left: this.x,
|
|
1180
|
+
zIndex: this.z,
|
|
1181
|
+
position: 'absolute',
|
|
1182
|
+
};
|
|
1183
|
+
// List of SVG file names to process sequentially
|
|
1184
|
+
// const svgFiles = ['A_test.svg', 'B_test.svg', 'C_test.svg', 'D_test.svg', 'अ_test.svg', 'ट_test.svg', 'क_test.svg', 'ख_test.svg', 'ग_test.svg']; // Add more SVG file names as needed
|
|
1185
|
+
return (index.h(index.Host, { key: 'c957926b2f3e281966de8d1dca6580931af54019', class: "trace", id: this.id, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, tabindex: this.tabIndex }, index.h("div", { key: 'f841bf92fec27ed26594c5ccca937fa20210451f', id: "svgContainer" })));
|
|
1186
|
+
}
|
|
1187
|
+
static get assetsDirs() { return ["svg"]; }
|
|
1188
|
+
};
|
|
1189
|
+
AppTrace.style = AppTraceStyle0;
|
|
1190
|
+
|
|
1191
|
+
const appWrapCss = ".wrap{display:grid;grid-gap:10px;grid-template-columns:repeat(auto-fill, minmax(186px, auto))}.wrap>*{padding:10px;background-color:var(--child-bg-color, #f0f0f0);box-sizing:border-box}";
|
|
1192
|
+
const AppWrapStyle0 = appWrapCss;
|
|
1193
|
+
|
|
1194
|
+
const AppWrap = class {
|
|
1195
|
+
constructor(hostRef) {
|
|
1196
|
+
index.registerInstance(this, hostRef);
|
|
1197
|
+
this.id = undefined;
|
|
1198
|
+
this.value = undefined;
|
|
1199
|
+
this.height = undefined;
|
|
1200
|
+
this.width = undefined;
|
|
1201
|
+
this.ariaLabel = undefined;
|
|
1202
|
+
this.ariaHidden = undefined;
|
|
1203
|
+
this.x = undefined;
|
|
1204
|
+
this.y = undefined;
|
|
1205
|
+
this.z = undefined;
|
|
1206
|
+
this.bgColor = undefined;
|
|
1207
|
+
this.type = undefined;
|
|
1208
|
+
this.tabIndex = undefined;
|
|
1209
|
+
this.visible = undefined;
|
|
1210
|
+
this.audio = undefined;
|
|
1211
|
+
this.onTouch = undefined;
|
|
1212
|
+
this.onCorrectTouch = undefined;
|
|
1213
|
+
this.onInCorrectTouch = undefined;
|
|
1214
|
+
this.onCorrectMatch = undefined;
|
|
1215
|
+
this.onMatch = undefined;
|
|
1216
|
+
this.onWrong = undefined;
|
|
1217
|
+
this.onEntry = undefined;
|
|
1218
|
+
}
|
|
1219
|
+
/**
|
|
1220
|
+
* Lifecycle hook that runs after the component is rendered in the DOM.
|
|
1221
|
+
* It initializes custom events based on the `type` of the wrap container.
|
|
1222
|
+
*/
|
|
1223
|
+
componentDidLoad() {
|
|
1224
|
+
utils.initEventsForElement(this.el, this.type);
|
|
1225
|
+
}
|
|
1226
|
+
render() {
|
|
1227
|
+
// Inline styles to position and size the wrap container, with grid layout applied
|
|
1228
|
+
const style = {
|
|
1229
|
+
height: this.height,
|
|
1230
|
+
width: this.width,
|
|
1231
|
+
top: this.y,
|
|
1232
|
+
left: this.x,
|
|
1233
|
+
display: this.visible ? 'grid' : 'none', // Use grid layout
|
|
1234
|
+
zIndex: this.z,
|
|
1235
|
+
backgroundColor: this.bgColor,
|
|
1236
|
+
};
|
|
1237
|
+
return (index.h(index.Host, { key: '7e955c4ff7d20f7138088114ccf344d0fda171d8', class: "wrap", value: this.value, type: this.type, tabindex: this.tabIndex, style: style, "aria-label": this.ariaLabel, "aria-hidden": this.ariaHidden, audio: this.audio, onTouch: this.onTouch, onMatch: this.onMatch, onWrong: this.onWrong, onCorrectMatch: this.onCorrectMatch, onCorrectTouch: this.onCorrectTouch, onInCorrectTouch: this.onInCorrectTouch, onEntry: this.onEntry }, index.h("slot", { key: '1ee6b59cfe7cbb8b3bc1c830c51e38e0711e6e62' })));
|
|
1238
|
+
}
|
|
1239
|
+
get el() { return index.getElement(this); }
|
|
1240
|
+
};
|
|
1241
|
+
AppWrap.style = AppWrapStyle0;
|
|
1242
|
+
|
|
1243
|
+
exports.app_col = AppCol;
|
|
1244
|
+
exports.app_container = AppContainer;
|
|
1245
|
+
exports.app_home = AppHome;
|
|
1246
|
+
exports.app_image = AppImage;
|
|
1247
|
+
exports.app_pos = AppPos;
|
|
1248
|
+
exports.app_random = AppRandom;
|
|
1249
|
+
exports.app_root = AppRoot;
|
|
1250
|
+
exports.app_row = AppRow;
|
|
1251
|
+
exports.app_shape = AppShape;
|
|
1252
|
+
exports.app_text = AppText;
|
|
1253
|
+
exports.app_trace = AppTrace;
|
|
1254
|
+
exports.app_wrap = AppWrap;
|
|
1255
|
+
|
|
1256
|
+
//# sourceMappingURL=app-col_12.cjs.entry.js.map
|