Advertisement
elvecent

metaballs

Jun 5th, 2017
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // can be run there: http://www.typescriptlang.org/play
  2.  
  3. class State {
  4.     static dragging: boolean;
  5.     static inflating: boolean;
  6.     static draggingBallIndex: number;
  7. }
  8.  
  9. class Ball {
  10.     posX: number;
  11.     posY: number;
  12.     weight: number;
  13.     constructor(public x: number, public y: number, radius) {
  14.         this.posX = x;
  15.         this.posY = y;
  16.         this.weight = Math.pow(radius, 2);
  17.     }
  18. }
  19.  
  20. class Grid {
  21.     content: Array<Array<number>>;
  22.     constructor(public height: number, public width: number) {
  23.         this.content = new Array(height);
  24.         let i: number;
  25.         for (i = 0; i < this.height; i++)
  26.             this.content[i] = new Array(width);
  27.         this.reset();
  28.     }
  29.     reset() {
  30.         let i: number;
  31.         let j: number;
  32.         for (i = 0; i < this.height; i++)
  33.             for (j = 0; j < this.width; j++)
  34.                 this.content[i][j] = 0;
  35.     }
  36.     drawBall(b) {
  37.         let i: number;
  38.         let j: number;
  39.         for (i = 0; i < this.height; i++)
  40.             for (j = 0; j < this.width; j++)
  41.                 this.content[i][j] += b.weight / (Math.pow(i - b.x, 2) + Math.pow(j - b.y, 2));
  42.     }
  43.     drawInContext(ctx) {
  44.         let i: number;
  45.         let j: number;
  46.         let data = ctx.getImageData(0,0,n,n);
  47.         for (i = 0; i < this.height; i++)
  48.             for (j = 0; j < this.width; j++)
  49.                 if (this.content[i][j] > 1)
  50.                     dot(data, i, j);
  51.         ctx.putImageData(data, 0, 0);
  52.     }
  53. }
  54.  
  55. function canvasInit(height, width) {
  56.     let canvas = document.createElement("canvas");
  57.     canvas.setAttribute("height", "" + height);
  58.     canvas.setAttribute("width", "" + width);
  59.     document.body.appendChild(canvas);
  60.     return canvas;
  61. }
  62. function onMouseDown(e) {
  63.     State.dragging = true;
  64.     let relX = e.pageX - canvas.offsetLeft;
  65.     let relY = e.pageY - canvas.offsetTop;
  66.     State.draggingBallIndex = nearestBall(relX, relY);
  67.     if (State.draggingBallIndex < 0) {
  68.         newBall(balls,relX, relY);
  69.         State.inflating = true;
  70.         State.draggingBallIndex = balls.length - 1;
  71.     }
  72. }
  73. function newBall(balls,x,y) {
  74.     balls[balls.length] = new Ball(x,y,10);
  75. }
  76. function onMouseMove(e) {
  77.     if (State.dragging) {
  78.         let relX = e.pageX - canvas.offsetLeft;
  79.     let relY = e.pageY - canvas.offsetTop;
  80.         balls[State.draggingBallIndex].x = relX;
  81.         balls[State.draggingBallIndex].y = relY;
  82.     }
  83. }
  84. function onMouseUp(e) {
  85.     State.dragging = false;
  86.     State.inflating = false;
  87. }
  88. function dist2(x,y,u,v) {
  89.     return Math.pow(x-u,2) + Math.pow(y-v,2);
  90. }
  91. function dot(data,x,y) {
  92.     data.data[(n*y + x)*4 + 0] = 0;
  93.     data.data[(n*y + x)*4 + 1] = 0;
  94.     data.data[(n*y + x)*4 + 2] = 0;
  95.     data.data[(n*y + x)*4 + 3] = 255;
  96. }
  97. function nearestBall(x, y) {
  98.     let res = -1;
  99.     let d = +Infinity;
  100.     let i: number;
  101.     for (i = 0; i < balls.length; i++) {
  102.         let dd = dist2(balls[i].x, balls[i].y,x,y);
  103.         if (dd < d && dd < balls[i].weight) {
  104.             d = dd;
  105.             res = i;
  106.         }
  107.     }
  108.     return res;
  109. }
  110. State.dragging = false;
  111. State.inflating = false;
  112. State.draggingBallIndex = -1;
  113. let n = 400;
  114. let canvas = canvasInit(n, n);
  115. let ctx = canvas.getContext("2d");
  116. canvas.addEventListener("mousedown", onMouseDown);
  117. canvas.addEventListener("mouseup", onMouseUp);
  118. canvas.addEventListener("mousemove",onMouseMove);
  119. let balls = [new Ball(120, 50, 30),
  120.              new Ball(100, 150, 70)];
  121. let grid = new Grid(n, n);
  122. function redraw(time) {
  123.     let i: number;
  124.     ctx.clearRect(0, 0, n, n);
  125.     grid.reset();
  126.     let draggingBall = balls[State.draggingBallIndex];
  127.     if (State.inflating) {
  128.         draggingBall.weight = Math.pow(Math.sqrt(draggingBall.weight) + 1,2);
  129.     }
  130.     for (i = 0; i < balls.length; i++)
  131.         grid.drawBall(balls[i]);
  132.     grid.drawInContext(ctx);
  133.     requestAnimationFrame(redraw);
  134. }
  135. requestAnimationFrame(redraw);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement