1

The fill effect that we can see here http://hakim.se/experiments/html5/coil/ is quite amazing. I could not even guess anything about how a fill like that (close the shape while drawing you'll see that you're creating fills of the closed shape) could work..

Any ideas, please ?

Mia
  • 6,220
  • 12
  • 47
  • 81
  • In addition to my answer, try searching the web for "flood fill polygon" if you're interested in the mechanics of how a browser's canvas implementation might fill the actual polygon content. – GargantuChet Jan 03 '13 at 00:29

3 Answers3

6

It sounds like you're looking for the overall high-level process. Without reverse-engineering the approach used at that site, here's how I might consider doing it.

Start with a point at the mouse's current position. Every so often,

  1. Draw a line segment from the mouse's previous position to the mouse's current position.
  2. Remove line segments that are too old.
  3. If the new line segment intersects any existing ones (Google "detect line segment intersection" or similar), split them at the point where they intersect (searching for "algorithm split line segment at intersection" might get you there).

    Assume that you start with

       o----o
        \
         \     o
          \   /
           \ /
            o
    

    and add a segment from the point on the right, extending leftward:

       o----o
        \
    o----------o
          \   /
           \ /
            o
    

    Note that the new segment intersects an existing line segment. Split them at the point of intersection:

       o----o
        \
    o----o-----o
          \   /
           \ /
            o
    

    Note that o denotes the end of a line segment. We've gone from four segments, two of which intersect, to six line segments, four of which share a common point.

    These steps will give you a continuous trail of line segments. Now let's figure out whether they form a polygon:

  4. Step end-to-end through each line segment. Identify the first end of a line segment that is shared between multiple non-adjacent segments. Once you've found that end, draw all line segments up to that point:

       ●----●
        \
         ●
    
  5. Start at the other end and do the same thing.

       o----o
        \
    ●----●
    
  6. All of the remaining line segments are part of the polygon. Now, draw the enclosed polygon on the canvas.

       o----o
        \
    o----●-----●
          \.../
           \./
            ●
    
  7. Finally it's time to figure out which circles are contained within the polygon. Armed with the list of segments from above that actually form the polygon, hit the web with a search like "algorithm point is inside polygon".

Community
  • 1
  • 1
GargantuChet
  • 5,691
  • 1
  • 30
  • 41
1

You're basically drawing a polyline (a line strip, in OpenGL terminology). There are three key problems:

  • How to test whether or not you've closed your polyline.
  • How to get the closed polyline once you've decided that there is one.
  • How to rasterise your closed polyline to get the filled shape.

For the first problem, you can (roughly speaking, although it will be a bit fiddly in practice) store the sequence of pixels you hit while drawing your polyline and then stop when the current bit of line you're drawing hits something you drew earlier. (In the game, the old bits of line expire after a while - this can be modelled by storing time values for the pixels and removing them when their age is greater than some threshold.)

For the second problem, you just keep the part of your pixel sequence between the start and end crossing points.

The third problem is somewhat harder if you want to do it robustly (there are lots of "enjoyable" special cases) - do a search for "polygon rasterization" and be prepared for quite a bit of reading. I once wrote some code to do it, which is here, for what it's worth:

https://github.com/sgolodetz/millipede/blob/master/trunk/source/common/graphics/PolylineRasterizer.cpp

Note that in practice, all of this will likely be rather fiddlier than I've described here - but something along these lines is roughly how you might go about it.

Stuart Golodetz
  • 20,238
  • 4
  • 51
  • 80
0

Use begin path http://www.html5canvastutorials.com/tutorials/html5-canvas-shape-fill/

<!DOCTYPE HTML>
<html>
<head>
<style>
  body {
    margin: 0px;
    padding: 0px;
  }
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');

  // begin custom shape
  context.beginPath();
  context.moveTo(170, 80);
  context.bezierCurveTo(130, 100, 130, 150, 230, 150);
  context.bezierCurveTo(250, 180, 320, 180, 340, 150);
  context.bezierCurveTo(420, 150, 420, 120, 390, 100);
  context.bezierCurveTo(430, 40, 370, 30, 340, 50);
  context.bezierCurveTo(320, 5, 250, 20, 250, 50);
  context.bezierCurveTo(200, 5, 150, 20, 170, 80);

  // complete custom shape
  context.closePath();
  context.lineWidth = 5;
  context.fillStyle = '#8ED6FF';
  context.fill();
  context.strokeStyle = 'blue';
  context.stroke();
</script>
</body>
</html>
wedstrom
  • 555
  • 1
  • 3
  • 14