I have a function that draws a string over BitmapData. The problem is, the TextFormat specified does not affect the text written on the image. The size, font I specify in the text format is not used at all.
function drawString(target:BitmapData,text:String,color:uint,x:Number,y:Number):void {
var channelName:TextField = new TextField();
channelName.textColor=color;
channelName.antiAliasType = AntiAliasType.ADVANCED;
channelName.alpha=1.0;
var txtFormat:TextFormat = new TextFormat("Verdana",25,color,true);
txtFormat.size=Number(25);
txtFormat.font="Verdana";
txtFormat.bold=true;
channelName.setTextFormat(txtFormat);
channelName.text = text;
channelName.defaultTextFormat = txtFormat;
channelName.cacheAsBitmap = true;
channelName.width=400;
var mat:Matrix = new Matrix();
mat.translate(x,y);
target.draw(channelName,mat);
}
How can I customize the text font and size drawn over the BitmapData?
Here is my code:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="640" height="400" creationComplete="init(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
[Embed(source='com/drawtext/Image.jpg')]
public var Picture:Class;
protected function init(event:FlexEvent):void
{
var bitmapData:BitmapData = new BitmapData(640, 400, true, 0xFF82DC);
bitmapData.draw(new Picture());
img.source = bitmapData;
drawString(bitmapData, "It is Yours!", 0xff0000, 70, 60);
}
protected function drawString(target:BitmapData,text:String,color:uint,x:Number,y:Number):void
{
var channelName:TextField = new TextField();
channelName.antiAliasType = AntiAliasType.ADVANCED;
var txtFormat:TextFormat = new TextFormat();
txtFormat.size = 35;
txtFormat.font = "Verdana";
txtFormat.bold = true;
channelName.defaultTextFormat = txtFormat;
channelName.width = 400;
channelName.height = 40;
channelName.textColor=color;
channelName.text = text;
var mat:Matrix = new Matrix();
mat.translate(x, y);
target.draw(channelName, mat);
}
]]>
</fx:Script>
<s:Image id="img" width="640" height="400"/>
</s:WindowedApplication>
The result:
Try setting text property before setting text format - and either use setTextFormat(...) or defaultTextFormat = ... not both
And you can also remove these lines too:
//does the same thing as new TextFormat("Verdana",25,color,true)
txtFormat.size=Number(25);
txtFormat.font="Verdana";
txtFormat.bold=true;
//only useful if you add textField to the display list (ie: if you did addChild(channelName)
channelName.cacheAsBitmap = true;
Related
I am developing mobile application for iOS and Android using Flex Mobile. On one of the views I am displaying StageWebView with a Google map and a spark List control to display another data. I am using the StageWebView in order to benefit from Google Maps JavaScript API v3. Example code below:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Clubs" backgroundAlpha="0"
viewActivate="view1_viewActivateHandler(event)"
backKeyPressed="view1_backKeyPressedHandler(event)"
initialize="view1_initializeHandler(event)">
<fx:Script>
<![CDATA[
import flash.sensors.Geolocation;
import mx.collections.ArrayCollection;
import mx.events.FlexEvent;
import spark.events.ViewNavigatorEvent;
private var myWebView:StageWebView;
[Bindable]
private var locations:ArrayCollection;
private var geolocation:Geolocation;
protected function view1_initializeHandler(event:FlexEvent):void
{
myWebView = new StageWebView();
myWebView.stage = this.stage;
}
protected function view1_viewActivateHandler(event:ViewNavigatorEvent):void
{
if(Geolocation.isSupported)
{
geolocation = new Geolocation();
geolocation.addEventListener(GeolocationEvent.UPDATE, onGeolocationChange);
}
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (myWebView) {
var point:Point = (new Point());
point = localToGlobal(point);
myWebView.viewPort = new Rectangle(point.x,point.y, stage.width,stage.height/3);
}
}
protected function view1_backKeyPressedHandler(event:Event):void
{
if (myWebView)
{
myWebView.viewPort = null;
myWebView = null;
}
navigator.popView();
}
protected function onGeolocationChange(event:GeolocationEvent):void
{
geolocation.removeEventListener(GeolocationEvent.UPDATE, onGeolocationChange);
locations = new ArrayCollection();
var location0:Object = new Object();
location0.lat = event.latitude;
location0.long = event.longitude;
locations.addItem(location0);
var location1:Object = new Object();
location1.lat = "42.697325";
location1.long = "23.315364";
locations.addItem(location1);
var location2:Object = new Object();
location2.lat = "42.696441";
location2.long = "23.321028";
locations.addItem(location2);
var url:String = "http://whozzzin.dev.mediatecture.at/gmapsformobile/map.php";
var counter:Number = 1;
for each(var location:Object in locations)
{
if(counter == 1)
{
url += "?locations["+counter.toString()+"][lat] = " + location.lat;
url += "&locations["+counter.toString()+"][long] = " + location.long;
}
else
{
url += "&locations["+counter.toString()+"][lat] = " + location.lat;
url += "&locations["+counter.toString()+"][long] = " + location.long;
}
counter++;
}
myWebView.loadURL(url);
}
]]>
</fx:Script>
<s:navigationContent>
<s:Button includeInLayout="{Capabilities.version.indexOf('IOS') > -1}" visible="{Capabilities.version.indexOf('IOS') > -1}" id="backButton" label="BACK" click="view1_backKeyPressedHandler(event)"/>
</s:navigationContent>
<s:List width="100%" contentBackgroundAlpha="0" id="placesList" dataProvider="{locations}" labelField="lat">
<s:layout>
<s:TileLayout columnWidth="{(width - 16)/3}"/>
</s:layout>
</s:List>
</s:View>
Currently the list is not visible because it appears behind the StageWebView. My question is how to position the List control exactly after the WebStageView.
You can use the top constraint:
<s:List width="100%" top="{stage.height/3}" id="placesList"
Edit: Put in a trace(stage.height); in your updateDisplayList function and also look at stage.stageHeight. Those values should help you figure out the exact top value to use in this case.
How I solved it:
I get the bottom of the WebStageView and convert a new point from global to local with x =0 and y = myWebView.bootom:
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (myWebView) {
var point:Point = (new Point(0,this.radiusDropDown.height));
point = localToGlobal(point);
myWebView.viewPort = new Rectangle(point.x,point.y, stage.width,stage.height/3);
this.placesList.y = globalToLocal(new Point(0,myWebView.viewPort.bottom)).y;
}
}
Please help me ㅠㅠ
I'm making ImageEditor. but I have a question for Image Rotating function.
When I load image and then Rotate it, Rotate function work very well.
But After resizing(width, height) loaded Image, rotate work ridiculously...
Pixed Image's width, height, It rotate only Image's content..
As a result, Quality of image go down...
This is screenshots.
Oh.. I can't post Images.. because reputation limit... :-<
http://blog.naver.com/hago89n/150164439917
Please visit my blog and confirm screenshots..
Can you understand my problem?
Um.. code is here
//resize button click handler
private function btn_resize_clickHandler(event:MouseEvent):void
{
image.width = parseInt(ti_width.text.toString());
image.height = parseInt(ti_height.text.toString());
}
//Rotate button click handler
private function btn_rotateCCW_clickHandler(event:MouseEvent):void
{//Rotate Counter ClockWise
var o_rotateimage:RotateImage = new RotateImage();
o_rotateimage.rotateCCW(image);
}
//Rotate function in RotateImage.as
public function rotateCCW(image:Image):void
{
m = new Matrix();
m.rotate(Math.PI/2);
m.tx = image.height;
var bd:BitmapData = new BitmapData(image.height as int, image.width as int);
bd.draw(image, m);
image.source = new Bitmap(bd);
}
I think you should do a matrix transformation for both operations.
If you just change the size of your Image object, it does not work fine in all situations.
Here is my code for this example.
//Application
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import com.imageeditor.RotateImage;
[Embed(source="/assets/img/chart.png")]
[Bindable]
public var chartPng:Class;
private var o_rotateimage:RotateImage = new RotateImage();
private function btn_resize_clickHandler(event:MouseEvent):void
{
o_rotateimage.scale(image, int(ti_width.text)/image.width, int(ti_height.text)/image.height);
}
private function btn_rotateCCW_clickHandler(event:MouseEvent):void
{
o_rotateimage.rotateCCW(image);
}
]]>
</fx:Script>
<s:VGroup x="10" y="10">
<s:HGroup>
<s:TextInput id="ti_width" text="300" width="40"/>
<s:TextInput id="ti_height" text="200" width="40"/>
<s:Button label="Resize" click="btn_resize_clickHandler(event)"/>
<s:Button label="Rotate" click="btn_rotateCCW_clickHandler(event)"/>
</s:HGroup>
<s:HGroup width="800" height="600" horizontalAlign="center" verticalAlign="middle">
<s:Image id="image" source="{chartPng}" width="600" height="400"/>
</s:HGroup>
</s:VGroup>
</s:Application>
//RotateImage.as
package com.imageeditor
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Matrix;
import spark.components.Image;
public class RotateImage
{
private var m:Matrix;
public function rotateCCW(image:Image):void
{
var w:int = image.width;
var h:int = image.height;
m = new Matrix();
m.rotate(Math.PI/2);
m.tx = image.height;
var bd:BitmapData = new BitmapData(image.height as int, image.width as int);
bd.draw(image, m);
image.width = h;
image.height = w;
image.source = new Bitmap(bd);
}
public function scale(image:Image, kx:Number, ky:Number):void
{
var w:int = image.width;
var h:int = image.height;
m = new Matrix();
m.scale(kx, ky);
var bd:BitmapData = new BitmapData(w*kx as int, h*ky as int);
bd.draw(image, m);
image.width = w*kx;
image.height = h*ky;
image.source = new Bitmap(bd);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="640" minHeight="480">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import flash.display.Shape;
import flash.display.Sprite;
import mx.core.UIComponent;
import spark.core.SpriteVisualElement;
private var rectangle:Sprite = new Sprite();
private var insterter:UIComponent = new UIComponent();
private var theme:SpriteVisualElement = new SpriteVisualElement();
private function main():void
{
rectangle.graphics.lineStyle(1,0x0000FF,1.0);
rectangle.graphics.drawRect(0,0,200,50);
theme.addChild(rectangle);
this.addElement(theme); //tried canvas.addElement
const WIDTH:int = 20;
const HEIGHT:int = 20;
/*var grid:Array = new Array();
for(var y:int = 0; y < HEIGHT; y++) {
var row:Array = new Array();
for (var x:int = 0; x < WIDTH; x++) {
row.push(/*random object*//*);
}
/ grid.push(row);
}*/
}
]]>
</fx:Script>
<!--<spark:Canvas id="canvas" x="34" y="10" width="90%" height="90%" textAlign="center">
</mx:Canvas>-->
</s:Application>
Basically this is not working. I used this question to improve - still nothing.
Why doesnt this Flex App draw a simple rectangle?
Why don't you just use UIComponent.graphics drawing abilities, instead of creating three different objects ?
var uic:UIComponent = new UIComponent();
this.addElement(uic);
uic.width = uic.height = 50;
uic.graphics.lineStyle(1,0x000000);
uic.graphics.drawRect(0,0,50,50);
I've a problem, I'm using an AdvancedDataGrid .
It loads about 3000 records with about 20 columns. I constantly get Flex execution timeout because the grid executes a lot inside LayoutManager.
How can I make it asyncronousely or faster at all?
Use Datagrid pagination.
http://gurufaction.blogspot.com/2007/02/flex-datagrid-paging-example-with.html
http://stackoverflow.com/questions/1893350/how-does-flex-3-datagrid-paging-work
or something like this
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="InitApp()" xmlns:MyComp="*">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.events.ItemClickEvent;
[Bindable]
public var myData:ArrayCollection = new ArrayCollection();
public var orgData:ArrayCollection = new ArrayCollection();
[Bindable]
public var nav:ArrayCollection = new ArrayCollection();
private var index:int = 0;
private var page:int = 25;
private var paging:Boolean = true;
private function InitApp():void {
for( var x:uint = 1; x <= 500; x++ ) {
var obj:Object = new Object();
obj.Id = x.toString();
obj.Name = "Column " + x.toString();
obj.Street = "5555 Street";
obj.Title = "CEO";
obj.City = "El Paso";
orgData.addItem(obj);
}
refreshDataProvider(0);
}
private function navPage(d:int):void {
index += d;
refreshDataProvider(index);
}
private function refreshDataProvider(start:int):void {
if (paging == true) {
page = 25;
myData = new ArrayCollection(orgData.source.slice(start,start+page));
}
else {
index = 0;
page = 500;
myData = new ArrayCollection(orgData.source);
}
down.enabled = index > 0;
up.enabled = index + page < orgData.length;
lbl.text = index.toString() + ' to ' + (index + page).toString() + ' of ' + orgData.length;
}
private function togglePaging():void {
paging = !paging;
toggle.label = paging.toString();
refreshDataProvider(index);
}
]]>
</mx:Script>
<mx:DataGrid id="dg" dataProvider="{myData}" width="510" height="202"></mx:DataGrid>
<mx:Button x="10" y="210" label="<" click="navPage(-25);" id="down"/>
<mx:Button x="216" y="210" label=">" click="navPage(25);" id="up"/>
<mx:Label x="58" y="212" text="page" width="150" id="lbl"/>
<mx:Button x="264" y="210" label="true" id="toggle" click="togglePaging();"/>
</mx:Application>
Load the data a chunk at a time? Say slightly more than however many rows are shown visually. That way you get the perceived performance that it renders quickly.
3000 records is a lot to be loading in one go it has to be said...
I have a panel in my application. My requirement is, I also require a link, that is "Help options" to appear in the panel's header. In the left, we will have the Panel's title and in the right corner, I need this link. Is that possible?
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
width="400" height="300" label="Panel's Label">
<mx:Script>
<![CDATA[
private var linkTextField:TextField;
private var _linkHtmlText:String = "";
public function set linkHtmlText(value:String):void
{
_linkHtmlText = value;
if(linkTextField)
linkTextField.htmlText = value;
}
override protected function createChildren():void
{
super.createChildren();
linkTextField = new TextField();
linkTextField.autoSize = TextFieldAutoSize.LEFT;
linkTextField.text = _linkHtmlText;
linkTextField.y = 5;
this.titleBar.addChild(linkTextField);
}
override protected function layoutChrome(unscaledWidth:Number,
unscaledHeight:Number):void
{
super.layoutChrome(unscaledWidth, unscaledHeight);
linkTextField.x = unscaledWidth - linkTextField.width - 10;
}
]]>
</mx:Script>
</mx:Panel>
import mx.core.IUITextField;
function init():void{
var rightpanel_ui:IUITextField = rightpanel.mx_internal::getStatusTextField();
rightpanel_ui.selectable = true;
rightpanel_ui.htmlText = "<a href='/mylink.php/' target='_new'><u><font color='white'>Help</font></u></a>";
}
<mx:Panel id="rightpanel" width="100%" height="100%" status="Help">