I have a route that is a combination of multiple sub routes. (By sub routes i mean multiple DirectionsRenderer objects)
I also have a loop where i go throught all of the DirectionsRenderer objects and attach "directions_changed" event to all of them.
Unfortunatelly only that last DirectionsRenderer object fires the event when i try to test what happens when i drag the polyline.
Here is a part of my code:
for(var k=0; k<directionsRenderers.length; k++)
{
var directionsRenderer = directionsRenderers[k];
var a = registerDirectionsChangedEvent(k,directionsRenderer);
}
function registerDirectionsChangedEvent(index, directionsRenderer)
{
this.index = index;
this.directionsRenderer = directionsRenderer;
var that = this;
var a = google.maps.event.addListener(this.directionsRenderer, "directions_changed", function()
{
var newStopPoint;
var directionsResult = that.directionsRenderer.getDirections();
var route = directionsResult.routes[0];
var legs = route.legs;
var legsIndex = 0;
for(var i=0; i<legs.length; i++)
{
var cLeg = legs[i];
var viaWaypoints = cLeg.via_waypoints;
if(viaWaypoints.length > 0)
{
newStopPoint = viaWaypoints[0];
if(that.index === 1) legsIndex += 9;
else if(that.index === 2) legsIndex += 18;
break;
}
legsIndex++;
}
addNewStopPoint(newStopPoint,legsIndex);
});
return a;
}
As i have mentioned above not only the last DirectionsRenderer object get fired but the ones before the last event do not implement the default behaviour.
Maybe you have noticed that i use:
this.index = index;
this.directionsRenderer = directionsRenderer;
var that = this;
event without it it still does not work.
I also tried to use a function created inside the loop like this:
(function someFunction(a,b){//do something here})(a,b);
but still no luck!
any advice how to make it works?
Use function closure, this is probably a duplicate (not tested):
for(var k=0; k<directionsRenderers.length; k++)
{
var directionsRenderer = directionsRenderers[k];
var a = registerDirectionsChangedEvent(k,directionsRenderer);
}
function registerDirectionsChangedEvent(index, directionsRenderer)
{
var a = google.maps.event.addListener(directionsRenderer, "directions_changed", function()
{
var newStopPoint;
var directionsResult = directionsRenderer.getDirections();
var route = directionsResult.routes[0];
var legs = route.legs;
var legsIndex = 0;
for(var i=0; i<legs.length; i++)
{
var cLeg = legs[i];
var viaWaypoints = cLeg.via_waypoints;
if(viaWaypoints.length > 0)
{
newStopPoint = viaWaypoints[0];
if(index === 1) legsIndex += 9;
else if(index === 2) legsIndex += 18;
break;
}
legsIndex++;
}
addNewStopPoint(newStopPoint,legsIndex);
});
return a;
}
Related
How can I get the iframes on the page? I want to get an external options(width, height, id, src) and inner HTML.
It's all I can get only if the iframes on the page are not dynamically added. If they are dynamically added, the order of the IFRAME in the DOM and in the frameid (switchToFrame(frameid)) differs, and I can not compare them.
HTML:
<iframe src="iframe.php?id=1"></iframe>
<iframe src="iframe.php?id=2"></iframe>
<div id="dynamic_iframe"></div>
<div id="dynamic_iframe2"></div>
<iframe src="iframe.php?id=3"></iframe>
<script>
var el = document.createElement("iframe");
el.src = 'iframe.php?id=21';
document.getElementById('dynamic_iframe').appendChild(el);
var el = document.createElement("iframe");
el.src = 'iframe.php?id=22';
document.getElementById('dynamic_iframe2').appendChild(el);
</script>
PhantomJS:
getAllIFramesFromPage = function(page){
return page.evaluate(function() {
var matches = document.querySelectorAll('iframe');
ifames = [];
for(var i = 0; i < matches.length; ++i){
ifames.push(matches[i].src);
}
return ifames;
});
};
out:
iframe.php?id=1
iframe.php?id=2
iframe.php?id=21
iframe.php?id=22
iframe.php?id=3
PhantomJS:
var cnt = page.framesCount;
for(var i = 0; i < cnt; i++){
page.switchToFrame(i);
console.log(page.framePlainText);
page.switchToMainFrame();
}
out:
1
2
3
21
22
I was able to get out of a problem like this:
When I pass all the iframe into the DOM I put in them hidden value
page.switchToMainFrame();
page.evaluate(function() {
var matches = document.querySelectorAll('iframe');
ifames = [];
for(var i = 0; i < matches.length; ++i){
var iframeWindow = matches[i].contentWindow || matches[i].contentDocument.parent;
var frmBody = iframeWindow.document.getElementsByTagName("body")[0].frame_id = i;
}
});
Already inside an iframe I can get this value as follows:
var cnt = this.page.framesCount;
for(var i = 0; i < cnt; i++){
page.switchToFrame(i);
frameIndex = this.page.evaluate(function() {
if (document.getElementsByTagName("body")[0].frame_id !== undefined){
return document.getElementsByTagName("body")[0].frame_id;
}
return false;
});
this.page.switchToParentFrame();
}
I'm trying to make a image editor in Flex 4.5.
However, there's one little thing that doesn't work as appropriate. Here's my code:
private function returnCropIndicatorBmpDataForTopLeft():BitmapData{
var topLeftX:int = 0;
var topLeftY:int = 0;
var topRightX:int = _bmpData.width;
var topRightY:int = 0;
var bottomRightX:int = _bmpData.width;
var bottomRightY:int = _bmpData.height;
var bottomLeftX:int = 0;
var bottomLeftY:int = _bmpData.height;
var cropIconX:int = _mouseX;
var cropIconY:int = _mouseY;
var temporaryBitmapData:BitmapData = _bmpData;
var originalColor:uint;
var dimmedColor:uint = 0x202020;
for (var i:int = 0; i < _bmpData.width; i++)
{
for (var j:int = 0; j < _bmpData.height; j++)
{
originalColor = _bmpData.getPixel(i,j);
if(i>cropIconX && j>cropIconY){
temporaryBitmapData.setPixel(i,j,originalColor);
}else{
temporaryBitmapData.setPixel(i,j,dimmedColor);
}
}
}
/*
*by the end of this loop, we have, in the temporaryBitmapData variable, a version of the _bmpData,
*the area to be cropped out dimmed a little bit.
*/
return temporaryBitmapData;
}
if you look carefully inside the first if statement in the innermost for loop,
temporaryBitmapData.setPixel(i,j,originalColor);
that bit of code should do the following:
If this (i,j) pixel is outside of the "to-be-cropped-out area", then repaint it with the original pixel color.
It just can't seem to get that to work!!!!
I've substituted that line with some hardcoded value (say, 0xFFFFFF for white) and it did work, so the problem is not there....
Hope you guys can help me out I've spent more than 4 hours on this already trying many different approaches!!
P.S.> I debugged this code in FB 4.5 and placed a breakpoint in that very if statement. For some reason, the _bmpData variable, which is where I want to get the original pixel color from , shows a small red square next to it.... Perhaps that is indicative of something.. perhaps it's somehow thread-'locked'?? I don't know, hope someone can figure out!
EDIT the problem I'm having is the following: the dimming of the image works fine, but if I then move the mouse cursor back to an area that got dimmed out, then the original image doesn't get repainted, as expected.
There must be something else going on there... I just tested your code and it worked fine for me.
package {
import flash.display.MovieClip;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.net.*;
import flash.display.Loader;
import flash.events.Event;
public class ImageCropper extends MovieClip {
protected var _bmpData:BitmapData;
protected var _mouseX:int;
protected var _mouseY:int;
var imageLoader:Loader;
public function ImageCropper() {
_mouseX = 80;
_mouseY = 50;
imageLoader = new Loader();
var image:URLRequest = new URLRequest("http://www.travelooce.com/pics/bear_picnic_table.jpg");
imageLoader.load(image);
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, _imageLoaded);
imageLoader.x = 0;
imageLoader.y = 0;
}
public function _imageLoaded($evt:Event):void {
_bmpData = new BitmapData(imageLoader.width, imageLoader.height, false);
_bmpData.draw(imageLoader);
var bmp2:BitmapData = returnCropIndicatorBmpDataForTopLeft();
var bmp:Bitmap = new Bitmap(bmp2);
addChild(bmp);
}
private function returnCropIndicatorBmpDataForTopLeft():BitmapData{
var topLeftX:int = 0;
var topLeftY:int = 0;
var topRightX:int = _bmpData.width;
var topRightY:int = 0;
var bottomRightX:int = _bmpData.width;
var bottomRightY:int = _bmpData.height;
var bottomLeftX:int = 0;
var bottomLeftY:int = _bmpData.height;
var cropIconX:int = _mouseX;
var cropIconY:int = _mouseY;
// This is the important line to change.
var temporaryBitmapData:BitmapData = _bmpData.clone();
var originalColor:uint;
var dimmedColor:uint = 0x202020;
for (var i:int = 0; i < _bmpData.width; i++)
{
for (var j:int = 0; j < _bmpData.height; j++)
{
originalColor = _bmpData.getPixel(i,j);
if(i>cropIconX && j>cropIconY){
temporaryBitmapData.setPixel(i,j,originalColor);
}else{
temporaryBitmapData.setPixel(i,j,dimmedColor);
}
}
}
/*
*by the end of this loop, we have, in the temporaryBitmapData variable, a version of the _bmpData,
*the area to be cropped out dimmed a little bit.
*/
return temporaryBitmapData;
}
}
}
Output:
http://cl.ly/3d0h023C1p392O270I2L
I have a string variable assigned with some Content in HTML format.
Some thing like this var strLabel:String = "This is <b>Test</b>;
But in run time i have get the first 10 characters of the string and display it in another control.
For this, what did was
txtLabelName.Text = String(strLabel).substr(0,10) + ' ...';
But in the output i am getting as This is <b. Basically it considering HTML related tags also as text. But my code has to omit the HTML tags while calculating sub string.
Please anybody help me to do this?
Use this regexp to strip html tags (more or less):
txtLabelName.text = strLabel.replace(/\<.+?\>/g, '').substr(0, 10) + ' ...';
It's a very simple regexp to strip all tags so it won't work on more complex tags (probably).
I got this code from some blog. This is working Perfectly
public static function stripHtmlTags(html:String, tags:String = ""):String
{
var tagsToBeKept:Array = new Array();
if (tags.length > 0)
tagsToBeKept = tags.split(new RegExp("\\s*,\\s*"));
var tagsToKeep:Array = new Array();
for (var i:int = 0; i < tagsToBeKept.length; i++)
{
if (tagsToBeKept[i] != null && tagsToBeKept[i] != "")
tagsToKeep.push(tagsToBeKept[i]);
}
var toBeRemoved:Array = new Array();
var tagRegExp:RegExp = new RegExp("<([^>\\s]+)(\\s[^>]+)*>", "g");
var foundedStrings:Array = html.match(tagRegExp);
for (i = 0; i < foundedStrings.length; i++)
{
var tagFlag:Boolean = false;
if (tagsToKeep != null)
{
for (var j:int = 0; j < tagsToKeep.length; j++)
{
var tmpRegExp:RegExp = new RegExp("<\/?" + tagsToKeep[j] + "( [^<>]*)*>", "i");
var tmpStr:String = foundedStrings[i] as String;
if (tmpStr.search(tmpRegExp) != -1)
tagFlag = true;
}
}
if (!tagFlag)
toBeRemoved.push(foundedStrings[i]);
}
for (i = 0; i < toBeRemoved.length; i++)
{
var tmpRE:RegExp = new RegExp("([\+\*\$\/])","g");
var tmpRemRE:RegExp = new RegExp((toBeRemoved[i] as String).replace(tmpRE, "\\$1"),"g");
html = html.replace(tmpRemRE, "");
}
return html;
}
I have flex 4 and writing my own autocomplete component (based on the popupanchor) to search for different books. In the dropdown box, how can I highlight the text that matches? For instance, a user types in "ema" and the search returns "Pet Sematary"....I want to highlight the letters "ema" within "Pet Sematary"
Wrote auto-complete a week ago :) You need to use Spark text components and pass custom TextFlow to them:
private function init():void
{
var textFlow:TextFlow = new TextFlow();
var paragraph:ParagraphElement = new ParagraphElement();
textFlow.addChild(paragraph);
var elements:Vector.<FlowElement> = highlight("Pet Sematary", "Se");
var n:int = elements.length;
for (var i:int = 0; i < n; i++)
{
paragraph.addChild(elements[i]);
}
label.textFlow = textFlow;
}
private function highlight(text:String, query:String):Vector.<FlowElement>
{
var result:Vector.<FlowElement> = new Vector.<FlowElement>();
// since we need to compare ignore-case we can not use split()
// and have to collect indexes of "query" matches in "text"
var indexes:Vector.<int> = new Vector.<int>();
var index:int = 0;
var textLowerCase:String = text.toLocaleLowerCase();
var queryLowerCase:String = query.toLocaleLowerCase();
var queryLength:int = query.length;
while (true)
{
index = textLowerCase.indexOf(queryLowerCase, index);
if (index == -1)
break;
indexes.push(index);
index += queryLength;
}
// now add SpanElement for each part of text. E.g. if we have
// text="aBc" and query is "b" then we add "a" and "c" as simple
// span and "B" as highlighted span.
var backgroundColor:uint = 0xFFCC00;
var n:int = indexes.length;
if (n == 0) // no matches
{
addSpan(result, text);
}
else
{
var startIndex:int = 0;
for (var i:int = 0; i < n; i++)
{
if (startIndex != indexes[i])
addSpan(result, text.substring(startIndex, indexes[i]));
addSpan(result, text.substr(indexes[i], queryLength),
backgroundColor);
startIndex = indexes[i] + queryLength;
}
if (startIndex != text.length)
addSpan(result, text.substr(startIndex));
}
return result;
}
private function addSpan(vector:Vector.<FlowElement>, text:String,
backgroundColor:* = "transparent"):void
{
var span:SpanElement = new SpanElement();
span.text = text;
span.backgroundColor = backgroundColor;
vector.push(span);
}
MXML code:
<s:RichEditableText editable="false" multiline="false"
selectable="false" id="label"
horizontalCenter="0" verticalCenter="0"/>
P.S: If you will have troubles with popup taking focus - add it manually to the toolTipChildren:
systemManager.toolTipChildren.addChildAt(child, 0);
i'm loading several sound files, and want to error check each load. however, instead programming each one with their own complete/error functions, i would like them to all use the same complete/error handler functions.
a successfully loaded sound should create a new sound channel variable, while an unsuccessfully loaded sound will produce a simple trace with the name of the sound that failed to load. however, in order to do this, i need to dynamically create variables, which i haven't yet figured out how to do.
here's my code for my complete and error functions:
function soundLoadedOK(e:Event):void
{
//EX: Sound named "explosion" will create Sound Channel named "explosionChannel"
var String(e.currentTarget.name + "Channel"):SoundChannel = new SoundChannel();
}
function soundLoadFailed(e:IOErrorEvent):void
{
trace("Failed To Load Sound:" + e.currentTarget.name);
}
-=-=-=-=-=-=-=-=-
UPDATED (RE: viatropos)
-=-=-=-=-=-=-=-=-
can not find the error.
TypeError: Error #1009: Cannot access a property or method of a null object reference. at lesson12_start_fla::MainTimeline/loadSounds() at lesson12_start_fla::MainTimeline/frame1():
//Sounds
var soundByName:Object = {};
var channelByName:Object = {};
var soundName:String;
var channelName:String;
loadSounds();
function loadSounds():void
{
var files:Array = ["robotArm.mp3", "click.mp3"];
var i:int = 0;
var n:int = files.length;
for (i; i < n; i++)
{
soundName = files[i];
soundByName[soundName] = new Sound();
soundByName[soundName].addEventListener(Event.COMPLETE, sound_completeHandler);
soundByName[soundName].addEventListener(IOErrorEvent.IO_ERROR, sound_ioErrorHandler);
soundByName[soundName].load(new URLRequest(soundName));
}
}
function sound_completeHandler(event:Event):void
{
channelName = event.currentTarget.id3.songName;
channelByName[channelName] = new SoundChannel();
}
function sound_ioErrorHandler(event:IOErrorEvent):void
{
trace("Failed To Load Sound:" + event.currentTarget.name);
}
You can do this a few ways:
Storing your SoundChannels in an Array. Good if you care about order or you don't care about getting them by name.
Storing SoundChannels by any name in an Object. Good if you want to easily be able to get the by name. Note, the Object class can only store keys ({key:value} or object[key] = value) that are Strings. If you need Objects as keys, use flash.utils.Dictionary, it's a glorified hash.
Here's an example demonstrating using an Array vs. an Object.
var channels:Array = [];
// instead of creating a ton of properties like
// propA propB propC
// just create one property and have it keep those values
var channelsByName:Object = {};
function loadSounds():void
{
var files:Array = ["soundA.mp3", "soundB.mp3", "soundC.mp3"];
var sound:Sound;
var soundChannel:SoundChannel;
var i:int = 0;
var n:int = files.length;
for (i; i < n; i++)
{
sound = new Sound();
sound.addEventListener(Event.COMPLETE, sound_completeHandler);
sound.addEventListener(IOErrorEvent.IO_ERROR, sound_ioErrorHandler);
sound.load(files[i]);
}
}
function sound_completeHandler(event:Event):void
{
// option A
var channelName:String = event.currentTarget.id3.songName;
// if you want to be able to get them by name
channelsByName[channelName] = new SoundChannel();
// optionB
// if you just need to keep track of all of them,
// and don't care about the name specifically
channels.push(new SoundChannel())
}
function sound_ioErrorHandler(event:IOErrorEvent):void
{
trace("Failed To Load Sound:" + event.currentTarget.name);
}
Let me know if that works out.
//Load Sounds
var soundDictionary:Dictionary = new Dictionary();
var soundByName:Object = new Object();
var channelByName:Object = new Object();
loadSounds();
function loadSounds():void
{
var files:Array = ["robotArm.mp3", "click.mp3"]; //etc.
for (var i:int = 0; i < files.length; i++)
{
var soundName:String = files[i];
var sound:Sound=new Sound();
soundDictionary[sound] = soundName;
soundByName[soundName] = sound;
sound.addEventListener(Event.COMPLETE, sound_completeHandler);
sound.addEventListener(IOErrorEvent.IO_ERROR, sound_ioErrorHandler);
sound.load(new URLRequest(soundName));
}
}
function sound_completeHandler(e:Event):void
{
var soundName:String=soundDictionary[e.currentTarget];
channelByName[soundName] = new SoundChannel();
}
function sound_ioErrorHandler(e:IOErrorEvent):void
{
trace("Failed To Load Sound:" + soundDictionary[e.currentTarget]);
}
//Play Sound
channelByName["robotArm.mp3"] = soundByName["robotArm.mp3"].play();
//Stop Sound
channelByName["robotArm.mp3"].stop();