Posts tagged "dashed"

How to create a dashed rectangle in Flash

If you were ever in the need of drawing a dashed rectangle in Flash, you find that it’s not so simple as using a DashedStroke. I think this is certainly a missing feature in Flash. After spending hours looking for existing code I decided to write it myself.

The first very simple approach is to create a BitmapData with the required dash-gap pattern and use it as lineBitmapStyle. This works quite well but you don’t get the nice corners.

Ugly Corners

Ugly Corners

So you really need to draw the lines yourself. The trick here is to constraint the lines to start with a dash in each corner. You need to calculate the number of gaps needed for the length of the lines and then distribute any excess pixels evenly. This is rather simple to do if you use floating point precision while drawing the lines. Of course this is easy because we’re only drawing horizontal and vertical lines and don’t support rounded corners.

Nice Corners

Nice Corners

Having created the dashed rectangle element, it’s easy to create a skin for the BorderContainer. Just create a new skin as a copy of the original BorderContainerSkin and replace its bgRect with the DashedRect. This little exercise is left for the reader :-)

Here’s the code for drawing the rectangle:

<!-- DashedRect.mxml -->
<?xml version="1.0" encoding="utf-8"?>
<s:Rect xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark"
    xmlns:mx="library://ns.adobe.com/flex/mx">
  <fx:Script>
    <![CDATA[
      import flash.display.Graphics;

      private var _dash:int = 6;

      private var _gap:int = 6;

      public function set gap(i:int):void {
        _gap = i;
      }

      public function set dash(i:int):void {
        _dash = i;
      }

      override protected function draw(g:Graphics):void {
        var xx:int = drawX + width;
        var yy:int = drawY + height;
        var x:int, y:int, gx:Number, gy:Number;

        var nGapsH:Number = Math.floor(width / (_gap + _dash));
        var nGapsV:Number = Math.floor(height / (_gap + _dash));
        var gw:Number = nGapsH == 0 ? 0 : (width-((nGapsH + 1) * _dash)) / nGapsH;
        var gh:Number = nGapsV == 0 ? 0 : (height-((nGapsV + 1) * _dash)) / nGapsV;

        // top line
        g.moveTo(drawX, drawY);
        x = gx = drawX;
        while (x < xx) {
          x = Math.min(x + _dash, xx);
          g.lineTo(x, drawY);
          gx+=_dash + gw;
          x = gx;
          g.moveTo(x, drawY);
        }
        // right line
        g.moveTo(xx, drawY);
        y = gy = drawY;
        while (y < yy) {
          y = Math.min(y + _dash, yy);
          g.lineTo(xx, y);
          gy+=_dash + gh;
          y = gy;
          g.moveTo(xx, y);
        }
        // bottom line
        g.moveTo(xx, yy);
        x = gx = xx;
        while (x > drawX) {
          x = Math.max(x - _dash, drawX);
          g.lineTo(x, yy);
          gx-=_dash + gw;
          x = gx;
          g.moveTo(x, yy);
        }
        // left line
        g.moveTo(drawX, yy);
        y = gy = yy;
        while (y > drawY) {
          y = Math.max(y - _dash, drawY);
          g.lineTo(drawX, y);
          gy-=_dash + gh;
          y = gy;
          g.moveTo(drawX, y);
        }
      }

    ]]>
  </fx:Script>
</s:Rect>

 

And here’s how to use it:

<local:DashedRect x="0" y="0" width="100%" height="100%" dash="6" gap="6">
  <local:stroke>
    <s:SolidColorStroke color="0x000000" weight="2"/>
  </local:stroke>
</local:DashedRect>