Jump to content


Photo

Autoshape acting on selection


  • Please log in to reply
12 replies to this topic

#1 mitya777

mitya777

    FireStarter

  • Members
  • PipPip
  • 28 posts

Posted 03 March 2011 - 02:51 PM

Hi guys, I am trying to build a label auto shape that take a user's selection and then display it's height and width. The way I have been trying to do this is to call a command that takes the current selection's height and width and sets pngTxt.width and pngTxt.height properties to these. Then the command inserts an autoShape which accesses the pngTxt properties to find out what it should display.

For some reason though I am getting some really strange behavior from the autoshape. Sometimes is will run, other times it won't. Am I on the right path? Or should I be looking for a better way to do this? Thank you in advance for your help.

#2 jdunning

jdunning

    Fireworks Ninja

  • Members
  • PipPipPipPipPip
  • 173 posts

Posted 03 March 2011 - 07:39 PM

Hi guys, I am trying to build a label auto shape that take a user's selection and then display it's height and width. The way I have been trying to do this is to call a command that takes the current selection's height and width and sets pngTxt.width and pngTxt.height properties to these. Then the command inserts an autoShape which accesses the pngTxt properties to find out what it should display.

For some reason though I am getting some really strange behavior from the autoshape. Sometimes is will run, other times it won't.

Auto shapes frequently act bizarrely. A lot of things you think should work don't. Even creating a local variable called "nodes" will break a shape. I mean, wtf?

Does your extension need to be an auto shape? Can you just create a command that inserts the label for the selected element? If both an element and the label are selected, you could have the same command update the label with the element's current size.

If you do want an auto shape, take a look at my Smart Resize shape: http://johndunning.c...out/SmartResize

It includes some commands that manipulate the shape. The Attach.jsf command, for instance, saves the size of the current selection and then inserts a Smart Resize shape, which uses the saved size info to size to the selection. It does this by saving the size in a global variable, which the shape code can access, so you don't actually need to save it in pngText.

The relevant code looks like:

	jdlib = jdlib || {};
	jdlib.SRInfo = jdlib.SRInfo || {};
	...
		// store the current selection and bounds in a global because the selection
		// is cleared when the auto shape is inserted.  the Group Resize shape
		// will use these globals in onInsertSmartShapeAt.
	jdlib.SRInfo.bounds = selBounds;
	jdlib.SRInfo.selection = [].concat(fw.selection);

		// insert the auto shape, which will leave it selected along with the
		// elements in jdlib.SRInfo.selection
	dom.insertSmartShapeAt("Smart Resize", { x: selBounds.left, y: selBounds.top }, false);
	...
		// clear the refrences to the selected elements 
	jdlib.SRInfo.selection = null;


In the shape's InsertSmartShapeAt handler, it looks for that global and accesses the size of the selection. The jdlib object is a global I use in a lot of commands. I try to use just a few globals to avoid polluting the namespace or possibly stomping on other commands.

Anyway, hope that helps point in you the right direction. I think my auto shape code is fairly well documented, so look through some of those commands might help as well.

#3 mitya777

mitya777

    FireStarter

  • Members
  • PipPip
  • 28 posts

Posted 04 March 2011 - 08:44 AM

Thanks John, the reason I wanted to use a smart shape is so that after I insert the label, I wanted the use to be able to move the label end around while the arm stayed attached to the item it was describing, kind of like the annotation smart shape that is in the auto shape folder.

I will try using a global variable and see if that works better. Thank you again for the timely advice.

#4 mitya777

mitya777

    FireStarter

  • Members
  • PipPip
  • 28 posts

Posted 04 March 2011 - 02:55 PM

Some of the strange behavior I have been getting. I have a very simple autoshape coded and saved in the Auto Shapes folder. I get it to run. Then I restart fireworks without changing the shape code. Run the shape again, it will throw an error:

Reference Error: SetNodePosition is not defined
0

Even though I have the following code in my auto shape:

SetNodePosition = function(node, pt){
SetBezierNodePosition(node, pt,pt,pt);
}



Another strange behavior: sometimes I will run the command that inserts the autoshape. Inside the autoshape I have various alerts. To get to the next alert I will have to press 'alt'. I think the alert is there, but it's like I have to press alt to display it. I keep pressing alt to run through all the alerts. When I just drag the autoshape onto the canvas, the alerts all show up by themselves without the need to press it.

I'm not sure how to proceed at this point.

#5 jdunning

jdunning

    Fireworks Ninja

  • Members
  • PipPipPipPipPip
  • 173 posts

Posted 04 March 2011 - 09:03 PM

Some of the strange behavior I have been getting. I have a very simple autoshape coded and saved in the Auto Shapes folder. I get it to run. Then I restart fireworks without changing the shape code. Run the shape again, it will throw an error:

Reference Error: SetNodePosition is not defined
0

Even though I have the following code in my auto shape:

SetNodePosition = function(node, pt){
SetBezierNodePosition(node, pt,pt,pt);
}

Are you calling SetNodePosition before it's defined? It looks like you're setting it to a global variable. So if you run the shape once and manage to define the global before using it, but then change the code so the first use comes before the definition, you won't see an error. The globally defined function will be there for the code to use. But on a fresh launch of FW, the global namespace is cleared, so running the code will then generate an error.

This gets back to what I was saying in another thread about wrapping code in a function "module":

(function(){
		function foo(x) { alert("foo: " + x); }
		var dom = fw.getDocumentDOM(); 
		foo(dom.backgroundColor);
	})();

dom and foo are local variables, so they won't stick around after the code executes. If you then change it to this:

(function(){
		foo(dom.currentLayerNum);
		function foo(x) { alert("foo: " + x); }
		var dom = fw.getDocumentDOM(); 
		foo(dom.backgroundColor);
	})();

You'll get an error, since you're using dom before it's defined (calling foo is okay, since functions are defined as part of the initial parsing pass before any code executes). If dom wasn't a local variable, then you might not see the error until you restart FW and try it again.

Another strange behavior: sometimes I will run the command that inserts the autoshape. Inside the autoshape I have various alerts. To get to the next alert I will have to press 'alt'. I think the alert is there, but it's like I have to press alt to display it. I keep pressing alt to run through all the alerts. When I just drag the autoshape onto the canvas, the alerts all show up by themselves without the need to press it.

Yeah, alerts in auto shape code can cause FW to misbehave. I'd recommend installing the Fireworks Console: http://johndunning.c...about/FWConsole

Then you can print messages and values to the console by calling console.log, like console.log(dom.currentFrameNum, dom.currentLayerNum). Just remember to remove those calls before distributing the shape, as they'll cause an error if the console isn't open.

#6 mitya777

mitya777

    FireStarter

  • Members
  • PipPip
  • 28 posts

Posted 05 March 2011 - 08:19 AM

Hey John, the smart shapes I have been looking at provided in Fireworks all call SetNodePosition before defining it at the end of the .jsf file in the following manner:

SetNodePosition = function...

I figured that during the initial parse since SetNodePosition was being set to a function it would get picked up on, as though I had set it like:

function SetNodePosition(){...}

But I will go take another look and also see if I'm missing any other global variables that are affecting things.

Good to know about the alerts in autoshape. Autoshapes are like a minefield!

#7 jdunning

jdunning

    Fireworks Ninja

  • Members
  • PipPipPipPipPip
  • 173 posts

Posted 05 March 2011 - 12:09 PM

Hey John, the smart shapes I have been looking at provided in Fireworks all call SetNodePosition before defining it at the end of the .jsf file in the following manner:

SetNodePosition = function...

Looking at the Annotation.jsf file, for example, there are a bunch of functions that are defined before SetNodePosition and which call it, but those functions aren't called before SetNodePosition gets defined. Otherwise, the code wouldn't work.

Note that the very last lines in that file are:

if (operation[smartShape.operation])
    operation[smartShape.operation]();

None of the functions that were defined above those lines have been called yet. It's the call to the operation handler that starts the execution. So perhaps your code that does this dispatching came before the point SetNodePosition was defined.

In general, the auto shapes that ship with FW aren't very well-written. The code looks like it came from someone who wasn't very familiar with JavaScript. Using the foo = function() idiom for what are intended to be local functions doesn't make sense. And the fact that everything is created as a global variable that sticks around after the code runs doesn't seem to have been considered.

At a more basic level, the whole auto shape system seems like a giant kludge. Every instance of an auto shape contains all of the JS source code for that object, which almost certainly takes up more space than a vector or bitmap representation of the shape. Even worse, *all* of that code is executed every single time you interact with the shape. This isn't like a browser where you load a JS file and set up some event handlers, which are then executed only when their particular event fires. It's more like a batch file that runs straight through and changes its behavior based on an environment variable (the smartShape.operation value in this case). So when dragging a control point on the Lorem Ipsum shape, for instance, 2000 lines of code are parsed for every mouse movement, even though only about 70 are needed to handle the event.

Anyway, you can still do some useful things with auto shapes (though not as much as you should be able to). It's just that I find them aesthetically displeasing. :)

I figured that during the initial parse since SetNodePosition was being set to a function it would get picked up on, as though I had set it like:

function SetNodePosition(){...}


Nope. function foo() creates a local variable named "foo" and points it at that function before the rest of the code is executed. var foo = function() isn't executed until that line is reached. (I think in some JS engines, the function is instantiated during parsing, but it isn't callable before that line because it hasn't been assigned to a variable yet.)

Try running this to see what I mean:

(function(){
	foo(42);
	bar(43);

	bar = function(x) { alert("bar: " + x); };
	function foo(x) { alert("foo: " + x); }
})();

Good to know about the alerts in autoshape. Autoshapes are like a minefield!


Indeed. Good luck getting out with all your limbs intact!

#8 mitya777

mitya777

    FireStarter

  • Members
  • PipPip
  • 28 posts

Posted 05 March 2011 - 01:30 PM

Right! I was confusing the definition with the execution. Ok, this has been super helpful. Gonna go donate :)

#9 jdunning

jdunning

    Fireworks Ninja

  • Members
  • PipPipPipPipPip
  • 173 posts

Posted 05 March 2011 - 11:04 PM

Right! I was confusing the definition with the execution. Ok, this has been super helpful. Gonna go donate :)

Thanks! Glad I could be of help.

#10 mitya777

mitya777

    FireStarter

  • Members
  • PipPip
  • 28 posts

Posted 07 March 2011 - 07:51 AM

"This gets back to what I was saying in another thread about wrapping code in a function "module""

I tried searching and couldn't find the thread you mentioned. Could you point me to it? Or summarize what the advantage is of doing this? Just curious.

#11 mitya777

mitya777

    FireStarter

  • Members
  • PipPip
  • 28 posts

Posted 07 March 2011 - 08:17 AM

Here is another problem I am running into:

If my script does this:

var dom = fw.getDocumentDOM();
dom.insertSmartShapeAt("Specter", {x: LEFT_OFFSET, y: TOP_OFFSET}, false);

if I then have an alert() anywhere in between those two lines, like so for instance:

var dom = fw.getDocumentDOM();
alert("yo, sup");
dom.insertSmartShapeAt("Specter", {x: LEFT_OFFSET, y: TOP_OFFSET}, false);

Fireworks hangs, displaying a gray "processing script" dialog box. At which point I have to kill it through task manager.

I can get around this by either not having an alert anywhere in between those two lines, or just inserting the smart shape with a fw.getDocumentDOM().insertSmartShape() call.

This must somehow be connected with my autoshape implementation because when I insert a FW provided shape, it works ok... but I am not sure why an alert() would cause something like this and I can't identify anything in my autoshape which reaches outside of its own scope except when I call the Math object.

I'm sure I am missing something, just wondering if you had any thoughts on this.

#12 jdunning

jdunning

    Fireworks Ninja

  • Members
  • PipPipPipPipPip
  • 173 posts

Posted 07 March 2011 - 09:05 AM

"This gets back to what I was saying in another thread about wrapping code in a function "module""

I tried searching and couldn't find the thread you mentioned. Could you point me to it? Or summarize what the advantage is of doing this? Just curious.

I think I was thinking about this post: http://www.fireworks...indpost&p=27848

#13 jdunning

jdunning

    Fireworks Ninja

  • Members
  • PipPipPipPipPip
  • 173 posts

Posted 07 March 2011 - 02:02 PM

Here is another problem I am running into:

If my script does this:

var dom = fw.getDocumentDOM();
dom.insertSmartShapeAt("Specter", {x: LEFT_OFFSET, y: TOP_OFFSET}, false);

if I then have an alert() anywhere in between those two lines, like so for instance:

var dom = fw.getDocumentDOM();
alert("yo, sup");
dom.insertSmartShapeAt("Specter", {x: LEFT_OFFSET, y: TOP_OFFSET}, false);

Fireworks hangs, displaying a gray "processing script" dialog box. At which point I have to kill it through task manager.

You mean, after you click OK in the alert, it hangs? That's odd. I've seen problems trying to show alerts during auto shape execution, but from one right before.

Actually, I was just able to reproduce this. The "processing command" dialog popped on top and wouldn't go away, so I had to kill FW. I think the only workaround is not to show an alert.

This must somehow be connected with my autoshape implementation because when I insert a FW provided shape, it works ok... but I am not sure why an alert() would cause something like this and I can't identify anything in my autoshape which reaches outside of its own scope except when I call the Math object.

FW has problems with that processing dialog popping up and blocking all UI access. I think it may have to do with Flash panels making API calls while another dialog is up. It's possible that closing all Flash panels before showing the alert might work. But in general, it's probably easier to avoid alert and use the console.