less copy protection, more size visualization
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

282 lignes
7.7 KiB

  1. let selected = null;
  2. let selectedEntity = null;
  3. let entityIndex = 0;
  4. let clicked = null;
  5. let dragging = false;
  6. let clickTimeout = null;
  7. let dragOffsetX = null;
  8. let dragOffsetY = null;
  9. let altHeld = false;
  10. const config = {
  11. height: math.unit(10, "meters"),
  12. minLineSize: 50,
  13. maxLineSize: 250
  14. }
  15. const entities = {
  16. }
  17. function constrainRel(coords) {
  18. return {
  19. x: Math.min(Math.max(coords.x, 0), 1),
  20. y: Math.min(Math.max(coords.y, 0), 1)
  21. }
  22. }
  23. function snapRel(coords) {
  24. return constrainRel({
  25. x: coords.x,
  26. y: altHeld ? coords.y : (Math.abs(coords.y - 1) < 0.05 ? 1 : coords.y)
  27. });
  28. }
  29. function adjustAbs(coords, oldHeight, newHeight) {
  30. return {x: coords.x, y: 1 + (coords.y - 1) * math.divide(oldHeight, newHeight)};
  31. }
  32. function rel2abs(coords) {
  33. const canvasWidth = document.querySelector("#display").clientWidth - 50;
  34. const canvasHeight = document.querySelector("#display").clientHeight - 50;
  35. return {x: coords.x * canvasWidth, y: coords.y * canvasHeight};
  36. }
  37. function abs2rel(coords) {
  38. const canvasWidth = document.querySelector("#display").clientWidth - 50;
  39. const canvasHeight = document.querySelector("#display").clientHeight - 50;
  40. return {x: coords.x / canvasWidth, y: coords.y / canvasHeight};
  41. }
  42. function updateEntityElement(entity, element) {
  43. const position = rel2abs({x: element.dataset.x, y: element.dataset.y});
  44. element.style.left = position.x + "px";
  45. element.style.top = position.y + "px";
  46. const canvasHeight = document.querySelector("#display").clientHeight;
  47. const pixels = math.divide(entity.height, config.height) * canvasHeight;
  48. element.style.setProperty("--height", pixels + "px");
  49. }
  50. function updateSizes() {
  51. drawScale();
  52. Object.entries(entities).forEach(([key, entity]) => {
  53. const element = document.querySelector("#entity-" + key);
  54. updateEntityElement(entity, element);
  55. });
  56. }
  57. function drawScale() {
  58. function drawTicks(/** @type {CanvasRenderingContext2D} */ ctx, pixelsPer, heightPer) {
  59. let total = heightPer.clone();
  60. total.value = 0;
  61. for (let y = ctx.canvas.clientHeight - 50; y >= 50; y -= pixelsPer) {
  62. drawTick(ctx, 50, y, total);
  63. total = math.add(total, heightPer);
  64. }
  65. }
  66. function drawTick(/** @type {CanvasRenderingContext2D} */ ctx, x, y, value) {
  67. const oldStyle = ctx.strokeStyle;
  68. ctx.beginPath();
  69. ctx.moveTo(x, y);
  70. ctx.lineTo(x + 20, y);
  71. ctx.strokeStyle = "#000000";
  72. ctx.stroke();
  73. ctx.beginPath();
  74. ctx.moveTo(x + 20, y);
  75. ctx.lineTo(ctx.canvas.clientWidth - 70, y);
  76. ctx.strokeStyle = "#aaaaaa";
  77. ctx.stroke();
  78. ctx.beginPath();
  79. ctx.moveTo(ctx.canvas.clientWidth - 70, y);
  80. ctx.lineTo(ctx.canvas.clientWidth - 50, y);
  81. ctx.strokeStyle = "#000000";
  82. ctx.stroke();
  83. ctx.beginPath();
  84. ctx.fillText(value.format({precision: 3}), x+20, y+20);
  85. ctx.strokeStyle = oldStyle;
  86. }
  87. const canvas = document.querySelector("#display");
  88. /** @type {CanvasRenderingContext2D} */
  89. const ctx = canvas.getContext("2d");
  90. let pixelsPer = (ctx.canvas.clientHeight - 100) / config.height.value;
  91. let heightPer = config.height.clone();
  92. heightPer.value = 1;
  93. if (pixelsPer < config.minLineSize) {
  94. heightPer.value /= pixelsPer / config.minLineSize;
  95. pixelsPer = config.minLineSize;
  96. }
  97. if (pixelsPer > config.maxLineSize) {
  98. heightPer.value /= pixelsPer / config.maxLineSize;
  99. pixelsPer = config.maxLineSize;
  100. }
  101. ctx.clearRect(0, 0, canvas.width, canvas.height);
  102. ctx.scale(1, 1);
  103. ctx.canvas.width = canvas.clientWidth;
  104. ctx.canvas.height = canvas.clientHeight;
  105. ctx.beginPath();
  106. ctx.moveTo(50, 50);
  107. ctx.lineTo(50, ctx.canvas.clientHeight - 50);
  108. ctx.stroke();
  109. ctx.beginPath();
  110. ctx.moveTo(ctx.canvas.clientWidth - 50, 50);
  111. ctx.lineTo(ctx.canvas.clientWidth - 50, ctx.canvas.clientHeight - 50);
  112. ctx.stroke();
  113. drawTicks(ctx, pixelsPer, heightPer);
  114. }
  115. function makeEntity() {
  116. const entityTemplate = {
  117. name: "",
  118. author: "",
  119. height: math.unit(Math.random() * 2 + 1, "meters")
  120. }
  121. return entityTemplate;
  122. }
  123. function clickDown(e) {
  124. clicked = e.target;
  125. const rect = e.target.getBoundingClientRect();
  126. let entX = document.querySelector("#entities").getBoundingClientRect().x;
  127. let entY = document.querySelector("#entities").getBoundingClientRect().y;
  128. dragOffsetX = e.clientX - rect.left + entX - rect.width / 2;
  129. dragOffsetY = e.clientY - rect.top + entY - rect.height;
  130. clickTimeout = setTimeout(() => {dragging = true}, 100)
  131. }
  132. function clickUp() {
  133. clearTimeout(clickTimeout);
  134. if (clicked) {
  135. if (dragging) {
  136. dragging = false;
  137. } else {
  138. select(clicked);
  139. }
  140. clicked = null;
  141. }
  142. }
  143. function deselect() {
  144. if (selected) {
  145. selected.classList.remove("selected");
  146. }
  147. selected = null;
  148. }
  149. function select(target) {
  150. deselect();
  151. selected = target;
  152. selectedEntity = entities[target.dataset.key];
  153. selected.classList.add("selected");
  154. entityInfo(selectedEntity);
  155. }
  156. function entityInfo(entity) {
  157. document.querySelector("#entity-name").innerText = "Name: " + entity.name;
  158. document.querySelector("#entity-author").innerText = "Author: " + entity.author;
  159. document.querySelector("#entity-height").innerText = "Height: " + entity.height.format({ precision: 3 });
  160. }
  161. function displayEntity(entity, x, y) {
  162. const location = entity.location;
  163. const img = document.createElement("img");
  164. img.src = "./pepper.png"
  165. img.classList.add("entity");
  166. img.dataset.x = x;
  167. img.dataset.y = y;
  168. img.addEventListener("mousedown", e => {clickDown(e); e.stopPropagation()});
  169. img.id = "entity-" + entityIndex;
  170. img.dataset.key = entityIndex;
  171. entities[entityIndex] = entity;
  172. entityIndex += 1;
  173. const world = document.querySelector("#entities");
  174. world.appendChild(img);
  175. updateEntityElement(entity, img);
  176. }
  177. document.addEventListener("DOMContentLoaded", () => {
  178. for (let x = 0; x < 5; x++) {
  179. const entity = makeEntity();
  180. entity.name = "Green is my pepper";
  181. entity.author = "Fen"
  182. const x = 0.25 + Math.random() * 0.5;
  183. const y = 0.25 + Math.random() * 0.5;
  184. displayEntity(entity, x, y);
  185. }
  186. updateSizes();
  187. document.querySelector("#options-height-value").addEventListener("input", e => {
  188. updateWorldHeight();
  189. })
  190. document.querySelector("#options-height-unit").addEventListener("input", e => {
  191. updateWorldHeight();
  192. })
  193. world.addEventListener("mousedown", e => deselect());
  194. document.addEventListener("mouseup", e => clickUp());
  195. });
  196. window.addEventListener("resize", () => {
  197. updateSizes();
  198. })
  199. document.addEventListener("mousemove", (e) => {
  200. if (clicked) {
  201. const position = snapRel(abs2rel({x: e.clientX - dragOffsetX, y: e.clientY - dragOffsetY}));
  202. clicked.dataset.x = position.x;
  203. clicked.dataset.y = position.y;
  204. updateEntityElement(entities[clicked.dataset.key], clicked);
  205. }
  206. });
  207. function updateWorldHeight() {
  208. const value = Math.max(1, document.querySelector("#options-height-value").value);
  209. const unit = document.querySelector("#options-height-unit").value;
  210. const oldHeight = config.height;
  211. config.height = math.unit(value + " " + unit)
  212. Object.entries(entities).forEach(([key, entity]) => {
  213. const element = document.querySelector("#entity-" + key);
  214. const newPosition = adjustAbs({x: element.dataset.x, y: element.dataset.y}, oldHeight, config.height);
  215. element.dataset.x = newPosition.x;
  216. element.dataset.y = newPosition.y;
  217. });
  218. updateSizes();
  219. }