Scaling with BitmapData - apache-flex

I am working on an application that will allow a user to scale an image. The issue that I am having with the method below is that the scaling is always taking place on the previous scale point.
For example: If I scale the image up one and then scale the image down one. I have to scale down twice to get it back to the point I want it to be.
Any help with this is greatly appreciated.
Here is my current code:
private var sourceBMD:BitmapData = testImage.source as BitmapData
private var matrixScaleX:Number = 1;
private var matrixScaleY:Number = 1;
private var baseScaleX:Number = .05;
private var baseScaleY:Number = .05;
private function sourceZoom(zoomType:Boolean = false):void{
var matrix:Matrix = new Matrix();
var matriximage:BitmapData;
if(zoomType){
matrixScaleX = matrixScaleX + baseScaleX;
matrixScaleY = matrixScaleY + baseScaleY;
matrix.a = matrixScaleX;
matrix.d = matrixScaleY
}else{
matrixScaleX = matrixScaleX - baseScaleX;
matrixScaleY = matrixScaleY - baseScaleY;
matrix.a = matrixScaleX;
matrix.d = matrixScaleY;
}
matriximage = new BitmapData(sourceBMD.width, sourceBMD.height, false, 0x0000000);
trace('MatrixScaleX: ' + matrixScaleX);
trace('MatrixScaleY: ' + matrixScaleY);
trace('BaseScaleX: ' + baseScaleX);
trace('BaseScaleY: ' + baseScaleY);
trace('Matrix: ' + ObjectUtil.toString(matrix));
matriximage.draw(sourceBMD, matrix);
testImage.source = matriximage;
}

That looks fine, I'd suspect that the problem lies with your input or the place this is getting called.
In order for it to work, events need to happen like this in your code:
capture input -> scale image -> draw image.
Since you appear to be setting the image to draw at the end of this function, I would check that this function is being called after the input has finished processing.
Can you confirm that's what's happening?

Related

How do you break a line of text within InDesign scripts?

So I'm new to InDesign CC scripting, but I really just need a very simple solution, or at least I hope that it's a simple solution. I have a script for adding a watermark to a document for export, however i'd like it to be on two lines and take up more space on the page rather than just one line. Below is the script I'm using:
var myDoc = app.activeDocument,
myPdfExportPreset = "[High Quality Print]",
myPdfFile = File(myDoc.fullName.fsName.replace(/.indd$/i, "") + ".pdf");
app.scriptPreferences.measurementUnit = MeasurementUnits.INCHES
var docHeight = myDoc.documentPreferences.pageHeight
var docWidth = myDoc.documentPreferences.pageWidth
with(myDoc.watermarkPreferences)
{
watermarkVisibility = true;
watermarkDoPrint = true;
watermarkDrawInBack = false;
watermarkText = "I would like the code to split between the word split and between";
watermarkFontFamily = "Helvetica";
watermarkFontStyle = "Bold";
watermarkFontPointSize = Math.round(docWidth * 7);
watermarkFontColor = [0, 0, 0];
watermarkOpacity = 15;
watermarkRotation = -25;
watermarkHorizontalPosition = WatermarkHorizontalPositionEnum.watermarkHCenter;
watermarkHorizontalOffset = 0;
watermarkVerticalPosition = WatermarkVerticalPositionEnum.watermarkVCenter;
watermarkVerticalOffset = 0;
}
If anyone has an idea on how to insert a line break, I'm not sure if it's like html where you can just <br> and be done with it, but that's kind of what I'm looking for, if that makes sense. Thanks so much in advance!

Show ToolTip on Series data on mouseover , in System.Web.UI.DataVisualization.Charting

I am working with System.Web.UI.DataVisualization.Charting to create some line charts. I want to show tooltips(x and y value of the datapoint) when mouse over on a data point of a series.
As shown in the chart image, i want a tooltip when mouse is hovered on the red circle.
chart image
I added series.ToolTip method but , its not working.
here is my createSeries meothod
private System.Web.UI.DataVisualization.Charting.Series CreateSeries(List<X> xAxisData, List<Y> yAxisdata)
{
// Chart Series
System.Web.UI.DataVisualization.Charting.Series _series =
new System.Web.UI.DataVisualization.Charting.Series(this.SeriesNameList[this.seriesCount]);
_series.ChartType = this.ChartType;
// Bind the data
_series.Points.DataBindXY(xAxisData, yAxisdata);
// Set Default Properties
_series.Font = this.GetFontForSeries();
_series.LabelForeColor = this.GetLabelColor();
// Add Transparent Marker to increase mouse area for ToolTip
_series.MarkerStyle = System.Web.UI.DataVisualization.Charting.MarkerStyle.Circle;
_series.MarkerSize = 7;
_series.ToolTip = "hello";
//// Smart Labels
_series.SmartLabelStyle.Enabled = true;
_series.SmartLabelStyle.MinMovingDistance = 5;
_series.SmartLabelStyle.MaxMovingDistance = 50;
_series.SmartLabelStyle.MovingDirection =
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.Top |
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.TopLeft |
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.TopRight |
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.Bottom |
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.BottomLeft |
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.BottomRight |
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.Left |
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.Right |
System.Web.UI.DataVisualization.Charting.LabelAlignmentStyles.Center;
_series.SmartLabelStyle.IsOverlappedHidden = true;
_series.SmartLabelStyle.AllowOutsidePlotArea = System.Web.UI.DataVisualization.Charting.LabelOutsidePlotAreaStyle.Yes;
this.seriesCount++;
return _series;
}
private void InitializeChart()
{
this.Chart.IsMapEnabled = false;
this.Chart.RenderType = System.Web.UI.DataVisualization.Charting.RenderType.ImageTag;
this.Chart.ImageType = System.Web.UI.DataVisualization.Charting.ChartImageType.Png;
this.Chart.AntiAliasing = System.Web.UI.DataVisualization.Charting.AntiAliasingStyles.Graphics;
this.Chart.TextAntiAliasingQuality = System.Web.UI.DataVisualization.Charting.TextAntiAliasingQuality.High;
this.CreateTitle();
this.CreateLegends();
}
Can someone help me ?
I searched through some of the questios but couldn't find a solution.
You need to add the tooltip to the points.
Points.DataBindXY does not have a way of binding extended chart properties like tooltips. (Points.DataBind appears to, btw)
Source: http://blogs.msdn.com/b/alexgor/archive/2009/02/21/data-binding-ms-chart-control.aspx
So a workaround is to loop through your series points and add the tooltip manually to the points. You can do so using / modifying the code below. (#VALX and #VAL is one way of adding the XY coordinate without directly reading the value, another way would be to read the XY values directly)
// Bind the data
_series.Points.DataBindXY(xAxisData, yAxisdata);
// Set Tooltips
foreach(var point in _series.Points)
{
point.ToolTip = "(#VALX, #VAL)";
}
// Set Default Properties
_series.Font = this.GetFontForSeries();
_series.LabelForeColor = this.GetLabelColor();
Alternate way not using keywords:
// Bind the data
_series.Points.DataBindXY(xAxisData, yAxisdata);
// Set Tooltips
foreach(var point in _series.Points)
{
point.ToolTip = "(" + point.X + ", " + point.YValues[0] + ")";
}
// Set Default Properties
_series.Font = this.GetFontForSeries();
_series.LabelForeColor = this.GetLabelColor();

Add itemEditorValidatorFunction with Pop up window confirmation to Flexicious Grid

I am trying to have my Flexicious DataGrid ask for confirmation of a change when I click in a cell to edit a value and enter a new value which deviates from the original by a certain percentage. I cannot see an easy way to do this. Initially, I tried to write a itemEditorValidatorFunction, which returns a boolean. This works perfectly for a hard coded return value, but if I try to take the return value from the CloseEvent of an Alert, that value is ignored:
protected function validateGcCap(editor:UIComponent):Boolean{
var warningBPDiffVal:Number = Number(5);
var warningPerCentDiffVal:Number = Number(warningBPDiffVal / 1000);
var allowChange:Boolean = true;
var origGcCapVal:Number = Number(managerGrid.getCurrentEditingCell().text);
var newGcCapVal:Number = Number((editor as TextInput).text);
var diffVal:Number = Number(newGcCapVal - origGcCapVal);
if (origGcCapVal > newGcCapVal) {
diffVal = origGcCapVal - newGcCapVal;
}
if (diffVal > warningPerCentDiffVal) {
//Alert.show("you changed the gccap from " + origGcCapVal + " to " + newGcCapVal + " by " + diffVal);
function alertCloseHandler(event:CloseEvent):void{
if (event.detail == Alert.CANCEL) {
allowChange = false;
}
};
var alert:Alert = Alert.show("Are you sure that you want to update gcCap% by more than " + warningBPDiffVal + "bps?",
"Please Confirm", (Alert.OK | Alert.CANCEL),
this, alertCloseHandler);
}
return allowChange;
}
I also tried to write a itemEditor for the grids:FlexDataGridColumn, where I extended com.flexicious.controls.TextInput, but I could not work out which method to override. I wanted to override the method and only make the call to super if the Alert was clicked OK, but I could not see which method I should override. I tried override protected function onTextInput(textEvent:TextEvent):void, but this did nothing.
I would be grateful for any insight into this problem.
Not sure why someone decided to downvote your question, it seems quite valid. From looking at this, the best way for you would be to "undo" the edit when the user selects no on the box. If you have enableTrackChanges on, all you have to do is to remove that change from the dgGrid.changes collection and call dgGrid.refreshCells(). If you dont have enableTrackChanges, all you need to do is to update the dataProvider row with the old value, call dgGrid.refreshCells() and you should be set.
This is what works:
private function validateGcCap(editor:UIComponent):Boolean{
var warningBPDiffVal:Number = Number(5);
var cell:IFlexDataGridCell = managerGrid.getCurrentEditingCell();
var warningPerCentDiffVal:Number = Number(warningBPDiffVal / 1000);
var origGcCapVal:Number = Number(cell.text);
var newGcCapVal:Number = Number((editor as TextInput).text);
var diffVal:Number = Number(newGcCapVal - origGcCapVal);
if (origGcCapVal > newGcCapVal){
diffVal = origGcCapVal - newGcCapVal;
}
if (diffVal > warningPerCentDiffVal){
function alertCloseHandler(event:CloseEvent):void{
if (event.detail == Alert.CANCEL) {
IAParamsVO(cell.rowInfo.data).gcCapWrapper = origGcCapVal;
managerGrid.refreshCells();
}
}
Alert.show("Are you sure that you want to update gcCap% by more than "
+ warningBPDiffVal + "bps?", "Please Confirm", (Alert.OK | Alert.CANCEL),
this, alertCloseHandler);
}
return true;
}

localToGlobal not working - for reals though

I know there a bajillion threads on this topic, and maybe I am retarded, but this simply isn't working and I think I am missing something really key?
Lets say I have sprites _testTarget and _testParent nested like this.
_testParent = new Sprite();
this.addChild(_testParent);
_testTarget = new Sprite()
_testParent.addChild(_testParent);
And lets say I want to get the global cords of _testTarget. When I do localToGlobal I always get back 0,0 when I know for a fact its actual cords are like 200,100
var point:Point = new Point(_testTarget.x, _testTarget.y);
point = _testTarget.localToGlobal(point); // returns 0,0
var point:Point = new Point(_testTarget.x, _testTarget.y);
point = _testTarget.parent.localToGlobal(point); // returns 0,0
var point:Point = new Point(this.x, this.y);
point = this.localToGlobal(point); // returns 0,0
var point:Point = new Point(this.x, this.y);
point = this.parent.localToGlobal(point); // Breaks, "parent" is null
If it helps, this class/sprite instantiated inside of a sprite, inside of a sprite, inside of a sprite...etc and the reason its cords are 200,100 are because one of its parent containers is set to that - but I thought localToGlobal was supposed to go all the way to very top layer? Help?
You must have a problem somewhere else (I can't see anyone in the code you pasted, except for the one mentioned by TandemAdam).
This works as expected:
var _testParent:Sprite;
var _testTarget:Sprite;
var _yetAnotherParent:Sprite;
_yetAnotherParent = new Sprite();
this.addChild(_yetAnotherParent);
_testParent = new Sprite();
_yetAnotherParent.addChild(_testParent);
_testTarget = new Sprite()
_testParent.addChild(_testTarget);
_testParent.y = 100;
_yetAnotherParent.y = -500;
var point:Point = new Point(_testTarget.x, _testTarget.y);
point = _testTarget.parent.localToGlobal(point);
trace(point); // (x=0, y=-400)
As a rule of thumb, when translating between coordinate spaces, the object on which you want to call localToGlobal or globalToLocal is almost always the parent of the object you're interested in, because an object's x and y are offsets relative to its parent.
In your first block, this wont work:
_testParent.addChild(_testParent);
Because you can't add a display object as its own child.
This also works as expected -- returns (x=600, y=600). So it looks like there must be something else wrong with your app?
var a:Sprite = new Sprite();
var b:Sprite = new Sprite();
var c:Sprite = new Sprite();
var d:Sprite = new Sprite();
var e:Sprite = new Sprite();
a.x = b.x = c.x = d.x = e.x = 100;
a.y = b.y = c.y = d.y = e.y = 100;
this.addChild(a);
a.addChild(b);
b.addChild(c);
c.addChild(d);
d.addChild(e);
var point:Point = new Point(e.x, e.y);
point = e.localToGlobal(point);
trace(point);
So, props to all you guys suggesting that I look through the rest of my code because it turns out that yes, I am retarded haha. On a hunch (from your advise) I found that the problem had nothing to do with localToGlobal - the problem was that I forgot to wait for the stage to be ready. The solution was very simple:
public function ClassConstructorOrWhatever(){
addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
_testParent = new Sprite();
this.addChild(_testParent);
_testTarget = new Sprite()
_testParent.addChild(_testTarget);
}
private function handleAddedToStage(e:Event):void {
var point:Point = new Point(_testTarget .x, _testTarget .y);
point = _testTarget.localToGlobal(point); // RETURNS 200,100!!!! :)
}
So yeah, that was the problem - thanks again guys!

Flex/ActionScript - rotate Sprite around its center

I have created a Sprite in Actionscript and rendered it to a Flex Canvas. Suppose:
var fooShape:Sprite = new FooSpriteSubclass();
fooCanvas.rawChildren.addChild(myshape);
//Sprite shape renders on screen
fooShape.rotation = fooNumber;
This will rotate my shape, but seems to rotate it around the upper-left
point of its parent container(the canvas).
How can I force the Sprite to rotate about is own center point? I could obviously
write code to calculate the rotation, and then have it re-render, but I think there
must be a built-in way to do this, and certainly do not want to 'reinvent the wheel'
if possible.
I am using FlexBuilder, and therefore do not have access to the full Flash API.
Thank you much!
The following steps are required to rotate objects based on a reference point (using Matrix object and getBounds):
Matrix translation (moving to the reference point)
Matrix rotation
Matrix translation (back to original position)
For example to rotate an object 90 degrees around its center:
// Get the matrix of the object
var matrix:Matrix = myObject.transform.matrix;
// Get the rect of the object (to know the dimension)
var rect:Rectangle = myObject.getBounds(parentOfMyObject);
// Translating the desired reference point (in this case, center)
matrix.translate(- (rect.left + (rect.width/2)), - (rect.top + (rect.height/2)));
// Rotation (note: the parameter is in radian)
matrix.rotate((90/180)*Math.PI);
// Translating the object back to the original position.
matrix.translate(rect.left + (rect.width/2), rect.top + (rect.height/2));
Key methods used:
Matrix.rotate
Matrix.translate
DisplayObject.getBounds
Didn't have much luck with the other examples. This one worked for me. I used it on a UIComponent.
http://www.selikoff.net/2010/03/17/solution-to-flex-image-rotation-and-flipping-around-center/
private static function rotateImage(image:Image, degrees:Number):void {
// Calculate rotation and offsets
var radians:Number = degrees * (Math.PI / 180.0);
var offsetWidth:Number = image.contentWidth/2.0;
var offsetHeight:Number = image.contentHeight/2.0;
// Perform rotation
var matrix:Matrix = new Matrix();
matrix.translate(-offsetWidth, -offsetHeight);
matrix.rotate(radians);
matrix.translate(+offsetWidth, +offsetHeight);
matrix.concat(image.transform.matrix);
image.transform.matrix = matrix;
}
Actually I had to add this code to make above solutions work for me.
private var _rotateCount = 0;
var _origginalMatrix:Matrix=new Matrix();
.........
if (_rotateCount++ >= 360 / angleDegrees)
{
myObject.transform.matrix = _origginalMatrix;
_rotateCount = 0;
return;
}
var matrix:Matrix = myObject.transform.matrix;
....
Without that after some long time rotated object slowly moves somewhere right top.
An alternative solution is to put your object inside another View, move it so that your image's center is at the container's top-left corner, and then rotate the container.
import spark.components.*;
var myContainer:View = new View();
var myImage:Image = new Image();
myContainer.addElement(myImage);
myImage.x = myImage.width / -2;
myImage.y = myImage.height / -2;
addElement(myContainer);
myContainer.rotation = whateverAngle;
One issue might be that the width of the image isn't know at the moment it is created, so you might want to find a way around that. (Hardcode it, or see if myImage.preliminaryWidth works)
/**
* Rotates the object based on its center
* Parameters: #obj => the object to rotate
* # rotation => angle to rotate
* */
public function RotateAroundCenter(obj:Object, rotation:Number):void
{
var bound:Rectangle = new Rectangle();
// get the bounded rectangle of objects
bound = obj.getRect(this);
// calculate mid poits
var midx1:Number = bound.x + bound.width/2;
var midy1:Number = bound.y + bound.height/2;
// assign the rotation
obj.rotation = rotation;
// assign the previous mid point as (x,y)
obj.x = midx1;
obj.y = midy1;
// get the new bounded rectangle of objects
bound = obj.getRect(this);
// calculate new mid points
var midx2:Number = bound.x + bound.width/2;
var midy2:Number = bound.y + bound.height/2;
// calculate differnece between the current mid and (x,y) and subtract
//it to position the object in the previous bound.
var diff:Number = midx2 - obj.x;
obj.x -= diff;
diff = midy2 - obj.y;
obj.y -= diff;
}
//////////////////
Usage:
you can use the above function as described below,
var img:Canvas = new Canvas()
RotateAroundCenter(img, rotation);
This will help you
REf: http://subashflash.blogspot.in/2010/08/rotation-of-object-based-on-center.html
If you want to rotate around the center, merely center the asset inside your sprite by setting the internal assets x and y to half of the width and height of the asset. This swill center your content and allow it to rotate around a center point.
An example of runtime loaded assets is as follows:
var loader:Loader = new Loader():
var request:URLRequest = new URLRequest(path/to/asset.ext);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _onLoaderComplete);
loader.load(request);
private function _onLoaderComplete(e:Event):void
{
var mc:MovieClip = e.target.content as MovieClip;
mc.x = -mc.width * 0.5;
mc.y = -mc.height * 0.5;
mc.rotation = 90;
addChild(mc);
}

Resources