Conditional Line Graph using Open Flash Charts - asp.net

I am using Open Flash Charts v2. I have been trying to make Conditional line graph. But I couldn't find any straight forward way, example or any class for producing Conditional charts.
Example of Conditional Graph
So I thought to use some techniques to emulate conditional graph ,I made separate Line object for values above limit range and then this line is used to overlap the plotted line.
This techniques works some what ok ,but there are problems with it,
How to color or place the conditional colored line exactly above the limit.
Remove tooltip and dot from limit line.
Tooltip of conditional line(red) and plotted line(green) are both shown ,I only need tooltip of green line.
Conditional Line Graph Problem illustrated
Source Code: // C#
var chart = new OpenFlashChart.OpenFlashChart();
var data1 = new List<double?> { 1, 3, 4, 5, 2, 1, 6, 7 };//>4=
var overlap = new List<double?> { null, null, 4, 5, null, null, null, null };
var overlap2 = new List<double?> { null, null, null, null, null, null, 6, 7 };
var limitData = new List<double?> { 4, 4, 4, 4, 4, 4, 4, 4 };
var line1 = new Line();
line1.Values = data1;
//line1.HaloSize = 0;
line1.Width = 2;
line1.DotSize = 5;
line1.DotStyleType.Tip = "#x_label#<br>#val#";
line1.Colour = "#37c855";
line1.Tooltip = "#val#";
var overLine = new Line();
overLine.Values = overlap;
//overLine.HaloSize = 0;
overLine.Width = 2;
overLine.DotSize = 5;
overLine.DotStyleType.Tip = "#x_label#<br>#val#";
overLine.Colour = "#d81417";
overLine.Tooltip = "#val#";
var overLine2 = new Line();
overLine2.Values = overlap2;
//overLine2.HaloSize = 0;
overLine2.Width = 2;
overLine2.DotSize = 5;
//overLine2.DotStyleType.Tip = "#x_label#<br>#val#";
//overLine2.DotStyleType.Type = DotType.DOT;
overLine2.Colour = "#d81417";
overLine2.Tooltip = "#val#";
var limit = new Line();
limit.Values = limitData;
limit.Width = 2;
limit.Colour = "#ff0000";
limit.HaloSize = -1;
limit.DotSize = -1;
// limit.DotStyleType.Tip = "";
limit.DotStyleType.Type = null;
//limit.Tooltip = "";
chart.AddElement(line1);
chart.AddElement(overLine);
chart.AddElement(overLine2);
chart.AddElement(limit);
chart.Y_Legend = new Legend("Experiment");
chart.Title = new Title("Conditional Line Graph");
chart.Y_Axis.SetRange(0, 10);
chart.X_Axis.Labels.Color = "#e43456";
chart.X_Axis.Steps = 4;
chart.Tooltip = new ToolTip("#val#");
chart.Tooltip.Shadow = true;
chart.Tooltip.Colour = "#e43456";
chart.Tooltip.MouseStyle = ToolTipStyle.CLOSEST;
Response.Clear();
Response.CacheControl = "no-cache";
Response.Write(chart.ToPrettyString());
Response.End();
Note:
I have already downloaded the OFC (Open Flash Charts) source ,If I modify the OFC Line.as source than how would I be able to generate json for the changed graph ? ,b/c I'm currently using .Net library for the json generation for OFC charts,please do let me know this also.
Update:
I have modified the source code on the advice of David Mears I'm using FlashDevelop for ActionScript.
P.S: I'm open for ideas if another library can do this job.

If you don't mind a little rebuilding, you can get the source of OFC here and modify the Line.solid_line() method in open-flash-chart/charts/Line.as to do this fairly easily.
In order to set the extra chart details through JSON using the .NET library, you'll also have to modify OpenFlashChart/LineBase.cs to add alternative colour and boundary properties. I'm not hugely familiar with .NET, but based on the existing properties you might add something like this:
private double boundary;
private string altcolour;
[JsonProperty("boundary")]
public virtual double Boundary
{
set { this.boundary = value; }
get { return this.boundary; }
}
[JsonProperty("alt-colour")]
public virtual string AltColour
{
set { this.altcolour = value; }
get { return this.altcolour; }
}
Then I believe the following should work in Line.as:
public function solid_line(): void {
var first:Boolean = true;
var i:Number;
var tmp:Sprite;
var x:Number;
var y:Number;
var last_e:Element;
var ratio:Number;
for ( i=0; i < this.numChildren; i++ ) {
// Step through every child object.
tmp = this.getChildAt(i) as Sprite;
// Only include data Elements, ignoring extra children such as line masks.
if( tmp is Element )
{
var e:Element = tmp as Element;
if( first )
{
if (this.props.get('alt-colour') != Number.NEGATIVE_INFINITY) {
if (e._y >= this.props.get_colour('boundary'))
{
// Line starts below boundary, set alt line colour.
this.graphics.lineStyle( this.props.get_colour('width'), this.props.get_colour('alt-colour') );
}
else
{
// Line starts above boundary, set normal line colour.
this.graphics.lineStyle( this.props.get_colour('width'), this.props.get_colour('colour') );
}
}
// Move to the first point.
this.graphics.moveTo(e.x, e.y);
x = e.x;
y = e.y;
first = false;
}
else
{
if (this.props.get('alt-colour') != Number.NEGATIVE_INFINITY) {
if (last_e._y < this.props.get_colour('boundary') && e._y >= this.props.get_colour('boundary'))
{
// Line passes below boundary. Draw first section and switch to alt colour.
ratio = (this.props.get_colour('boundary') - last_e._y) / (e._y - last_e._y);
this.graphics.lineTo(last_e.x + (e.x - last_e.x) * ratio, last_e.y + (e.y - last_e.y) * ratio);
this.graphics.lineStyle( this.props.get_colour('width'), this.props.get_colour('alt-colour') );
}
else if (last_e._y >= this.props.get_colour('boundary') && e._y < this.props.get_colour('boundary'))
{
// Line passes above boundary. Draw first section and switch to normal colour.
ratio = (this.props.get_colour('boundary') - last_e._y) / (e._y - last_e._y);
this.graphics.lineTo(last_e.x + (e.x - last_e.x) * ratio, last_e.y + (e.y - last_e.y) * ratio);
this.graphics.lineStyle( this.props.get_colour('width'), this.props.get_colour('colour') );
}
}
// Draw a line to the next point.
this.graphics.lineTo(e.x, e.y);
}
last_e = e;
}
}
if ( this.props.get('loop') ) {
// close the line loop (radar charts)
this.graphics.lineTo(x, y);
}
}
With the new open-flash-chart.swf, you should be able to just set your new properties on line1:
line1.Boundary = 4;
line1.AltColour = "#d81417";

Related

Retrieving Signature from Point-Array

I'm trying to retrieve the Points of a SignaturePad to redisplay the signature.
public static void GetPoints(string airid, SignaturePadView padView)
{
List<Strokes> DBStrokes = SqLiteHelper.conn.Query<Strokes>("select * from Strokes where airid = ? order by PointSequence", airid);
List<Point> points = new List<Point>();
foreach (Strokes stroke in DBStrokes)
points.Add(new Point { X = stroke.pointx, Y = stroke.pointy });
padView.Points = points.AsEnumerable();
}
The array points is filled correctly, but the padView.Points shows as result
{Xamarin.Forms.Point[0]}.
I've found the Problem. It seems that it is only possible to set the Points property when the Signaturepad is visible. so my new code looks like this:
List<Strokes> DBStrokes = SqLiteHelper.conn.Query<Strokes>("select * from Strokes where airid = ? order by PointSequence", formField.pictFile);
Xamarin.Forms.Point[] points = new Point[DBStrokes.Count];
for (int i = 0; i < DBStrokes.Count; i++)
points[i] = new Point(DBStrokes[i].pointx, DBStrokes[i].pointy);
var originalPoints = JsonConvert.SerializeObject(points);
Xamarin.Forms.Point[] points4View = JsonConvert.DeserializeObject<Xamarin.Forms.Point[]>(originalPoints);
signatureView.Points = points4View;
Now i'm using the Handle_MeasureInvalidated - Event to run this code.

Is it possible to reset an entire class without looping through the elements

I have a 12 month calendar. When a user clicks on the month I am calling my function toggleZoom
$monthNode.onclick = function(){toggleZoom(this)};
at the moment I cam controlling the zoom using this JS:
function toggleZoom(month) {
var zoomed = window.getComputedStyle(month).zIndex;
var m = document.getElementsByClassName("month");
for(var i = 0; i < m.length; i++)
{
m[i].style ='' ;
}
if (zoomed != 2) {
month.style = 'transform:scale(1.1,1.1); z-index:2';
}
}
Is there a cleaner way (one line of code, maybe) to reset all of my month classes to un-zoomed without looping through all 12? Something like document.getElementsByClassName("month").style=""
You can use the map() function to loop through your array in a single line without creating a for loop, like so: m.map(function(mo){ mo.style = ''; });
function toggleZoom(month) {
var zoomed = window.getComputedStyle(month).zIndex;
var m = document.getElementsByClassName("month");
m.map(function(mo){ mo.style = ''; });
if (zoomed != 2) {
month.style = 'transform:scale(1.1,1.1); z-index:2';
}
}
Or, using ES6's arrow function:
function toggleZoom(month) {
var zoomed = window.getComputedStyle(month).zIndex;
var m = document.getElementsByClassName("month");
m.map(mo => mo.style = '');
if (zoomed != 2) {
month.style = 'transform:scale(1.1,1.1); z-index:2';
}
}

Get physicsBody position when collide

I seem to have some problems with getting the position of a physicsBody.
I want to set the position of a physicsBody (bodyA) to the position of an other physicsBody (bodyB), when this one collides with a third one.
I tried using _bodyA.position = _bodyB.position; but this doesn't work.
The problem is, that the physicsBody I want to get the position of is moving around all the time. So I might need a method that checks the position of the physicsBody in every frame and when the physicsBody collides, the method returns the CGPoint.
This might be a simple task, but I can't figure it out. Thanks for help!
I did up a quick sample project for you to take a look at. You can fine tune the code to fit your exact needs but it will show you how to do what you asked.
Tap anywhere on the screen to launch the blue square into the red square. Once the two make contact, the green square's position will change to the red square.
Another alternative to the way I wrote the code is to have the sprites added to an array but that all depends on how your code is set up.
Side note - you cannot update a sprite's position in the didBeginContact: section because it will not work. That is why I created the CGPoint to store the position and update Object C during the next cycle in update:
Here is the code:
#import "MyScene.h"
typedef NS_OPTIONS(uint32_t, CNPhysicsCategory)
{
Category1 = 1 << 0,
Category2 = 1 << 1,
Category3 = 1 << 2,
};
#interface MyScene()<SKPhysicsContactDelegate>
#end
#implementation MyScene
{
SKSpriteNode *objectA;
SKSpriteNode *objectB;
SKSpriteNode *objectC;
CGPoint newPositionForObjectC;
}
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
self.physicsWorld.contactDelegate = self;
objectA = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(30, 30)];
objectA.position = CGPointMake(110, 20);
objectA.name = #"objectA";
objectA.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:objectA.size];
objectA.physicsBody.categoryBitMask = Category1;
objectA.physicsBody.collisionBitMask = Category2;
objectA.physicsBody.contactTestBitMask = Category2;
objectA.physicsBody.affectedByGravity = NO;
[self addChild:objectA];
objectB = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(30, 30)];
objectB.position = CGPointMake(100, 200);
objectB.name = #"objectB";
objectB.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:objectB.size];
objectB.physicsBody.categoryBitMask = Category2;
objectB.physicsBody.collisionBitMask = Category1;
objectB.physicsBody.contactTestBitMask = Category1;
objectB.physicsBody.affectedByGravity = NO;
[self addChild:objectB];
objectC = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(30, 30)];
objectC.position = CGPointMake(250, 250);
objectC.name = #"objectC";
objectC.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:objectC.size];
objectC.physicsBody.categoryBitMask = Category3;
objectC.physicsBody.collisionBitMask = 0;
objectC.physicsBody.contactTestBitMask = 0;
objectC.physicsBody.affectedByGravity = NO;
[self addChild:objectC];
newPositionForObjectC = CGPointMake(0, 0);
}
return self;
}
- (void)didBeginContact:(SKPhysicsContact *)contact
{
uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
if (collision == (Category1 | Category2))
{
newPositionForObjectC = CGPointMake(contact.bodyA.node.position.x, contact.bodyA.node.position.y);
}
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[objectA.physicsBody applyImpulse:CGVectorMake(0, 5)];
}
-(void)update:(CFTimeInterval)currentTime
{
if(newPositionForObjectC.x > 0)
{
objectC.position = newPositionForObjectC;
newPositionForObjectC = CGPointMake(0, 0);
}
}
#end

ActionScript 2 character selection

I haven't been able to make a character selection in ActionScript 2 so what is an example that, if I click on this button, a movieclip comes out in this frame?
Frame 1:
movieClip1.alpha = 0;
movieClip1.stop();
movieClip2.alpha = 0;
movieClip2.stop();
movieClip3.alpha = 0;
movieClip3.stop();
button1.onPress = function() {
movieClip1.alpha = 100;
movieClip1.play();
}
button2.onPress = function() {
movieClip2.alpha = 100;
movieClip2.play();
}
button3.onPress = function() {
movieClip3.alpha = 100;
movieClip3.play();
}
try something like the below. I haven;t tested this so it prob won;t compile but it'll be very close. Basically put this on a single empty frame on the main timeline. make sure you have button and character movieclips all with export settings and linkage identifiers set. Modify code below and see what happens.
var numButtons:Number = 10; //number of buttons you want
var buttonMovieClipName:String = "button"; //linkage identifier of button
var startX:Number = 10; //start x position
var startY:Number = 500; //start y position
var dist:Number = 10; //distance between buttons
var characters:Array = {"A","B","C","D"}; //linkage names of your characters
var currentChar:MovieClip = null;
for(var i:Number = 0; i < numButtons; i++)
{
this.attachMovie("button", "button"+i, this.getNextHighestDepth());
this["button"+i]._x = startX + (i*(dist+this["button"+i]._width]));
this["button"+i]._y = startY;
this["button"+i].character = characters[i];
this["button"+i].onPress = displayCharacter;
}
function displayCharacter():void
{
var par = this._parent;
//remove previous character on stage
if(currentChar != null)
{
removeMovieClip(par[currentChar]);
}
par.attachMovie(this.character, this.character, par.getNextHighestDepth()); //atach character
par[this.character]._x = 400; //set to whatever
par[this.character]._y = 300; //set to whatever
currentChar = this.character; //set current character to this
}

How to draw a continuous curved line from 3 given points at a time

I am trying to draw a continuous curved line in flash. There are many methods but none of the ones I have found so far quite fit my requirements. First of all, I want to use the flash graphic api's curveTo() method. I DO NOT want to simulate a curve with hundreds of calls to lineTo() per curved line segment. It is my experience and understanding that line segments are processor heavy. Flash's quadratic bezier curve should take less CPU power. Please challenge this assumption if you think I am wrong.
I also do not want to use a pre-made method that takes the entire line as an argument (eg mx.charts.chartClasses.GraphicsUtilities.drawPolyline()).
The reason is that I will need to modify the logic eventually to add decorations to the line I am drawing, so I need something I understand at its lowest level.
I have currently created a method that will draw a curve given 3 points, using the mid-point method found here.
Here is a picture:
The problem is that the lines do not actually curve through the "real" points of the line (the gray circles). Is there a way using the power of math that I can adjust the control point so that the curve will actually pass through the "real" point? Given only the current point and its prev/next point as arguments? The code to duplicate the above picture follows. It would be great if I could modify it to meet this requirement (note the exception for first and last point).
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.geom.Point;
[SWF(width="200",height="200")]
public class TestCurves extends Sprite {
public function TestCurves() {
stage.scaleMode = "noScale";
var points:Array = [
new Point(10, 10),
new Point(80, 80),
new Point(80, 160),
new Point(20, 160),
new Point(20, 200),
new Point(200, 100)
];
graphics.lineStyle(2, 0xFF0000);
var point:Point = points[0];
var nextPoint:Point = points[1];
SplineMethod.drawSpline(graphics, point, null, nextPoint);
var prevPoint:Point = point;
var n:int = points.length;
var i:int;
for (i = 2; i < n + 1; i++) {
point = nextPoint;
nextPoint = points[i]; //will eval to null when i == n
SplineMethod.drawSpline(graphics, point, prevPoint, nextPoint);
prevPoint = point;
}
//straight lines and vertices for comparison
graphics.lineStyle(2, 0xC0C0C0, 0.5);
graphics.drawCircle(points[0].x, points[0].y, 4);
for (i = 1; i < n; i++) {
graphics.moveTo(points[i - 1].x, points[i - 1].y);
graphics.lineTo(points[i].x, points[i].y);
graphics.drawCircle(points[i].x, points[i].y, 4);
}
}
}
}
import flash.display.Graphics;
import flash.geom.Point;
internal class SplineMethod {
public static function drawSpline(target:Graphics, p:Point, prev:Point=null, next:Point=null):void {
if (!prev && !next) {
return; //cannot draw a 1-dimensional line, ie a line requires at least two points
}
var mPrev:Point; //mid-point of the previous point and the target point
var mNext:Point; //mid-point of the next point and the target point
if (prev) {
mPrev = new Point((p.x + prev.x) / 2, (p.y + prev.y) / 2);
}
if (next) {
mNext = new Point((p.x + next.x) / 2, (p.y + next.y) / 2);
if (!prev) {
//This is the first line point, only draw to the next point's mid-point
target.moveTo(p.x, p.y);
target.lineTo(mNext.x, mNext.y);
return;
}
} else {
//This is the last line point, finish drawing from the previous mid-point
target.moveTo(mPrev.x, mPrev.y);
target.lineTo(p.x, p.y);
return;
}
//draw from mid-point to mid-point with the target point being the control point.
//Note, the line will unfortunately not pass through the actual vertex... I want to solve this
target.moveTo(mPrev.x, mPrev.y);
target.curveTo(p.x, p.y, mNext.x, mNext.y);
}
}
Later I will be adding arrows and things to the draw method.
I think you're looking for a Catmull-Rom spline. I've googled an AS3 implementation for you but haven't tried it so use at your own discretion:
http://actionsnippet.com/?p=1031
Ok, the Catmull-Rom spline suggestion is a good one but not exactly what I am looking for.
The example from the link provided was a good starting point, but a bit inflexible. I have taken it and modified my original source code to use it. I am posting this as an answer because I think it is more modular and easier to understand than Zevan's blog post (no offense Zevan!). The following code will display the following image:
Here is the code:
package {
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.geom.Point;
[SWF(width="300",height="300")]
public class TestCurves extends Sprite {
public function TestCurves() {
stage.scaleMode = "noScale";
//draw a helpful grid
graphics.lineStyle(1, 0xC0C0C0, 0.5);
for (var x:int = 0; x <= 300; x += 10) {
graphics.moveTo(x, 0);
graphics.lineTo(x, 300);
graphics.moveTo(0, x);
graphics.lineTo(300, x);
}
var points:Array = [
new Point(40, 20),
new Point(120, 80),
new Point(120, 160),
new Point(60, 160),
new Point(60, 200),
new Point(240, 150),
new Point(230, 220),
new Point(230, 280)
];
SplineMethod.setResolution(5);
graphics.lineStyle(2, 0xF00000);
graphics.moveTo(points[0].x, points[0].y);
var n:int = points.length;
var i:int;
for (i = 0; i < n - 1; i++) {
SplineMethod.drawSpline(
graphics,
points[i], //segment start
points[i + 1], //segment end
points[i - 1], //previous point (may be null)
points[i + 2] //next point (may be null)
);
}
//straight lines and vertices for comparison
graphics.lineStyle(2, 0x808080, 0.5);
graphics.drawCircle(points[0].x, points[0].y, 4);
for (i = 1; i < n; i++) {
graphics.moveTo(points[i - 1].x, points[i - 1].y);
graphics.lineTo(points[i].x, points[i].y);
graphics.drawCircle(points[i].x, points[i].y, 4);
}
}
}
}
import flash.display.Graphics;
import flash.geom.Point;
internal class SplineMethod {
//default setting will just draw a straight line
private static var hermiteValues:Array = [0, 0, 1, 0];
public static function setResolution(value:int):void {
var resolution:Number = 1 / value;
hermiteValues = [];
for (var t:Number = resolution; t <= 1; t += resolution) {
var h00:Number = (1 + 2 * t) * (1 - t) * (1 - t);
var h10:Number = t * (1 - t) * (1 - t);
var h01:Number = t * t * (3 - 2 * t);
var h11:Number = t * t * (t - 1);
hermiteValues.push(h00, h10, h01, h11);
}
}
public static function drawSpline(target:Graphics, segmentStart:Point, segmentEnd:Point, prevSegmentEnd:Point=null, nextSegmentStart:Point=null):void {
if (!prevSegmentEnd) {
prevSegmentEnd = segmentStart;
}
if (!nextSegmentStart) {
nextSegmentStart = segmentEnd;
}
var m1:Point = new Point((segmentEnd.x - prevSegmentEnd.x) / 2, (segmentEnd.y - prevSegmentEnd.y) / 2);
var m2:Point = new Point((nextSegmentStart.x - segmentStart.x) / 2, (nextSegmentStart.y - segmentStart.y) / 2);
var n:int = hermiteValues.length;
for (var i:int = 0; i < n; i += 4) {
var h00:Number = hermiteValues[i];
var h10:Number = hermiteValues[i + 1];
var h01:Number = hermiteValues[i + 2];
var h11:Number = hermiteValues[i + 3];
var px:Number = h00 * segmentStart.x + h10 * m1.x + h01 * segmentEnd.x + h11 * m2.x;
var py:Number = h00 * segmentStart.y + h10 * m1.y + h01 * segmentEnd.y + h11 * m2.y;
target.lineTo(px, py);
}
}
}
This is not a perfect solution. But unfortunately, I cannot piece together how to accomplish what I want using curveTo(). Note that GraphicsUtilities.drawPolyLine() does accomplish what I am attempting to do--the problem there is that it is inflexible and I cannot parse the code (more importantly, it doesn't appear to properly draw acute angles--correct me if I am wrong). If anyone can provide any insight, please post. For now, the above is my answer.
I code this, I think it may help:
SWF: http://dl.dropbox.com/u/2283327/stackoverflow/SplineTest.swf
Code: http://dl.dropbox.com/u/2283327/stackoverflow/SplineTest.as
I left a lot of comments on the code. I wish it helps!
Here is the theory behind the code:
A and C are the first and last point, B is the "control point" in AS3 you can draw the curve like this:
graphics.moveTo(A.x, A.y);
graphics.curveTo(B.x, B.y, C.x, C.y);
Now, D is the mid-point of the vector AC. And the mid-point of DB is the mid-point of the curve. Now what I did in the code was to move B exactly to D+DB*2 so, if you draw the curve using that point as control point, the mid-point of the curve will be B.
PS: Sorry for my poor Enlgish

Resources