new-project.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // JS pour la view projects/new
  2. (function(){
  3. var templates = {
  4. neutral: { title: 'Neutre', description: 'Template neutre', emoji: '🔲' },
  5. rural: { title: 'Paysage rural', description: 'Champs et forêts', emoji: '🌾' },
  6. urban: { title: 'Paysage urbain', description: 'Villes, bâtiments et routes', emoji: '🏙️' }
  7. };
  8. var mapTemplateEl = document.getElementById('mapTemplate');
  9. // Lire les tileDefinitions injectées côté serveur
  10. var tilesDataEl = document.getElementById('templateTilesData');
  11. var tilesData = {};
  12. if (tilesDataEl) {
  13. try {
  14. tilesData = JSON.parse(tilesDataEl.textContent || '{}');
  15. } catch (e) {
  16. tilesData = {};
  17. }
  18. }
  19. if (mapTemplateEl) {
  20. mapTemplateEl.addEventListener('change', function() {
  21. var selectedTemplate = this.value;
  22. var previewDiv = document.getElementById('templatePreview');
  23. var templateImage = document.getElementById('templateImage');
  24. var templateTitle = document.getElementById('templateTitle');
  25. var templateDescription = document.getElementById('templateDescription');
  26. var templateTilesContainer = document.getElementById('templateTiles');
  27. if (!selectedTemplate) {
  28. previewDiv.style.display = 'none';
  29. return;
  30. }
  31. // Render title/description from static map or fallback
  32. var staticMeta = templates[selectedTemplate] || null;
  33. if (staticMeta) {
  34. templateImage.innerHTML = '<span style="font-size: 3rem;">' + (staticMeta.emoji || '🎲') + '</span>';
  35. templateTitle.textContent = staticMeta.title || '';
  36. templateDescription.textContent = staticMeta.description || '';
  37. } else {
  38. templateImage.innerHTML = '';
  39. templateTitle.textContent = '';
  40. templateDescription.textContent = '';
  41. }
  42. // Render tiles from tilesData if present
  43. templateTilesContainer.innerHTML = '';
  44. var defs = tilesData[selectedTemplate] || [];
  45. if (Array.isArray(defs) && defs.length > 0) {
  46. defs.forEach(function(td) {
  47. var tileEl = document.createElement('div');
  48. tileEl.className = 'd-flex align-items-center gap-2';
  49. tileEl.style.margin = '0 .25rem';
  50. var swatch = document.createElement('div');
  51. swatch.style.width = '28px';
  52. swatch.style.height = '20px';
  53. swatch.style.background = td.color || '#ccc';
  54. swatch.style.border = '1px solid rgba(0,0,0,0.08)';
  55. swatch.style.borderRadius = '3px';
  56. var label = document.createElement('div');
  57. label.style.fontSize = '0.85rem';
  58. label.style.color = '#333';
  59. label.textContent = td.name || td.id || '';
  60. var wrapper = document.createElement('div');
  61. wrapper.style.display = 'flex';
  62. wrapper.style.flexDirection = 'column';
  63. wrapper.style.alignItems = 'center';
  64. wrapper.style.minWidth = '60px';
  65. wrapper.appendChild(swatch);
  66. wrapper.appendChild(label);
  67. templateTilesContainer.appendChild(wrapper);
  68. });
  69. } else {
  70. // pas de définitions => message court
  71. var msg = document.createElement('div');
  72. msg.className = 'text-muted small';
  73. msg.textContent = 'Aucune définition de tuiles disponible pour ce modèle.';
  74. templateTilesContainer.appendChild(msg);
  75. }
  76. previewDiv.style.display = 'block';
  77. });
  78. }
  79. // Gestion des presets hexagonaux et synchronisation du radius
  80. var hexPresets = document.getElementById('hexPresets');
  81. var hexRadius = document.getElementById('hexRadius');
  82. function hexCellsFromRadius(r) {
  83. // Formule nombre d'hexagones pour un rayon r : 1 + 3r(r+1)
  84. r = parseInt(r, 10) || 0;
  85. return 1 + 3 * r * (r + 1);
  86. }
  87. // Mettre à jour le champ radius caché quand le preset change
  88. if (hexRadius) {
  89. hexRadius.addEventListener('change', function() {
  90. var r = parseInt(this.value, 10) || 0;
  91. var radiusInput = document.getElementById('radiusInput');
  92. if (radiusInput) radiusInput.value = r;
  93. // redraw preview
  94. drawHexPreview(r);
  95. });
  96. }
  97. // Dessiner un aperçu SVG exact en maillage hexagonal (pointy-top)
  98. function drawHexPreview(radius) {
  99. var container = document.getElementById('hexPreview');
  100. if (!container) return;
  101. container.innerHTML = '';
  102. var svgNS = 'http://www.w3.org/2000/svg';
  103. var svg = document.createElementNS(svgNS, 'svg');
  104. svg.setAttribute('width', '100%');
  105. svg.setAttribute('height', '100%');
  106. svg.setAttribute('viewBox', '0 0 100 100');
  107. // Générer coordonnées axiales des hexagones pour un rayon donné
  108. var cells = [];
  109. for (var q = -radius; q <= radius; q++) {
  110. var r1 = Math.max(-radius, -q - radius);
  111. var r2 = Math.min(radius, -q + radius);
  112. for (var r = r1; r <= r2; r++) {
  113. cells.push({q: q, r: r});
  114. }
  115. }
  116. // Paramètres visuels : on va centrer et scaler dans le viewBox 0..100
  117. var N = cells.length;
  118. // Pour positionner les hex, utiliser conversion axial -> pixel pour pointy-top
  119. function hexToPixel(q, r, size) {
  120. var x = size * Math.sqrt(3) * (q + r/2);
  121. var y = size * 3/2 * r;
  122. return { x: x, y: y };
  123. }
  124. // Taille estimée : calculer bounding box non-scalée
  125. var size = 1; // unité
  126. var points = cells.map(function(c) { return hexToPixel(c.q, c.r, size); });
  127. var xs = points.map(p => p.x);
  128. var ys = points.map(p => p.y);
  129. var minX = Math.min.apply(null, xs);
  130. var maxX = Math.max.apply(null, xs);
  131. var minY = Math.min.apply(null, ys);
  132. var maxY = Math.max.apply(null, ys);
  133. var width = maxX - minX || 1;
  134. var height = maxY - minY || 1;
  135. // Définir un scale pour remplir le viewBox (tous en %) avec marges
  136. var padding = 6; // % padding
  137. var avail = 100 - 2*padding;
  138. var scale = Math.min(avail / width, avail / height);
  139. // Size (pixel unit in viewBox coords)
  140. var hexSize = scale * 0.9; // ajustement visuel
  141. // Center offset
  142. var offsetX = (100 - (width * scale)) / 2 - minX * scale;
  143. var offsetY = (100 - (height * scale)) / 2 - minY * scale;
  144. // Fonction pour dessiner un hexagon pointy-top at (cx,cy) with size s
  145. function hexPoints(cx, cy, s) {
  146. var pts = [];
  147. for (var i = 0; i < 6; i++) {
  148. var angle_deg = 60 * i - 30;
  149. var angle_rad = Math.PI / 180 * angle_deg;
  150. var x = cx + s * Math.cos(angle_rad);
  151. var y = cy + s * Math.sin(angle_rad);
  152. pts.push(x + ',' + y);
  153. }
  154. return pts.join(' ');
  155. }
  156. // Draw each hex
  157. cells.forEach(function(c, idx) {
  158. var p = hexToPixel(c.q, c.r, size);
  159. var cx = p.x * scale + offsetX;
  160. var cy = p.y * scale + offsetY;
  161. var s = hexSize / 2; // visual half-size
  162. var poly = document.createElementNS(svgNS, 'polygon');
  163. poly.setAttribute('points', hexPoints(cx, cy, s));
  164. poly.setAttribute('fill', '#e9ecef');
  165. poly.setAttribute('stroke', '#6c757d');
  166. poly.setAttribute('stroke-width', Math.max(0.2, s * 0.05));
  167. poly.setAttribute('opacity', '0.95');
  168. svg.appendChild(poly);
  169. });
  170. container.appendChild(svg);
  171. }
  172. // initial draw (respecter la valeur par défaut du select)
  173. if (hexRadius) drawHexPreview(parseInt(hexRadius.value,10));
  174. var form = document.getElementById('newProjectForm');
  175. if (form) {
  176. form.addEventListener('submit', function(e) {
  177. var name = (document.getElementById('mapName').value || '').trim();
  178. var radius = parseInt((document.getElementById('radiusInput') || {}).value, 10) || 0;
  179. if (!name) {
  180. alert('Veuillez saisir un nom pour votre carte.');
  181. e.preventDefault();
  182. return;
  183. }
  184. // Validation radius (1..15)
  185. if (radius < 1 || radius > 15) {
  186. alert('Le rayon doit être compris entre 1 et 15.');
  187. e.preventDefault();
  188. return;
  189. }
  190. // Log pour debug
  191. console.log('Création du projet (radius):', { name: name, radius: radius, template: document.getElementById('mapTemplate').value });
  192. });
  193. }
  194. })();