PierreH commited on
Commit
2620a3c
·
verified ·
1 Parent(s): 5187d48

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +31 -288
index.html CHANGED
@@ -1,298 +1,41 @@
1
- <!DOCTYPE html>
2
- <html lang="fr">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
- <title>Toile Dynamique Minimaliste</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
10
- <style>
11
- .target-container {
12
- position: relative;
13
- width: 100%;
14
- aspect-ratio: 1/1;
15
- border-radius: 50%;
16
- overflow: visible;
17
- }
18
- .circle { position: absolute; border-radius: 50%; z-index: 1; }
19
- .circle1 { background-color: #fecaca; width: 8%; height: 8%; top: 46%; left: 46%; }
20
- .circle2 { background-color: #fed7aa; width: 20%; height: 20%; top: 40%; left: 40%; }
21
- .circle3 { background-color: #fef08a; width: 35%; height: 35%; top: 32.5%; left: 32.5%; }
22
- .circle4 { background-color: #bbf7d0; width: 55%; height: 55%; top: 22.5%; left: 22.5%; }
23
- .circle5 { background-color: #bfdbfe; width: 75%; height: 75%; top: 12.5%; left: 12.5%; }
24
 
25
- .label {
26
- position: absolute;
27
- font-weight: bold;
28
- font-size: 0.75rem;
29
- color: #333;
30
- cursor: pointer;
31
- user-select: none;
32
- white-space: nowrap;
33
- z-index: 7;
34
- padding: 0.25rem 0.5rem;
35
- background-color: rgba(255, 255, 255, 0.85);
36
- border-radius: 0.25rem;
37
- transition: all 0.2s ease;
38
- box-shadow: 0 1px 2px rgba(0,0,0,0.1);
39
- }
40
- .label:hover { transform: scale(1.05); background-color: rgba(255,255,255,0.95); }
41
- .label.selected { background-color: #3b82f6; color: white; transform: scale(1.1); }
42
 
43
- #canvas {
44
- position: absolute;
45
- top: 0; left: 0;
46
- width: 100%; height: 100%;
47
- z-index: 6;
48
- pointer-events: none;
49
- }
50
 
51
- .note-input {
52
- resize: none;
53
- font-size: 0.875rem;
54
- text-align: center;
55
- background-color: transparent;
56
- border: none;
57
- outline: none;
58
  }
59
 
60
- .note-input::placeholder { color: #9ca3af; }
61
-
62
- .action-btn {
63
- transition: all 0.2s ease;
64
- }
65
-
66
- .action-btn:hover { transform: translateY(-1px); }
67
- .action-btn:active { transform: translateY(1px); }
68
- </style>
69
- </head>
70
- <body class="bg-gray-50 min-h-screen flex flex-col items-center justify-center p-4">
71
- <div class="w-full max-w-md bg-white rounded-xl shadow-md p-6 space-y-6">
72
- <h1 class="text-xl font-bold text-center text-gray-700">☆ Mon Étoile de Mots ☆</h1>
73
- <textarea id="userNotes" class="note-input w-full p-2 rounded-lg bg-gray-50" placeholder="Écrivez vos notes ici..." rows="2"></textarea>
74
- <div class="target-container bg-white shadow-inner" id="target-container">
75
- <canvas id="canvas"></canvas>
76
- <div class="circle circle5"></div>
77
- <div class="circle circle4"></div>
78
- <div class="circle circle3"></div>
79
- <div class="circle circle2"></div>
80
- <div class="circle circle1"></div>
81
- </div>
82
-
83
- <div class="grid grid-cols-2 gap-3">
84
- <input type="text" id="newKeyword" placeholder="Nouveau mot" class="col-span-2 p-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
85
- <div class="flex space-x-2">
86
- <input type="text" id="editKeyword" placeholder="Modifier" class="flex-1 p-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
87
- <button onclick="updateKeyword()" class="action-btn bg-blue-500 text-white px-3 py-2 rounded-lg hover:bg-blue-600">Modifier</button>
88
- </div>
89
- <button onclick="deleteKeyword()" class="action-btn bg-red-500 text-white py-2 rounded-lg hover:bg-red-600">Supprimer</button>
90
- <button onclick="addKeyword()" class="action-btn bg-green-500 text-white py-2 rounded-lg hover:bg-green-600">Ajouter</button>
91
- <button onclick="saveAsImage()" class="action-btn bg-purple-500 text-white py-2 rounded-lg hover:bg-purple-600">Enregistrer (Image)</button>
92
- <button onclick="saveAsPDF()" class="action-btn bg-indigo-500 text-white py-2 rounded-lg hover:bg-indigo-600">Enregistrer (PDF)</button>
93
- <button onclick="resetKeywords()" class="action-btn bg-gray-500 text-white py-2 rounded-lg hover:bg-gray-600 col-span-2">Réinitialiser</button>
94
- </div>
95
- </div>
96
-
97
- <script>
98
- const { jsPDF } = window.jspdf;
99
-
100
- let keywords = [
101
- { text: "Identification", x: null, y: null },
102
- { text: "Gestion", x: null, y: null },
103
- { text: "Adaptation", x: null, y: null },
104
- { text: "Autonomie", x: null, y: null },
105
- { text: "Connaissance", x: null, y: null },
106
- { text: "Prévention", x: null, y: null },
107
- { text: "Équilibre", x: null, y: null },
108
- { text: "Stratégies", x: null, y: null },
109
- { text: "Motivation", x: null, y: null },
110
- { text: "Recours", x: null, y: null }
111
- ];
112
-
113
- let selectedKeywordIndex = null;
114
- let isDragging = false;
115
- let dragStartX, dragStartY;
116
- let draggedLabel = null;
117
- let draggedIndex = null;
118
-
119
- const canvas = document.getElementById('canvas');
120
- const ctx = canvas.getContext('2d');
121
-
122
- function renderKeywords() {
123
- const container = document.getElementById('target-container');
124
- const centerX = container.offsetWidth / 2;
125
- const centerY = container.offsetHeight / 2;
126
- const radius = Math.min(centerX, centerY) * 0.35;
127
-
128
- container.querySelectorAll('.label').forEach(e => e.remove());
129
-
130
- keywords.forEach((word, index) => {
131
- const labelWidth = word.text.length * 8 + 16;
132
- const labelHeight = 24;
133
 
134
- if (word.x === null || word.y === null) {
135
- const angleStep = (2 * Math.PI) / keywords.length;
136
- const angle = index * angleStep - Math.PI / 2;
137
- word.x = centerX + radius * Math.cos(angle) - labelWidth / 2;
138
- word.y = centerY + radius * Math.sin(angle) - labelHeight / 2;
139
- }
140
 
141
- const label = document.createElement('div');
142
- label.className = 'label draggable';
143
- label.style.left = `${word.x}px`;
144
- label.style.top = `${word.y}px`;
145
- label.textContent = word.text;
146
- label.dataset.index = index;
147
-
148
- label.addEventListener('mousedown', (e) => startDrag(e, label, index));
149
- label.addEventListener('touchstart', (e) => {
150
- const touch = e.touches[0];
151
- startDrag(touch, label, index);
152
- });
153
-
154
- if (index === selectedKeywordIndex) label.classList.add('selected');
155
-
156
- container.appendChild(label);
157
- });
158
-
159
- resizeCanvas();
160
  }
161
 
162
- function startDrag(e, label, index) {
163
- isDragging = true;
164
- draggedLabel = label;
165
- draggedIndex = index;
166
- dragStartX = e.clientX - parseFloat(label.style.left);
167
- dragStartY = e.clientY - parseFloat(label.style.top);
168
-
169
- selectKeyword(index);
170
-
171
- document.addEventListener('mousemove', drag);
172
- document.addEventListener('mouseup', stopDrag);
173
-
174
- e.preventDefault();
175
- }
176
-
177
- function drag(e) {
178
- if (!isDragging) return;
179
-
180
- const container = document.getElementById('target-container');
181
- let newX = e.clientX - dragStartX;
182
- let newY = e.clientY - dragStartY;
183
-
184
- newX = Math.max(0, Math.min(newX, container.offsetWidth - draggedLabel.offsetWidth));
185
- newY = Math.max(0, Math.min(newY, container.offsetHeight - draggedLabel.offsetHeight));
186
-
187
- draggedLabel.style.left = `${newX}px`;
188
- draggedLabel.style.top = `${newY}px`;
189
-
190
- keywords[draggedIndex].x = newX;
191
- keywords[draggedIndex].y = newY;
192
-
193
- resizeCanvas();
194
- }
195
-
196
- function stopDrag() {
197
- isDragging = false;
198
- draggedLabel = null;
199
- draggedIndex = null;
200
-
201
- document.removeEventListener('mousemove', drag);
202
- document.removeEventListener('mouseup', stopDrag);
203
- }
204
-
205
- function selectKeyword(index) {
206
- selectedKeywordIndex = index;
207
- document.getElementById('editKeyword').value = keywords[index].text;
208
- document.querySelectorAll('.label').forEach(label => label.classList.remove('selected'));
209
- const selectedLabel = document.querySelector(`.label[data-index='${index}']`);
210
- if (selectedLabel) selectedLabel.classList.add('selected');
211
- }
212
-
213
- function resizeCanvas() {
214
- const container = document.getElementById('target-container');
215
- canvas.width = container.offsetWidth;
216
- canvas.height = container.offsetHeight;
217
- drawLines();
218
- }
219
-
220
- function drawLines() {
221
- ctx.clearRect(0, 0, canvas.width, canvas.height);
222
- if (keywords.length < 2) return;
223
-
224
- ctx.beginPath();
225
- ctx.strokeStyle = '#3b82f6';
226
- ctx.lineWidth = 1;
227
- ctx.setLineDash([5, 3]);
228
-
229
- const positions = keywords.map((k, i) => {
230
- const label = document.querySelector(`.label[data-index='${i}']`);
231
- return {
232
- x: k.x + (label?.offsetWidth || 0) / 2,
233
- y: k.y + (label?.offsetHeight || 0) / 2
234
- };
235
- });
236
-
237
- for (let i = 0; i < positions.length; i++) {
238
- const next = positions[(i + 1) % positions.length];
239
- ctx.moveTo(positions[i].x, positions[i].y);
240
- ctx.lineTo(next.x, next.y);
241
- }
242
-
243
- ctx.stroke();
244
- }
245
-
246
- function addKeyword() {
247
- const input = document.getElementById('newKeyword');
248
- const text = input.value.trim();
249
- if (text) {
250
- keywords.push({ text, x: null, y: null });
251
- input.value = '';
252
- renderKeywords();
253
- }
254
- }
255
-
256
- function updateKeyword() {
257
- const input = document.getElementById('editKeyword');
258
- const text = input.value.trim();
259
- if (text && selectedKeywordIndex !== null) {
260
- keywords[selectedKeywordIndex].text = text;
261
- renderKeywords();
262
- selectKeyword(selectedKeywordIndex);
263
- }
264
- }
265
-
266
- function deleteKeyword() {
267
- if (selectedKeywordIndex !== null) {
268
- keywords.splice(selectedKeywordIndex, 1);
269
- selectedKeywordIndex = null;
270
- document.getElementById('editKeyword').value = '';
271
- renderKeywords();
272
- }
273
- }
274
-
275
- function resetKeywords() {
276
- keywords.forEach(word => { word.x = null; word.y = null; });
277
- renderKeywords();
278
- }
279
-
280
- async function saveAsImage() { /* ... */ }
281
- async function saveAsPDF() { /* ... */ }
282
-
283
- // Support drag tactile
284
- document.addEventListener('touchmove', function(e) {
285
- if (isDragging) {
286
- const touch = e.touches[0];
287
- drag(touch);
288
- e.preventDefault();
289
- }
290
- }, { passive: false });
291
-
292
- document.addEventListener('touchend', stopDrag);
293
 
294
- document.addEventListener('DOMContentLoaded', renderKeywords);
295
- window.addEventListener('resize', renderKeywords);
296
- </script>
297
- </body>
298
- </html>
 
1
+ function renderKeywords() {
2
+ const container = document.getElementById('target-container');
3
+ const centerX = container.offsetWidth / 2;
4
+ const centerY = container.offsetHeight / 2;
5
+ const radius = Math.min(centerX, centerY) * 0.35;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
+ container.querySelectorAll('.label').forEach(e => e.remove());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ keywords.forEach((word, index) => {
10
+ const labelWidth = word.text.length * 8 + 16;
11
+ const labelHeight = 24;
 
 
 
 
12
 
13
+ if (word.x === null || word.y === null) {
14
+ const angleStep = (2 * Math.PI) / keywords.length;
15
+ const angle = index * angleStep - Math.PI / 2;
16
+ word.x = centerX + radius * Math.cos(angle) - labelWidth / 2;
17
+ word.y = centerY + radius * Math.sin(angle) - labelHeight / 2;
 
 
18
  }
19
 
20
+ const label = document.createElement('div');
21
+ label.className = 'label draggable';
22
+ label.style.left = `${word.x}px`;
23
+ label.style.top = `${word.y}px`;
24
+ label.textContent = word.text;
25
+ label.dataset.index = index;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
+ label.addEventListener('mousedown', (e) => startDrag(e, label, index));
28
+ label.addEventListener('touchstart', (e) => {
29
+ const touch = e.touches[0];
30
+ startDrag(touch, label, index);
31
+ });
 
32
 
33
+ if (index === selectedKeywordIndex) {
34
+ label.classList.add('selected');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  }
36
 
37
+ container.appendChild(label);
38
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
+ resizeCanvas();
41
+ }