<!doctype html>
<html lang="en" dir="ltr">
  <head>
    <meta charset="utf-8" />
  </head>
  <body>
    <script type="module">
      import {
        combinations,
        remap,
      } from "./node_modules/@jrc03c/js-math-tools/src/index.mjs"

      import {
        pointIsInTriangle,
        getConvexHull,
      } from "./dist/js-convex-hull.import.mjs"

      CanvasRenderingContext2D.prototype.drawLine = function (x1, y1, x2, y2) {
        const self = this
        self.beginPath()
        self.moveTo(x1, y1)
        self.lineTo(x2, y2)
        self.stroke()
        return self
      }

      const mouse = [0, 0]
      const padding = 32
      const width = 512
      const height = 512
      const canvas = document.createElement("canvas")
      canvas.width = width
      canvas.height = height
      document.body.appendChild(canvas)

      const context = canvas.getContext("2d")
      context.lineWidth = 4

      // generate points
      const centroids = []

      for (let i = 0; i < parseInt(Math.random() * 7 + 1); i++) {
        centroids.push([Math.random() * width, Math.random() * height])
      }

      let points = []
      const randomness = width / 5

      for (let i = 0; i < 250; i++) {
        const c = centroids[parseInt(Math.random() * centroids.length)]
        const r = Math.random() * randomness
        const a = Math.random() * 2 * Math.PI
        const x = Math.cos(a) * r
        const y = Math.sin(a) * r
        points.push([c[0] + x, c[1] + y])
      }

      const xvals = points.map(p => p[0])
      const yvals = points.map(p => p[1])
      const xmin = Math.min(...xvals)
      const xmax = Math.max(...xvals)
      const ymin = Math.min(...yvals)
      const ymax = Math.max(...yvals)

      points = points.map(p => {
        return [
          remap(p[0], xmin, xmax, padding, width - padding),
          remap(p[1], ymin, ymax, padding, height - padding),
        ]
      })

      // compute hull
      const hull = getConvexHull(points)

      function loop() {
        try {
          context.fillStyle = "rgb(235, 235, 235)"
          context.fillRect(0, 0, width, height)

          // draw points
          context.fillStyle = "black"

          points.forEach(p => {
            context.beginPath()
            context.arc(p[0], p[1], 5, 0, Math.PI * 2, false)
            context.fill()
          })

          // check whether or not mouse is inside hull
          const triangles = combinations(
            hull.map(h => JSON.stringify(h)),
            3,
          ).map(tri => tri.map(p => JSON.parse(p)))

          const mouseIsInHull = triangles.some(tri => {
            try {
              return pointIsInTriangle(mouse, tri)
            } catch (e) {
              return false
            }
          })

          // draw hull
          context.strokeStyle = mouseIsInHull ? "green" : "red"

          context.fillStyle = mouseIsInHull
            ? "rgba(0, 255, 0, 0.1)"
            : "rgba(255, 0, 0, 0.1)"

          context.beginPath()

          hull.forEach((h1, i) => {
            const h2 = hull[(i + 1) % hull.length]

            if (i === 0) {
              context.moveTo(...h1)
            }

            context.lineTo(...h2)
          })

          context.fill()
          context.stroke()

          window.requestAnimationFrame(loop)
        } catch (e) {}
      }

      canvas.addEventListener("mousemove", event => {
        mouse[0] = event.offsetX
        mouse[1] = event.offsetY
      })

      loop()
    </script>
  </body>
</html>