Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A Starling Mesh that displays a slice of a quad (just like a pie chart, but rectangular). Useful e.g. for a circular progress indicator.
package starling.extensions
{
import flash.geom.Point;
import flash.geom.Rectangle;
import starling.display.Mesh;
import starling.rendering.IndexData;
import starling.rendering.VertexData;
import starling.textures.Texture;
public class QuadSection extends Mesh
{
private var _width:Number;
private var _height:Number;
private var _color:uint;
private var _ratio:Number;
private static var sPoint:Point = new Point();
private static const sSlices:Array =
[
{ ratio: 0.0, u: 0.5, v: 0.0 },
{ ratio: 0.125, u: 1.0, v: 0.0 },
{ ratio: 0.375, u: 1.0, v: 1.0 },
{ ratio: 0.625, u: 0.0, v: 1.0 },
{ ratio: 0.875, u: 0.0, v: 0.0 },
{ ratio: 1.0, u: 0.5, v: 0.0 }
];
public function QuadSection(width:Number, height:Number, color:uint = 0xffffff)
{
_color = color;
_width = width;
_height = height;
_ratio = 1.0;
var vertexData:VertexData = new VertexData(null, 6);
var indexData:IndexData = new IndexData(15);
super(vertexData, indexData);
this.updateVertices();
}
private function updateVertices():void
{
vertexData.numVertices = 0;
indexData.numIndices = 0;
if (_ratio < 1.e-4)
{
setVertexDataChanged();
return;
}
var angle:Number = (_ratio * 2.0 - 0.5) * Math.PI;
var numSlices:int = sSlices.length;
updateVertex(0, 0.5, 0.5); // center point
for (var i:int = 1; i < numSlices; ++i)
{
var currSlice:Object = sSlices[i];
var prevSlice:Object = sSlices[i - 1];
var nextVertexID:int = i < 6 ? i + 1 : 1;
indexData.addTriangle(0, i, nextVertexID);
updateVertex(i, prevSlice.u, prevSlice.v);
if (_ratio > currSlice.ratio)
{
updateVertex(nextVertexID, currSlice.u, currSlice.v);
}
else
{
intersectLineWithSlice(prevSlice.u, prevSlice.v, currSlice.u, currSlice.v, angle, sPoint);
updateVertex(nextVertexID, sPoint.x, sPoint.y);
break;
}
}
setVertexDataChanged();
}
private function updateVertex(vertexID:int, u:Number, v:Number):void
{
var x:Number = u;
var y:Number = v;
var tex:Texture = super.texture;
if (tex !== null)
{
var frame:Rectangle = tex.frame;
if (frame !== null)
{
x -= 0.5;
y -= 0.5;
x *= tex.width / frame.width;
y *= tex.height / frame.height;// assume equal aspect
x += 0.5;
y += 0.5;
}
tex.setTexCoords(vertexData, vertexID, "texCoords", u, v);
}
x *= _width;
y *= _height;
vertexData.setPoint(vertexID, "position", x, y);
vertexData.setColor(vertexID, "color", _color);
}
private function intersectLineWithSlice(ax:Number, ay:Number, bx:Number, by:Number, angle:Number, out:Point = null):Point
{
if ((ax == bx) && (ay == by)) return null; // length = 0
var abx:Number = bx - ax;
var aby:Number = by - ay;
var cdx:Number = Math.cos(angle);
var cdy:Number = Math.sin(angle);
var tDen:Number = cdy * abx - cdx * aby;
if (tDen == 0.0) return null; // parallel or identical
out ||= new Point();
var cx:Number = 0.5;
var cy:Number = 0.5;
var t:Number = (aby * (cx - ax) - abx * (cy - ay)) / tDen;
out.x = cx + t * cdx;
out.y = cy + t * cdy;
return out;
}
override public function get color():uint { return _color; }
override public function set color(value:uint):void { super.color = _color = value; }
override public function set texture(value:Texture):void
{
if (super.texture === value)
return;
super.texture = value;
updateVertices();
}
public function get ratio():Number { return _ratio; }
public function set ratio(value:Number):void
{
if (_ratio != value)
{
_ratio = value;
updateVertices();
}
}
public static function fromTexture(texture:Texture):QuadSection
{
var quadPie:QuadSection = new QuadSection(texture.width, texture.height);
quadPie.texture = texture;
return quadPie;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.