Permalink
Browse files

Merge branch 'master' into refactoring-amd-to-commonjs

Conflicts:
	lib/scxml/state-kinds-enum.coffee
	src/main/bash/build/convert-scxml-tests-to-json.sh
	src/main/bash/build/generate-requirejs-array-test-loader-module.sh
	src/main/bash/build/generate-requirejs-json-test-tuples.sh
	src/main/bash/build/generate-requirejs-test-loader-module.sh
	src/main/bash/util/scxml-to-json.sh
	src/main/coffeescript/node/index.coffee
	src/main/coffeescript/optimization/class.coffee
	src/main/coffeescript/optimization/initializer.coffee
	src/main/coffeescript/optimization/state-table.coffee
	src/main/coffeescript/optimization/switch.coffee
	src/main/coffeescript/optimization/transition-optimizer.coffee
	src/main/coffeescript/runner.coffee
	src/main/coffeescript/scxml/SCXML.coffee
	src/main/coffeescript/scxml/async-for.coffee
	src/main/coffeescript/scxml/doc2json.coffee
	src/main/coffeescript/scxml/doc2model.coffee
	src/main/coffeescript/scxml/event.coffee
	src/main/coffeescript/scxml/extra-model.coffee
	src/main/coffeescript/scxml/json2extra-model.coffee
	src/main/coffeescript/scxml/json2model.coffee
	src/main/coffeescript/scxml/model.coffee
	src/main/coffeescript/scxml/scxml-dynamic-name-match-transition-selector.coffee
	src/main/coffeescript/scxml/setup-default-opts.coffee
	src/main/coffeescript/test-harness/basic-test-harness.coffee
	src/main/coffeescript/test-harness/browser-harness.coffee
	src/main/coffeescript/test-harness/harness.coffee
	src/main/coffeescript/test-harness/multi-process/client.coffee
	src/main/coffeescript/test-harness/multi-process/initialize-json-test-descriptor.coffee
	src/main/coffeescript/test-harness/multi-process/json-tests.coffee
	src/main/coffeescript/test-harness/multi-process/scxml.coffee
	src/main/coffeescript/test-harness/multi-process/server.coffee
	src/main/coffeescript/test-harness/node-optimization-harness.coffee
	src/main/coffeescript/test-harness/optimization-harness.coffee
	src/main/coffeescript/test-harness/report2string.coffee
	src/main/coffeescript/test-harness/rhino-optimization-harness.coffee
	src/main/coffeescript/test-harness/simple-browser-test.coffee
	src/main/coffeescript/test-harness/simple-browser-test.html
	src/main/coffeescript/test-harness/simple-env.coffee
	src/main/coffeescript/test-harness/simple-node-test.coffee
	src/main/coffeescript/test-harness/spartan-optimization-harness.coffee
	src/main/coffeescript/util/BufferedStream.coffee
	src/main/coffeescript/util/annotate-scxml-json.coffee
	src/main/coffeescript/util/memory.coffee
	src/main/coffeescript/util/readline.coffee
	src/main/coffeescript/util/reduce.coffee
	src/main/coffeescript/util/set/ArraySet.coffee
	src/main/coffeescript/util/set/BitVector.coffee
	src/main/coffeescript/util/set/BooleanArray.coffee
	src/main/coffeescript/util/set/ObjectSet.coffee
	src/main/coffeescript/util/utils.coffee
	src/main/python/scxml/SCXML.py
	src/main/python/scxml/doc2model.py
	src/main/python/scxml/evaluators/es.py
	src/main/python/scxml/evaluators/interface.py
	src/main/python/scxml/evaluators/py.py
	src/main/python/scxml/event.py
	src/main/python/scxml/json2model.py
	src/main/python/scxml/model.py
	src/main/python/scxml/multithreaded.py
	src/main/python/scxml/simpleEnv.py
	src/main/python/scxml/test/harness.py
	src/main/xslt/add-entry-exit-logging.xsl
	src/main/xslt/flattenTransitions.xsl
	src/main/xslt/normalizeInitialStates.xsl
	src/test-scripts/run-basic-test.sh
	src/test-scripts/run-optimization-tests-node.sh
	src/test-scripts/run-optimization-tests-rhino.sh
	src/test-scripts/run-optimization-tests-spartan-shell.sh
	src/test-scripts/test-runner.html
	src/test/actionSend/send1.json
	src/test/actionSend/send1.scxml
	src/test/actionSend/send2.json
	src/test/actionSend/send2.scxml
	src/test/actionSend/send3.json
	src/test/actionSend/send3.scxml
	src/test/actionSend/send4.json
	src/test/actionSend/send4.scxml
	src/test/actionSend/send5.json
	src/test/actionSend/send5.scxml
	src/test/actionSend/send6.json
	src/test/actionSend/send6.scxml
	src/test/actionSend/send7.json
	src/test/actionSend/send7.scxml
	src/test/actionSend/send8.json
	src/test/actionSend/send8.scxml
	src/test/assign-current-small-step/test0.json
	src/test/assign-current-small-step/test0.scxml
	src/test/assign-current-small-step/test1.json
	src/test/assign-current-small-step/test1.scxml
	src/test/assign-current-small-step/test2.json
	src/test/assign-current-small-step/test2.scxml
	src/test/assign-current-small-step/test3.json
	src/test/assign-current-small-step/test3.scxml
	src/test/assign-next-small-step/test0.json
	src/test/assign-next-small-step/test0.scxml
	src/test/assign-next-small-step/test1.json
	src/test/assign-next-small-step/test1.scxml
	src/test/assign-next-small-step/test2.json
	src/test/assign-next-small-step/test2.scxml
	src/test/assign-next-small-step/test3.json
	src/test/assign-next-small-step/test3.scxml
	src/test/atom3-basic-tests/m0.json
	src/test/atom3-basic-tests/m0.scxml
	src/test/atom3-basic-tests/m1.json
	src/test/atom3-basic-tests/m1.scxml
	src/test/atom3-basic-tests/m2.json
	src/test/atom3-basic-tests/m2.scxml
	src/test/atom3-basic-tests/m3.json
	src/test/atom3-basic-tests/m3.scxml
	src/test/basic/basic0.json
	src/test/basic/basic0.scxml
	src/test/basic/basic1.json
	src/test/basic/basic1.scxml
	src/test/basic/basic2.json
	src/test/basic/basic2.scxml
	src/test/cond-js/TestConditionalTransition.json
	src/test/cond-js/TestConditionalTransition.scxml
	src/test/cond-js/test0.json
	src/test/cond-js/test0.scxml
	src/test/cond-js/test1.json
	src/test/cond-js/test1.scxml
	src/test/cond-js/test2.json
	src/test/cond-js/test2.scxml
	src/test/default-initial-state/initial1.json
	src/test/default-initial-state/initial1.scxml
	src/test/default-initial-state/initial2.json
	src/test/default-initial-state/initial2.scxml
	src/test/default-initial-state/initial3.json
	src/test/default-initial-state/initial3.scxml
	src/test/delayedSend/send1.json
	src/test/delayedSend/send1.scxml
	src/test/delayedSend/send2.json
	src/test/delayedSend/send2.scxml
	src/test/delayedSend/send3.json
	src/test/delayedSend/send3.scxml
	src/test/documentOrder/documentOrder0.json
	src/test/documentOrder/documentOrder0.scxml
	src/test/hierarchy+documentOrder/test0.json
	src/test/hierarchy+documentOrder/test0.scxml
	src/test/hierarchy+documentOrder/test1.json
	src/test/hierarchy+documentOrder/test1.scxml
	src/test/hierarchy/hier0.json
	src/test/hierarchy/hier0.scxml
	src/test/hierarchy/hier1.json
	src/test/hierarchy/hier1.scxml
	src/test/hierarchy/hier2.json
	src/test/hierarchy/hier2.scxml
	src/test/history/history0.json
	src/test/history/history0.scxml
	src/test/history/history1.json
	src/test/history/history1.scxml
	src/test/history/history2.json
	src/test/history/history2.scxml
	src/test/history/history3.json
	src/test/history/history3.scxml
	src/test/history/history4.json
	src/test/history/history4.scxml
	src/test/history/history5.json
	src/test/history/history5.scxml
	src/test/in/TestInPredicate.json
	src/test/in/TestInPredicate.scxml
	src/test/multiple-events-per-transition/test1.json
	src/test/multiple-events-per-transition/test1.scxml
	src/test/parallel+interrupt/test0.json
	src/test/parallel+interrupt/test0.scxml
	src/test/parallel+interrupt/test1.json
	src/test/parallel+interrupt/test1.scxml
	src/test/parallel+interrupt/test10.json
	src/test/parallel+interrupt/test10.scxml
	src/test/parallel+interrupt/test11.json
	src/test/parallel+interrupt/test11.scxml
	src/test/parallel+interrupt/test12.json
	src/test/parallel+interrupt/test12.scxml
	src/test/parallel+interrupt/test13.json
	src/test/parallel+interrupt/test13.scxml
	src/test/parallel+interrupt/test14.json
	src/test/parallel+interrupt/test14.scxml
	src/test/parallel+interrupt/test15.json
	src/test/parallel+interrupt/test15.scxml
	src/test/parallel+interrupt/test16.json
	src/test/parallel+interrupt/test16.scxml
	src/test/parallel+interrupt/test17.json
	src/test/parallel+interrupt/test17.scxml
	src/test/parallel+interrupt/test18.json
	src/test/parallel+interrupt/test18.scxml
	src/test/parallel+interrupt/test19.json
	src/test/parallel+interrupt/test19.scxml
	src/test/parallel+interrupt/test2.json
	src/test/parallel+interrupt/test2.scxml
	src/test/parallel+interrupt/test20.json
	src/test/parallel+interrupt/test20.scxml
	src/test/parallel+interrupt/test21.json
	src/test/parallel+interrupt/test21.scxml
	src/test/parallel+interrupt/test22.json
	src/test/parallel+interrupt/test22.scxml
	src/test/parallel+interrupt/test23.json
	src/test/parallel+interrupt/test23.scxml
	src/test/parallel+interrupt/test24.json
	src/test/parallel+interrupt/test24.scxml
	src/test/parallel+interrupt/test25.json
	src/test/parallel+interrupt/test25.scxml
	src/test/parallel+interrupt/test26.json
	src/test/parallel+interrupt/test26.scxml
	src/test/parallel+interrupt/test27.json
	src/test/parallel+interrupt/test27.scxml
	src/test/parallel+interrupt/test28.json
	src/test/parallel+interrupt/test28.scxml
	src/test/parallel+interrupt/test29.json
	src/test/parallel+interrupt/test29.scxml
	src/test/parallel+interrupt/test3.json
	src/test/parallel+interrupt/test3.scxml
	src/test/parallel+interrupt/test30.json
	src/test/parallel+interrupt/test30.scxml
	src/test/parallel+interrupt/test31.json
	src/test/parallel+interrupt/test31.scxml
	src/test/parallel+interrupt/test4.json
	src/test/parallel+interrupt/test4.scxml
	src/test/parallel+interrupt/test5.json
	src/test/parallel+interrupt/test5.scxml
	src/test/parallel+interrupt/test6.json
	src/test/parallel+interrupt/test6.scxml
	src/test/parallel+interrupt/test7.json
	src/test/parallel+interrupt/test7.scxml
	src/test/parallel+interrupt/test8.json
	src/test/parallel+interrupt/test8.scxml
	src/test/parallel+interrupt/test9.json
	src/test/parallel+interrupt/test9.scxml
	src/test/parallel/test0.json
	src/test/parallel/test0.scxml
	src/test/parallel/test1.json
	src/test/parallel/test1.scxml
	src/test/parallel/test2.json
	src/test/parallel/test2.scxml
	src/test/parallel/test3.json
	src/test/parallel/test3.scxml
	src/test/script/test0.json
	src/test/script/test0.scxml
	src/test/script/test1.json
	src/test/script/test1.scxml
	src/test/script/test2.json
	src/test/script/test2.scxml
	src/test/scxml-prefix-event-name-matching/star0.json
	src/test/scxml-prefix-event-name-matching/star0.scxml
	src/test/scxml-prefix-event-name-matching/test0.json
	src/test/scxml-prefix-event-name-matching/test0.scxml
	src/test/scxml-prefix-event-name-matching/test1.json
	src/test/scxml-prefix-event-name-matching/test1.scxml
	src/test/send-data/send1.json
	src/test/send-data/send1.scxml
	src/test/targetless-transition/test0.json
	src/test/targetless-transition/test0.scxml
	src/test/targetless-transition/test1.json
	src/test/targetless-transition/test1.scxml
	src/test/targetless-transition/test2.json
	src/test/targetless-transition/test2.scxml
	src/test/targetless-transition/test3.json
	src/test/targetless-transition/test3.scxml
  • Loading branch information...
2 parents faab352 + bf98756 commit fceaea92562784b3859282fa1a91f72bcd70807a @jbeard4 committed Mar 27, 2012
View
154 demo/drag-and-drop/drag-and-drop.xhtml
@@ -24,98 +24,98 @@ allow authoring of SVG content with inline, declarative behavioural descriptions
using SCXML:
* the document is searched for scxml elements
* it compiles them locally to JavaScript, and then hooks up event listeners on the parent DOM node,
- so that DOM events are sent to the state machine for processing
+ so that DOM events are sent to the state machine for processing
* the state machine is able to manipulate the DOM directly through executable content nodes
-->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
- <head>
- <style type="text/css">
- html, body {
- height:100%;
- margin: 0;
- padding: 0;
- }
- </style>
- <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/1.0.1/require.min.js"></script>
- <script type="text/javascript" src="http://jbeard4.github.com/SCION/builds/scion-browser-0.1.js"></script>
- <script type="text/javascript">
- require(['util/browser/parseOnLoad'],function(parseOnLoad){
- parseOnLoad()
- });
- </script>
+ <head>
+ <style type="text/css">
+ html, body {
+ height:100%;
+ margin: 0;
+ padding: 0;
+ }
+ </style>
+ <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/1.0.1/require.min.js"></script>
+ <script type="text/javascript" src="http://jbeard4.github.com/SCION/builds/scion-browser-0.1.js"></script>
+ <script type="text/javascript">
+ require(['util/browser/parseOnLoad'],function(parseOnLoad){
+ parseOnLoad()
+ });
+ </script>
- </head>
- <body>
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:scion="https://github.com/jbeard4/SCION" width="100%" height="99%" >
+ </head>
+ <body>
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:scion="https://github.com/jbeard4/SCION" width="100%" height="99%" >
- <rect width="100" height="100" stroke="black" fill="red" id="rectToTranslate" >
- <!-- the domEventsToConnect attribute is just some syntactic sugar provided by the scion parseOnLoad module -->
- <scxml
- xmlns="http://www.w3.org/2005/07/scxml"
- version="1.0"
- profile="ecmascript"
- id="scxmlRoot"
- initial="idle"
- scion:domEventsToConnect="mousedown,mouseup,mousemove">
+ <rect width="100" height="100" stroke="black" fill="red" id="rectToTranslate" >
+ <!-- the domEventsToConnect attribute is just some syntactic sugar provided by the scion parseOnLoad module -->
+ <scxml
+ xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ profile="ecmascript"
+ id="scxmlRoot"
+ initial="idle"
+ scion:domEventsToConnect="mousedown,mouseup,mousemove">
- <script>
- function computeTDelta(oldEvent,newEvent){
- //summary:computes the offset between two events; to be later used with this.translate
- var dx = newEvent.clientX - oldEvent.clientX;
- var dy = newEvent.clientY - oldEvent.clientY;
+ <script>
+ function computeTDelta(oldEvent,newEvent){
+ //summary:computes the offset between two events; to be later used with this.translate
+ var dx = newEvent.clientX - oldEvent.clientX;
+ var dy = newEvent.clientY - oldEvent.clientY;
- return {'dx':dx,'dy':dy};
- }
+ return {'dx':dx,'dy':dy};
+ }
- function translate(rawNode,tDelta){
- var tl = rawNode.transform.baseVal;
- var t = tl.numberOfItems ? tl.getItem(0) : rawNode.ownerSVGElement.createSVGTransform();
- var m = t.matrix;
- var newM = rawNode.ownerSVGElement.createSVGMatrix().translate(tDelta.dx,tDelta.dy).multiply(m);
- t.setMatrix(newM);
- tl.initialize(t);
- return newM;
- }
- </script>
+ function translate(rawNode,tDelta){
+ var tl = rawNode.transform.baseVal;
+ var t = tl.numberOfItems ? tl.getItem(0) : rawNode.ownerSVGElement.createSVGTransform();
+ var m = t.matrix;
+ var newM = rawNode.ownerSVGElement.createSVGMatrix().translate(tDelta.dx,tDelta.dy).multiply(m);
+ t.setMatrix(newM);
+ tl.initialize(t);
+ return newM;
+ }
+ </script>
- <datamodel>
- <data id="firstEvent"/>
- <data id="eventStamp"/>
- <data id="tDelta"/>
- </datamodel>
+ <datamodel>
+ <data id="firstEvent"/>
+ <data id="eventStamp"/>
+ <data id="tDelta"/>
+ </datamodel>
- <state id="idle">
- <transition event="mousedown" target="dragging">
- <assign location="firstEvent" expr="_event.data"/>
- <assign location="eventStamp" expr="_event.data"/>
- </transition>
- </state>
+ <state id="idle">
+ <transition event="mousedown" target="dragging">
+ <assign location="firstEvent" expr="_event.data"/>
+ <assign location="eventStamp" expr="_event.data"/>
+ </transition>
+ </state>
- <state id="dragging">
- <transition event="mouseup" target="idle"/>
+ <state id="dragging">
+ <transition event="mouseup" target="idle"/>
- <transition event="mousemove" target="dragging">
- <script>
- //This assignment to tDelta looks like it would assign to the global object,
- //but will in fact be assigned to the statechart's datamodel. Internally, the
- //script block is being evaluated inside of a JavaScript "with" statement,
- //where the datamodel object is the clause to "with".
- tDelta = computeTDelta(eventStamp,_event.data);
+ <transition event="mousemove" target="dragging">
+ <script>
+ //This assignment to tDelta looks like it would assign to the global object,
+ //but will in fact be assigned to the statechart's datamodel. Internally, the
+ //script block is being evaluated inside of a JavaScript "with" statement,
+ //where the datamodel object is the clause to "with".
+ tDelta = computeTDelta(eventStamp,_event.data);
- //The "this" object hereis the parent rect node.
- //This is syntactic sugar, provided by the scion interpreter's evaluationContext
- //parameter, and the parseOnLoad script. See util/browser/parseOnLoad for more details.
- translate(this,tDelta);
- </script>
- <assign location="eventStamp" expr="_event.data"/>
- </transition>
- </state>
+ //The "this" object hereis the parent rect node.
+ //This is syntactic sugar, provided by the scion interpreter's evaluationContext
+ //parameter, and the parseOnLoad script. See util/browser/parseOnLoad for more details.
+ translate(this,tDelta);
+ </script>
+ <assign location="eventStamp" expr="_event.data"/>
+ </transition>
+ </state>
- </scxml>
- </rect>
- </svg>
- </body>
+ </scxml>
+ </rect>
+ </svg>
+ </body>
</html>
View
214 demo/drag-and-drop/drag-and-drop2.xhtml
@@ -24,113 +24,113 @@ own state.
-->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
- <head>
- <style type="text/css">
- html, body {
- height:100%;
- margin: 0;
- padding: 0;
- }
- </style>
- <!-- we use jquery for jQuery.get and jQuery.globalEval (globalEval can optionally be used by the statechart) -->
- <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js" type="text/javascript"></script>
- <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/1.0.1/require.min.js"></script>
- <script type="text/javascript" src="http://jbeard4.github.com/SCION/builds/scion-browser-0.1.js"></script>
- </head>
- <body>
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="99%" id="canvas"/>
- <button id="elementButton" style="position:absolute;bottom:0px;left:0px;">Make draggable SVG Element</button>
- <script><![CDATA[
- var svgCanvas = document.getElementById("canvas"),
- elementButton = document.getElementById("elementButton"),
- SVG_NS = "http://www.w3.org/2000/svg";
-
- //hook up minimal console api
- if(typeof console == "undefined"){
- console = {};
- ["log","info","error","dirxml"].forEach(function(m){console[m] = console[m] || function(){} });
- }
-
- //the steps 1-7 referenced here are described in full detail in src/main/coffeescript/util/browser/parseOnLoad.coffee
- require(["scxml/SCXML","util/annotate-scxml-json","scxml/json2model","scxml/event","lib/JsonML_DOM"],function(scxml,jsonAnnotator,json2model,Event,JsonML){
- var BrowserInterpreter = scxml.BrowserInterpreter;
-
- //step 1 - get the scxml document
- jQuery.get("drag-and-drop2.xml" , function(scxmlToTransform, textStatus, jqXHR){
-
- console.log("scxmlToTransform",scxmlToTransform);
-
- //step 2 - transform scxmlToTransform to JSON
- var arr = JsonML.parseDOM(scxmlToTransform);
- var scxmlJson = arr[1];
- console.log("scxmlJson",scxmlJson);
-
- //step 3 - transform the parsed JSON model so it is friendlier to interpretation
- var annotatedScxmlJson = jsonAnnotator(scxmlJson);
- console.log("annotatedScxmlJson",annotatedScxmlJson);
-
- //step 4 - initialize sc object model
- var model = json2model(annotatedScxmlJson);
- console.log("model",model);
-
-
- //just for fun, random color generator, courtesy of http://stackoverflow.com/questions/1484506/random-color-generator-in-javascript
- function get_random_color() {
- var letters = '0123456789ABCDEF'.split('');
- var color = '#';
- for (var i = 0; i < 6; i++ ) {
- color += letters[Math.round(Math.random() * 15)];
- }
- return color;
- }
-
- //hook up button UI control
- elementButton.addEventListener("click",function(e){
-
- //do DOM stuff- create new blue circle
- var newGNode = document.createElementNS(SVG_NS,"g");
- var newTextNode = document.createElementNS(SVG_NS,"text");
- var newNode = document.createElementNS(SVG_NS,"circle");
- newNode.setAttributeNS(null,"cx",50);
- newNode.setAttributeNS(null,"cy",50);
- newNode.setAttributeNS(null,"r",50);
- newNode.setAttributeNS(null,"fill",get_random_color());
- newNode.setAttributeNS(null,"stroke","black");
-
- newGNode.appendChild(newNode);
- newGNode.appendChild(newTextNode);
-
- //step 5 - instantiate statechart
- var interpreter = new BrowserInterpreter(model,
- {
- //globalEval is used to execute any top-level script children of the scxml element
- //use of jQuery's global-eval is optional
- //TODO: cite that blog post about global-eval
- globalEval : jQuery.globalEval
- });
- console.log("interpreter",interpreter);
-
- //step 6 - connect all relevant event listeners
- ["mousedown","mouseup","mousemove"].forEach(function(eventName){
- newGNode.addEventListener( eventName, function(e){
- e.preventDefault();
- interpreter.gen(new Event(eventName,e))
- },false)
- });
-
- //step 7 - start statechart
- interpreter.start()
-
- //step 8 - initialize his variables by sending an "init" event and passing the nodes in as data
- interpreter.gen(new Event("init",{rawNode:newGNode,textNode:newTextNode}));
-
- svgCanvas.appendChild(newGNode);
- },false);
-
- },"xml");
- });
- ]]></script>
- </body>
+ <head>
+ <style type="text/css">
+ html, body {
+ height:100%;
+ margin: 0;
+ padding: 0;
+ }
+ </style>
+ <!-- we use jquery for jQuery.get and jQuery.globalEval (globalEval can optionally be used by the statechart) -->
+ <script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js" type="text/javascript"></script>
+ <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/require.js/1.0.1/require.min.js"></script>
+ <script type="text/javascript" src="http://jbeard4.github.com/SCION/builds/scion-browser-0.1.js"></script>
+ </head>
+ <body>
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="99%" id="canvas"/>
+ <button id="elementButton" style="position:absolute;bottom:0px;left:0px;">Make draggable SVG Element</button>
+ <script><![CDATA[
+ var svgCanvas = document.getElementById("canvas"),
+ elementButton = document.getElementById("elementButton"),
+ SVG_NS = "http://www.w3.org/2000/svg";
+
+ //hook up minimal console api
+ if(typeof console == "undefined"){
+ console = {};
+ ["log","info","error","dirxml"].forEach(function(m){console[m] = console[m] || function(){} });
+ }
+
+ //the steps 1-7 referenced here are described in full detail in src/main/coffeescript/util/browser/parseOnLoad.coffee
+ require(["scxml/SCXML","util/annotate-scxml-json","scxml/json2model","scxml/event","lib/JsonML_DOM"],function(scxml,jsonAnnotator,json2model,Event,JsonML){
+ var BrowserInterpreter = scxml.BrowserInterpreter;
+
+ //step 1 - get the scxml document
+ jQuery.get("drag-and-drop2.xml" , function(scxmlToTransform, textStatus, jqXHR){
+
+ console.log("scxmlToTransform",scxmlToTransform);
+
+ //step 2 - transform scxmlToTransform to JSON
+ var arr = JsonML.parseDOM(scxmlToTransform);
+ var scxmlJson = arr[1];
+ console.log("scxmlJson",scxmlJson);
+
+ //step 3 - transform the parsed JSON model so it is friendlier to interpretation
+ var annotatedScxmlJson = jsonAnnotator(scxmlJson);
+ console.log("annotatedScxmlJson",annotatedScxmlJson);
+
+ //step 4 - initialize sc object model
+ var model = json2model(annotatedScxmlJson);
+ console.log("model",model);
+
+
+ //just for fun, random color generator, courtesy of http://stackoverflow.com/questions/1484506/random-color-generator-in-javascript
+ function get_random_color() {
+ var letters = '0123456789ABCDEF'.split('');
+ var color = '#';
+ for (var i = 0; i < 6; i++ ) {
+ color += letters[Math.round(Math.random() * 15)];
+ }
+ return color;
+ }
+
+ //hook up button UI control
+ elementButton.addEventListener("click",function(e){
+
+ //do DOM stuff- create new blue circle
+ var newGNode = document.createElementNS(SVG_NS,"g");
+ var newTextNode = document.createElementNS(SVG_NS,"text");
+ var newNode = document.createElementNS(SVG_NS,"circle");
+ newNode.setAttributeNS(null,"cx",50);
+ newNode.setAttributeNS(null,"cy",50);
+ newNode.setAttributeNS(null,"r",50);
+ newNode.setAttributeNS(null,"fill",get_random_color());
+ newNode.setAttributeNS(null,"stroke","black");
+
+ newGNode.appendChild(newNode);
+ newGNode.appendChild(newTextNode);
+
+ //step 5 - instantiate statechart
+ var interpreter = new BrowserInterpreter(model,
+ {
+ //globalEval is used to execute any top-level script children of the scxml element
+ //use of jQuery's global-eval is optional
+ //TODO: cite that blog post about global-eval
+ globalEval : jQuery.globalEval
+ });
+ console.log("interpreter",interpreter);
+
+ //step 6 - connect all relevant event listeners
+ ["mousedown","mouseup","mousemove"].forEach(function(eventName){
+ newGNode.addEventListener( eventName, function(e){
+ e.preventDefault();
+ interpreter.gen(new Event(eventName,e))
+ },false)
+ });
+
+ //step 7 - start statechart
+ interpreter.start()
+
+ //step 8 - initialize his variables by sending an "init" event and passing the nodes in as data
+ interpreter.gen(new Event("init",{rawNode:newGNode,textNode:newTextNode}));
+
+ svgCanvas.appendChild(newGNode);
+ },false);
+
+ },"xml");
+ });
+ ]]></script>
+ </body>
</html>
View
126 demo/drag-and-drop/drag-and-drop2.xml
@@ -1,76 +1,76 @@
<scxml
- xmlns="http://www.w3.org/2005/07/scxml"
- version="1.0"
- profile="ecmascript"
- id="scxmlRoot"
- initial="initial_default">
+ xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ profile="ecmascript"
+ id="scxmlRoot"
+ initial="initial_default">
- <script>
- function computeTDelta(oldEvent,newEvent){
- //summary:computes the offset between two events; to be later used with this.translate
- var dx = newEvent.clientX - oldEvent.clientX;
- var dy = newEvent.clientY - oldEvent.clientY;
+ <script>
+ function computeTDelta(oldEvent,newEvent){
+ //summary:computes the offset between two events; to be later used with this.translate
+ var dx = newEvent.clientX - oldEvent.clientX;
+ var dy = newEvent.clientY - oldEvent.clientY;
- return {'dx':dx,'dy':dy};
- }
+ return {'dx':dx,'dy':dy};
+ }
- function translate(rawNode,tDelta){
- var tl = rawNode.transform.baseVal;
- var t = tl.numberOfItems ? tl.getItem(0) : rawNode.ownerSVGElement.createSVGTransform();
- var m = t.matrix;
- var newM = rawNode.ownerSVGElement.createSVGMatrix().translate(tDelta.dx,tDelta.dy).multiply(m);
- t.setMatrix(newM);
- tl.initialize(t);
- return newM;
- }
- </script>
+ function translate(rawNode,tDelta){
+ var tl = rawNode.transform.baseVal;
+ var t = tl.numberOfItems ? tl.getItem(0) : rawNode.ownerSVGElement.createSVGTransform();
+ var m = t.matrix;
+ var newM = rawNode.ownerSVGElement.createSVGMatrix().translate(tDelta.dx,tDelta.dy).multiply(m);
+ t.setMatrix(newM);
+ tl.initialize(t);
+ return newM;
+ }
+ </script>
- <datamodel>
- <data id="firstEvent"/>
- <data id="eventStamp"/>
- <data id="tDelta"/>
- <data id="rawNode"/>
- <data id="textNode"/>
- </datamodel>
+ <datamodel>
+ <data id="firstEvent"/>
+ <data id="eventStamp"/>
+ <data id="tDelta"/>
+ <data id="rawNode"/>
+ <data id="textNode"/>
+ </datamodel>
- <state id="initial_default">
- <transition event="init" target="idle">
- <script>
- rawNode = _event.data.rawNode;
- textNode = _event.data.textNode;
- </script>
- </transition>
- </state>
+ <state id="initial_default">
+ <transition event="init" target="idle">
+ <script>
+ rawNode = _event.data.rawNode;
+ textNode = _event.data.textNode;
+ </script>
+ </transition>
+ </state>
- <state id="idle">
- <onentry>
- <script>
- textNode.textContent='idle';
- </script>
- </onentry>
+ <state id="idle">
+ <onentry>
+ <script>
+ textNode.textContent='idle';
+ </script>
+ </onentry>
- <transition event="mousedown" target="dragging">
- <assign location="firstEvent" expr="_event.data"/>
- <assign location="eventStamp" expr="_event.data"/>
- </transition>
- </state>
+ <transition event="mousedown" target="dragging">
+ <assign location="firstEvent" expr="_event.data"/>
+ <assign location="eventStamp" expr="_event.data"/>
+ </transition>
+ </state>
- <state id="dragging">
- <onentry>
- <script>
- textNode.textContent='dragging';
- </script>
- </onentry>
+ <state id="dragging">
+ <onentry>
+ <script>
+ textNode.textContent='dragging';
+ </script>
+ </onentry>
- <transition event="mouseup" target="idle"/>
+ <transition event="mouseup" target="idle"/>
- <transition event="mousemove" target="dragging">
- <script>
- tDelta = computeTDelta(eventStamp,_event.data);
- translate(rawNode,tDelta);
- </script>
- <assign location="eventStamp" expr="_event.data"/>
- </transition>
- </state>
+ <transition event="mousemove" target="dragging">
+ <script>
+ tDelta = computeTDelta(eventStamp,_event.data);
+ translate(rawNode,tDelta);
+ </script>
+ <assign location="eventStamp" expr="_event.data"/>
+ </transition>
+ </state>
</scxml>
View
1,194 demo/drawing-tool/behaviour/canvas.xml
@@ -28,618 +28,618 @@ Only one tool can be selected at a time.
Nodes can be selected or not selected. When selected, they are surrounded by a dashed rect.
When transform tool is selected:
- If there are selected nodes, then either the rotate or translate handles will be visible, and will eb psoitioned on the aggregate bbox of all selected nodes; otherwise, if no nodes are selected, then neither rotate nor transform handles will be shown.
+ If there are selected nodes, then either the rotate or translate handles will be visible, and will eb psoitioned on the aggregate bbox of all selected nodes; otherwise, if no nodes are selected, then neither rotate nor transform handles will be shown.
- Dragging rotation handle rotates the nodes about the center point of their aggregate bbox. On mouseup, handle positions are reset.
- Dragging scale handle scales the nodes.
- Dragging selected node results in all selected nodes being dragged.
- Dragging non-selected node results in node being selected, and all other nodes being deselected.
- Dragging (no shift) on canvas results in marquee being drawn, all nodes inside of marquee being selected, and all other nodes being deselected,
- Dragging (with shift) on canvas results in marquee being drawn, all nodes inside of marquee being selected (added to selection).
+ Dragging rotation handle rotates the nodes about the center point of their aggregate bbox. On mouseup, handle positions are reset.
+ Dragging scale handle scales the nodes.
+ Dragging selected node results in all selected nodes being dragged.
+ Dragging non-selected node results in node being selected, and all other nodes being deselected.
+ Dragging (no shift) on canvas results in marquee being drawn, all nodes inside of marquee being selected, and all other nodes being deselected,
+ Dragging (with shift) on canvas results in marquee being drawn, all nodes inside of marquee being selected (added to selection).
- Mouseclick (no shift) on selected node results in rotation/scale handles being toggled.
+ Mouseclick (no shift) on selected node results in rotation/scale handles being toggled.
- Dragging node (no shift) will deselect other nodes, drag the node, and select this node.
- Dragging node (with shift) has same effect as dragging on canvas.
+ Dragging node (no shift) will deselect other nodes, drag the node, and select this node.
+ Dragging node (with shift) has same effect as dragging on canvas.
- Additionally, when no nodes are selected, and nodes are first selected, then the scale rotation handles will be shown first
- UNLESS, the last time nodes were selected, rotation handles were shown when they were deselected;
- AND, the way the nodes are being selected now is via a drag (not a click)
+ Additionally, when no nodes are selected, and nodes are first selected, then the scale rotation handles will be shown first
+ UNLESS, the last time nodes were selected, rotation handles were shown when they were deselected;
+ AND, the way the nodes are being selected now is via a drag (not a click)
When rect or ellipse drawing tools are selected:
- Rotate and translate handles will never be visible.
- When only one node is selected, then that node's resize/roundness controls will be shown.
+ Rotate and translate handles will never be visible.
+ When only one node is selected, then that node's resize/roundness controls will be shown.
- Mouseclick (no shift) on selected node HAS NO EFFECT.
+ Mouseclick (no shift) on selected node HAS NO EFFECT.
- Dragging (on canvas, rect, wherever) results in a new element being draw, created and selected. On mouseup, all other elements are deselect.
+ Dragging (on canvas, rect, wherever) results in a new element being draw, created and selected. On mouseup, all other elements are deselect.
In both:
- Mouseclick (no shift) on canvas results in all nodes being selected.
- Mouseclick (with shift) on node results in node's selection state being toggled.
+ Mouseclick (no shift) on canvas results in all nodes being selected.
+ Mouseclick (with shift) on node results in node's selection state being toggled.
- Mouseclick (no shift) on non-selected node results in node being selected, and all other nodes being deselected.
+ Mouseclick (no shift) on non-selected node results in node being selected, and all other nodes being deselected.
- Ctrl+A selects all
- Delete deletes selected nodes (and deselects them in the process, natch)
+ Ctrl+A selects all
+ Delete deletes selected nodes (and deselects them in the process, natch)
-->
<scxml
- xmlns="http://www.w3.org/2005/07/scxml"
- version="1.0"
- profile="ecmascript"
- id="scxmlRoot"
- initial="initial_default"
- name="Canvas">
-
- <script><![CDATA[
- function computeTDelta(oldEvent,newEvent){
- //summary:computes the offset between two events; to be later used with this.translate
- var dx = newEvent.clientX - oldEvent.clientX;
- var dy = newEvent.clientY - oldEvent.clientY;
-
- return {'dx':dx,'dy':dy};
- }
-
- function updateRect(node,tDelta){
- node.width.baseVal.value = tDelta.dx;
- node.height.baseVal.value = tDelta.dy;
- }
-
- function updateCircle(node,startPosition,currentPosition){
- var dxByTwo = (currentPosition.clientX - startPosition.clientX)/2;
- var dyByTwo = (currentPosition.clientY - startPosition.clientY)/2;
- node.cx.baseVal.value = startPosition.clientX + dxByTwo;
- node.cy.baseVal.value = startPosition.clientY + dyByTwo;
- node.rx.baseVal.value = dxByTwo;
- node.ry.baseVal.value = dyByTwo;
- }
-
- function updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule){
- //var sePtX = cachedBBox.width + cachedBBox.x;
- //var sePtY = cachedBBox.height + cachedBBox.y;
- var bbox = getAggregateBBox(selectedNodes,transformModule);
- var sePtX = bbox.x + bbox.width, sePtY = bbox.y + bbox.height;
-
- //TODO: make this more general
- var sScale = scaleHandle.transform.baseVal.getItem(0);
- var newM = scaleHandle.ownerSVGElement.createSVGMatrix().translate(sePtX,sePtY).
- multiply(scaleHandle.ownerSVGElement.createSVGMatrix().rotate(-45));
- sScale.setMatrix(newM);
-
- var rScale = rotationHandle.transform.baseVal.getItem(0);
- var newM = rotationHandle.ownerSVGElement.createSVGMatrix().translate(sePtX,sePtY);
- rScale.setMatrix(newM);
- }
-
- function getAggregateBBox(nodes,transformModule){
-
- //get the aggregate of the bounding boxes of his children, or if he has no hier children, get his own bbox
- var newBBox;
- if(nodes.length){
- var bboxes = nodes.map(function(n){
- return transformModule.getBoundingBoxInCanvasCoordinates(n); //FIXME: we do everything in canvas coordinates
- });
-
- var newBBoxX0 = Math.min.apply(this,bboxes.map(function(bbox){ return bbox.x }))
- var newBBoxY0 = Math.min.apply(this,bboxes.map(function(bbox){ return bbox.y }))
- var newBBoxX1 = Math.max.apply(this,bboxes.map(function(bbox){return bbox.x+bbox.width}))
- var newBBoxY1 = Math.max.apply(this,bboxes.map(function(bbox){ return bbox.y+bbox.height}))
-
- var newBBoxWidth = newBBoxX1 - newBBoxX0
- var newBBoxHeight = newBBoxY1 - newBBoxY0
-
- newBBox = {
- x : newBBoxX0,
- y : newBBoxY0,
- width : newBBoxWidth,
- height : newBBoxHeight
- };
-
- }else{
- newBBox = {
- x : 0,
- y : 0,
- width : 0,
- height : 0
- }
- }
-
- return newBBox;
-
- }
-
- function getAggregateCenterPoint(nodes,transformModule){
- var bbox = getAggregateBBox(nodes,transformModule);
-
- var cPt = {
- 'x': bbox.x + (bbox.width / 2),
- 'y': bbox.y + (bbox.height / 2)
- }
-
- return cPt;
- }
-
-
- function computeRDelta(oldEvent,newEvent,cachedCenterPoint){
- return _computeRotationAngle(cachedCenterPoint,{x:oldEvent.clientX,y:oldEvent.clientY},{x:newEvent.clientX,y:newEvent.clientY});
- }
-
- function _computeRotationAngle(cpt,pt1,pt2){
- var a1 = _computeAngle(cpt,pt1)
- var a2 = _computeAngle(cpt,pt2)
- var angleInDegrees = a2-a1
- return angleInDegrees;
- }
-
- function _computeAngle(cpt,pt){
- var angle=0;
-
- //put him on the trig circle
- var signedPt= {
- x:pt.x-cpt.x,
- y:pt.y-cpt.y
- }
-
- //put him in upper right corner
- var normalizedPt= {
- x:Math.abs(signedPt.x),
- y:Math.abs(signedPt.y)
- };
-
- //compute the angle
- var angle=Math.abs(Math.atan2(normalizedPt.y, normalizedPt.x));
-
- //get angle for signed coordinates
- if(signedPt.x<0 && signedPt.y>=0){
- angle=Math.PI-angle;
- }else if(signedPt.x<0 && signedPt.y<0){
- angle=Math.PI+angle;
- }else if(signedPt.x>=0 && signedPt.y<0){
- angle=2*Math.PI-angle;
- }
- return angle;
- }
-
- ]]></script>
-
-
- <datamodel>
- <!-- these get passed in on initiation -->
- <data id="svg"/>
- <data id="transformModule"/>
- <data id="scaleHandle"/>
- <data id="rotationHandle"/>
-
- <!-- toolbar stuff -->
- <data id="ellipseButton"/>
- <data id="ellipseIcon"/>
- <data id="rectButton"/>
- <data id="rectIcon"/>
- <data id="transformButton"/>
- <data id="transformIcon"/>
-
- <!-- constant expression -->
- <data id="svgNs" expr="'http://www.w3.org/2000/svg'"/>
-
- <!-- dynamically changing data -->
- <data id="selectedNodes" expr="[]"/>
- <data id="allNodes" expr="[]"/>
-
- </datamodel>
-
- <state id="initial_default">
- <transition event="init" target="main">
- <assign location="svg" expr="_event.data.svg"/>
- <assign location="transformModule" expr="_event.data.transformModule"/>
- <assign location="scaleHandle" expr="_event.data.scaleHandle"/>
- <assign location="rotationHandle" expr="_event.data.rotationHandle"/>
-
- <assign location="ellipseButton" expr="_event.data.ellipseButton"/>
- <assign location="ellipseIcon" expr="_event.data.ellipseIcon"/>
- <assign location="rectButton" expr="_event.data.rectButton"/>
- <assign location="rectIcon" expr="_event.data.rectIcon"/>
- <assign location="transformButton" expr="_event.data.transformButton"/>
- <assign location="transformIcon" expr="_event.data.transformIcon"/>
- </transition>
- </state>
-
-
- <parallel id="main">
-
- <state id="presentation_state" initial="rect_tool_selected">
-
- <state id="transform_tool_selected">
- <onentry>
- <script>
- //$(transformButton).addClass("selected");
- transformButton.setAttributeNS(null,"class","selected");
- </script>
- </onentry>
- <onexit>
- <script>
- //$(transformButton).removeClass("selected");
- transformButton.removeAttributeNS(null,"class");
- </script>
- </onexit>
-
-
- <initial id="transform_tool_selected_initial">
- <transition target="no_nodes_selected" cond="selectedNodes.length === 0"/>
- <transition target="nodes_selected" cond="selectedNodes.length !== 0"/>
- </initial>
-
- <state id="no_nodes_selected">
- <transition target="nodes_selected" event="NODES_SELECTED_WITH_CLICK"/>
- <transition target="nodes_selected_history" event="NODES_SELECTED_WITH_DRAG"/>
- </state>
-
- <state id="nodes_selected" initial="ready_to_scale">
-
- <onentry>
- <assign location="cachedCenterPoint" expr="getAggregateCenterPoint(selectedNodes,transformModule)"/>
- <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
- <script>
- updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
- </script>
- </onentry>
-
- <history type="shallow" id="nodes_selected_history">
- <transition target="ready_to_scale"/>
- </history>
-
- <state id="ready_to_rotate">
- <onentry>
- <script>
- rotationHandle.setAttributeNS(null,"visibility","visible");
- </script>
- </onentry>
- <onexit>
- <script>
- rotationHandle.setAttributeNS(null,"visibility","hidden");
- </script>
- </onexit>
- <transition target="ready_to_scale" event="TOGGLE_TRANSFORM"/>
- </state>
-
- <state id="ready_to_scale">
- <onentry>
- <script>
- scaleHandle.setAttributeNS(null,"visibility","visible");
- </script>
- </onentry>
- <onexit>
- <script>
- scaleHandle.setAttributeNS(null,"visibility","hidden");
- </script>
- </onexit>
- <transition target="ready_to_rotate" event="TOGGLE_TRANSFORM"/>
- </state>
-
- <transition target="no_nodes_selected" event="CHECK_NODES" cond="selectedNodes.length === 0"/>
-
- </state>
-
- <transition target="ellipse_tool_selected" event="mousedown" cond="_event.data.target === ellipseIcon"/>
- <transition target="rect_tool_selected" event="mousedown" cond="_event.data.target === rectIcon"/>
- </state>
-
- <state id="drawing_tool_selected">
- <state id="ellipse_tool_selected">
- <onentry>
- <script>
- //$(ellipseButton).addClass("selected");
- ellipseButton.setAttributeNS(null,"class","selected");
- </script>
- </onentry>
- <onexit>
- <script>
- //$(ellipseButton).removeClass("selected");
- ellipseButton.removeAttributeNS(null,"class");
- </script>
- </onexit>
-
- <transition target="rect_tool_selected" event="mousedown" cond="_event.data.target === rectIcon"/>
- </state>
-
- <state id="rect_tool_selected">
- <onentry>
- <script>
- //$(rectButton).addClass("selected");
- rectButton.setAttributeNS(null,"class","selected");
- </script>
- </onentry>
- <onexit>
- <script>
- //$(rectButton).removeClass("selected");
- rectButton.removeAttributeNS(null,"class");
- </script>
- </onexit>
-
- <transition target="ellipse_tool_selected" event="mousedown" cond="_event.data.target === ellipseIcon"/>
- </state>
-
- <!-- TODO: add reference to transform button handle -->
- <transition target="transform_tool_selected" event="mousedown" cond="_event.data.target === transformIcon"/>
- </state>
- </state>
-
- <state id="processing_events" initial="ready">
- <datamodel>
- <data id="clickedNode"/>
-
- <data id="firstEvent"/>
- <data id="eventStamp"/>
- <data id="tDelta"/>
- <data id="rDelta"/>
- <data id="cachedCenterPoint"/>
- <data id="cachedBBox"/>
-
- <data id="nodeBeingDrawn"/>
- </datamodel>
-
- <state id="ready">
- <onexit>
- <assign location="clickedNode" expr="_event.data.target"/>
-
- <assign location="firstEvent" expr="_event.data"/>
- <assign location="eventStamp" expr="_event.data"/>
- </onexit>
- <onentry>
- <script>
- updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
- </script>
- </onentry>
-
- <transition target="after_mousedown_on_selected_nodes" event="mousedown"
- cond="selectedNodes.indexOf(_event.data.target) !== -1
- &amp;&amp; !_event.data.shiftKey"/>
-
- <transition target="after_mousedown_with_shift_key_on_selected_nodes" event="mousedown"
- cond="selectedNodes.indexOf(_event.data.target) !== -1
- &amp;&amp; _event.data.shiftKey"/>
-
- <transition target="after_mousedown_on_nonselected_nodes" event="mousedown"
- cond="allNodes.indexOf(_event.data.target) !== -1
- &amp;&amp; !_event.data.shiftKey"/>
-
- <transition target="after_mousedown_with_shift_key_on_nonselected_nodes" event="mousedown"
- cond="allNodes.indexOf(_event.data.target) !== -1
- &amp;&amp; _event.data.shiftKey"/>
-
- <transition target="after_mousedown_on_canvas" event="mousedown" cond="_event.data.target === svg.root()"/>
-
- <transition target="rotating" event="mousedown"
- cond="_event.data.target === rotationHandle
- &amp;&amp; In('ready_to_rotate')"/>
-
- <transition target="scaling" event="mousedown"
- cond="_event.data.target === scaleHandle
- &amp;&amp; In('ready_to_scale')"/>
- </state>
-
- <state id="after_mousedown" initial="after_mousedown_on_selected_nodes">
-
- <state id="after_mousedown_on_selected_nodes">
- <transition target="ready" event="mouseup" >
- <if cond="In('transform_tool_selected')">
- <send event="TOGGLE_TRANSFORM"/>
- </if>
- </transition>
-
- <transition target="dragging" event="mousemove" cond="In('transform_tool_selected')">
- <!-- TODO: add dragging behaviour -->
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- </transition>
- </state>
-
- <state id="after_mousedown_with_shift_key_on_selected_nodes">
- <transition target="ready" event="mouseup">
- <script>
- //$(clickedNode).removeClass("selected");
- clickedNode.removeAttributeNS(null,"class");
-
- selectedNodes.splice(selectedNodes.indexOf(clickedNode),1);
- </script>
- <send event="CHECK_NODES"/>
- </transition>
-
- <!-- TODO: add marquee-drawing logic -->
- <transition target="drawing_marquee" event="mousemove" cond="In('transform_tool_selected')">
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- </transition>
-
- </state>
-
- <state id="after_mousedown_on_nonselected_nodes">
- <transition target="ready" event="mouseup">
- <script>
- //$(selectedNodes).removeClass("selected");
- //$(clickedNode).addClass("selected");
- selectedNodes.forEach(function(n){n.removeAttributeNS(null,"class")})
- clickedNode.setAttributeNS(null,"class","selected");
- </script>
- <assign location="selectedNodes" expr="[clickedNode]"/>
- <send event="NODES_SELECTED_WITH_CLICK"/>
- </transition>
- <transition target="dragging" event="mousemove" cond="In('transform_tool_selected')">
- <script>
- //$(selectedNodes).removeClass("selected");
- //$(clickedNode).addClass("selected");
- selectedNodes.forEach(function(n){n.removeAttributeNS(null,"class","selected")})
- clickedNode.setAttributeNS(null,"class","selected");
- </script>
- <assign location="selectedNodes" expr="[clickedNode]"/>
- <send event="NODES_SELECTED_WITH_DRAG"/>
- <!-- TODO: add dragging logic -->
-
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- </transition>
-
- </state>
-
- <!-- TODO-->
- <state id="after_mousedown_with_shift_key_on_nonselected_nodes">
- <transition target="ready" event="mouseup">
- <script>
- //$(clickedNode).addClass("selected");
- clickedNode.setAttributeNS(null,"class","selected");
-
- selectedNodes.push(clickedNode);
- </script>
- <send event="NODES_SELECTED_WITH_CLICK"/>
- </transition>
-
- <!-- TODO: add marquee-drawing logic -->
- <transition target="drawing_marquee" event="mousemove" cond="In('transform_tool_selected')">
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- </transition>
-
- </state>
-
- <state id="after_mousedown_on_canvas">
- <transition target="ready" event="mouseup">
- <script>
- //$(selectedNodes).removeClass("selected");
- selectedNodes.forEach(function(n){n.removeAttributeNS(null,"class")});
- </script>
- <assign location="selectedNodes" expr="[]"/>
- <send event="CHECK_NODES"/>
- </transition>
-
- <transition target="drawing_marquee" event="mousemove" cond="In('transform_tool_selected')">
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- </transition>
-
- </state>
-
- <transition target="drawing_rect" event="mousemove" cond="In('rect_tool_selected')">
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- <assign location="nodeBeingDrawn" expr="svg.rect(_event.data.clientX,_event.data.clientY,1,1,{'fill':'red','stroke':'black'})"/>
- </transition>
- <transition target="drawing_ellipse" event="mousemove" cond="In('ellipse_tool_selected')">
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- <assign location="nodeBeingDrawn" expr="svg.ellipse(_event.data.clientX,_event.data.clientY,1,1,{'fill':'blue','stroke':'black'})"/>
- </transition>
-
- </state>
-
- <state id="dragging">
- <transition target="dragging" event="mousemove">
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- <assign location="eventStamp" expr="_event.data"/>
- <script><![CDATA[
- for(var i=0,l=selectedNodes.length; i < l; i++){
- var n = selectedNodes[i];
-
- transformModule.translate(n,tDelta);
- }
- ]]></script>
- </transition>
- <transition target="ready" event="mouseup">
- <assign location="tDelta" expr="computeTDelta(firstEvent,eventStamp)"/>
- <assign location="cachedCenterPoint" expr="getAggregateCenterPoint(selectedNodes,transformModule)"/>
- <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
- <!-- TODO -->
- <script>
- updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
- </script>
- </transition>
- </state>
-
- <state id="rotating">
- <transition target="ready" event="mouseup">
- <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
- <script>
- updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
- </script>
- </transition>
-
- <transition target="rotating" event="mousemove">
- <assign location="rDelta" expr="computeRDelta(eventStamp,_event.data,cachedCenterPoint)"/>
- <assign location="eventStamp" expr="_event.data"/>
- <script><![CDATA[
- for(var i=0,l=selectedNodes.length; i < l; i++){
- var n = selectedNodes[i];
-
- transformModule.rotateRadians(n,rDelta,cachedCenterPoint.x,cachedCenterPoint.y);
- }
-
- transformModule.rotateRadians(rotationHandle,rDelta,cachedCenterPoint.x,cachedCenterPoint.y);
- ]]></script>
- </transition>
- </state>
-
- <state id="scaling">
- <transition target="ready" event="mouseup">
- <assign location="cachedCenterPoint" expr="getAggregateCenterPoint(selectedNodes,transformModule)"/>
- <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
- <script>
- updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
- </script>
- </transition>
- <transition target="scaling" event="mousemove">
- <script><![CDATA[
- for(var i=0,l=selectedNodes.length; i < l; i++){
- var n = selectedNodes[i];
-
- transformModule.scale(n,eventStamp,_event.data,cachedBBox)
- }
- ]]></script>
- <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
- <assign location="eventStamp" expr="_event.data"/>
- <script>
- updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
- </script>
- </transition>
- </state>
-
-
- <!-- TODO: add marquee-drawing logic -->
- <state id="drawing_marquee">
- <transition target="ready" event="mouseup">
- <!-- TODO: select what is inside marquee -->
- <send event="CHECK_NODES"/>
- </transition>
-
- <transition target="drawing_marquee" event="mousemove"/>
- </state>
-
- <state id="drawing">
- <state id="drawing_ellipse">
- <transition target="drawing_ellipse" event="mousemove">
- <script>
- updateCircle(nodeBeingDrawn,eventStamp,_event.data);
- </script>
- </transition>
- </state>
-
- <state id="drawing_rect">
- <transition target="drawing_rect" event="mousemove">
- <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
- <script>
- updateRect(nodeBeingDrawn,tDelta);
- </script>
- </transition>
- </state>
-
- <transition target="ready" event="mouseup">
- <script>
- //$(selectedNodes).removeClass("selected");
- selectedNodes.forEach(function(n){n.removeAttributeNS(null,"class")});
- </script>
- <script>
- selectedNodes = [nodeBeingDrawn];
-
- allNodes.push(nodeBeingDrawn);
-
- //$(nodeBeingDrawn).addClass("selected");
- nodeBeingDrawn.setAttributeNS(null,"class","selected");
- </script>
- </transition>
- </state>
- </state>
- </parallel>
+ xmlns="http://www.w3.org/2005/07/scxml"
+ version="1.0"
+ profile="ecmascript"
+ id="scxmlRoot"
+ initial="initial_default"
+ name="Canvas">
+
+ <script><![CDATA[
+ function computeTDelta(oldEvent,newEvent){
+ //summary:computes the offset between two events; to be later used with this.translate
+ var dx = newEvent.clientX - oldEvent.clientX;
+ var dy = newEvent.clientY - oldEvent.clientY;
+
+ return {'dx':dx,'dy':dy};
+ }
+
+ function updateRect(node,tDelta){
+ node.width.baseVal.value = tDelta.dx;
+ node.height.baseVal.value = tDelta.dy;
+ }
+
+ function updateCircle(node,startPosition,currentPosition){
+ var dxByTwo = (currentPosition.clientX - startPosition.clientX)/2;
+ var dyByTwo = (currentPosition.clientY - startPosition.clientY)/2;
+ node.cx.baseVal.value = startPosition.clientX + dxByTwo;
+ node.cy.baseVal.value = startPosition.clientY + dyByTwo;
+ node.rx.baseVal.value = dxByTwo;
+ node.ry.baseVal.value = dyByTwo;
+ }
+
+ function updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule){
+ //var sePtX = cachedBBox.width + cachedBBox.x;
+ //var sePtY = cachedBBox.height + cachedBBox.y;
+ var bbox = getAggregateBBox(selectedNodes,transformModule);
+ var sePtX = bbox.x + bbox.width, sePtY = bbox.y + bbox.height;
+
+ //TODO: make this more general
+ var sScale = scaleHandle.transform.baseVal.getItem(0);
+ var newM = scaleHandle.ownerSVGElement.createSVGMatrix().translate(sePtX,sePtY).
+ multiply(scaleHandle.ownerSVGElement.createSVGMatrix().rotate(-45));
+ sScale.setMatrix(newM);
+
+ var rScale = rotationHandle.transform.baseVal.getItem(0);
+ var newM = rotationHandle.ownerSVGElement.createSVGMatrix().translate(sePtX,sePtY);
+ rScale.setMatrix(newM);
+ }
+
+ function getAggregateBBox(nodes,transformModule){
+
+ //get the aggregate of the bounding boxes of his children, or if he has no hier children, get his own bbox
+ var newBBox;
+ if(nodes.length){
+ var bboxes = nodes.map(function(n){
+ return transformModule.getBoundingBoxInCanvasCoordinates(n); //FIXME: we do everything in canvas coordinates
+ });
+
+ var newBBoxX0 = Math.min.apply(this,bboxes.map(function(bbox){ return bbox.x }))
+ var newBBoxY0 = Math.min.apply(this,bboxes.map(function(bbox){ return bbox.y }))
+ var newBBoxX1 = Math.max.apply(this,bboxes.map(function(bbox){return bbox.x+bbox.width}))
+ var newBBoxY1 = Math.max.apply(this,bboxes.map(function(bbox){ return bbox.y+bbox.height}))
+
+ var newBBoxWidth = newBBoxX1 - newBBoxX0
+ var newBBoxHeight = newBBoxY1 - newBBoxY0
+
+ newBBox = {
+ x : newBBoxX0,
+ y : newBBoxY0,
+ width : newBBoxWidth,
+ height : newBBoxHeight
+ };
+
+ }else{
+ newBBox = {
+ x : 0,
+ y : 0,
+ width : 0,
+ height : 0
+ }
+ }
+
+ return newBBox;
+
+ }
+
+ function getAggregateCenterPoint(nodes,transformModule){
+ var bbox = getAggregateBBox(nodes,transformModule);
+
+ var cPt = {
+ 'x': bbox.x + (bbox.width / 2),
+ 'y': bbox.y + (bbox.height / 2)
+ }
+
+ return cPt;
+ }
+
+
+ function computeRDelta(oldEvent,newEvent,cachedCenterPoint){
+ return _computeRotationAngle(cachedCenterPoint,{x:oldEvent.clientX,y:oldEvent.clientY},{x:newEvent.clientX,y:newEvent.clientY});
+ }
+
+ function _computeRotationAngle(cpt,pt1,pt2){
+ var a1 = _computeAngle(cpt,pt1)
+ var a2 = _computeAngle(cpt,pt2)
+ var angleInDegrees = a2-a1
+ return angleInDegrees;
+ }
+
+ function _computeAngle(cpt,pt){
+ var angle=0;
+
+ //put him on the trig circle
+ var signedPt= {
+ x:pt.x-cpt.x,
+ y:pt.y-cpt.y
+ }
+
+ //put him in upper right corner
+ var normalizedPt= {
+ x:Math.abs(signedPt.x),
+ y:Math.abs(signedPt.y)
+ };
+
+ //compute the angle
+ var angle=Math.abs(Math.atan2(normalizedPt.y, normalizedPt.x));
+
+ //get angle for signed coordinates
+ if(signedPt.x<0 && signedPt.y>=0){
+ angle=Math.PI-angle;
+ }else if(signedPt.x<0 && signedPt.y<0){
+ angle=Math.PI+angle;
+ }else if(signedPt.x>=0 && signedPt.y<0){
+ angle=2*Math.PI-angle;
+ }
+ return angle;
+ }
+
+ ]]></script>
+
+
+ <datamodel>
+ <!-- these get passed in on initiation -->
+ <data id="svg"/>
+ <data id="transformModule"/>
+ <data id="scaleHandle"/>
+ <data id="rotationHandle"/>
+
+ <!-- toolbar stuff -->
+ <data id="ellipseButton"/>
+ <data id="ellipseIcon"/>
+ <data id="rectButton"/>
+ <data id="rectIcon"/>
+ <data id="transformButton"/>
+ <data id="transformIcon"/>
+
+ <!-- constant expression -->
+ <data id="svgNs" expr="'http://www.w3.org/2000/svg'"/>
+
+ <!-- dynamically changing data -->
+ <data id="selectedNodes" expr="[]"/>
+ <data id="allNodes" expr="[]"/>
+
+ </datamodel>
+
+ <state id="initial_default">
+ <transition event="init" target="main">
+ <assign location="svg" expr="_event.data.svg"/>
+ <assign location="transformModule" expr="_event.data.transformModule"/>
+ <assign location="scaleHandle" expr="_event.data.scaleHandle"/>
+ <assign location="rotationHandle" expr="_event.data.rotationHandle"/>
+
+ <assign location="ellipseButton" expr="_event.data.ellipseButton"/>
+ <assign location="ellipseIcon" expr="_event.data.ellipseIcon"/>
+ <assign location="rectButton" expr="_event.data.rectButton"/>
+ <assign location="rectIcon" expr="_event.data.rectIcon"/>
+ <assign location="transformButton" expr="_event.data.transformButton"/>
+ <assign location="transformIcon" expr="_event.data.transformIcon"/>
+ </transition>
+ </state>
+
+
+ <parallel id="main">
+
+ <state id="presentation_state" initial="rect_tool_selected">
+
+ <state id="transform_tool_selected">
+ <onentry>
+ <script>
+ //$(transformButton).addClass("selected");
+ transformButton.setAttributeNS(null,"class","selected");
+ </script>
+ </onentry>
+ <onexit>
+ <script>
+ //$(transformButton).removeClass("selected");
+ transformButton.removeAttributeNS(null,"class");
+ </script>
+ </onexit>
+
+
+ <initial id="transform_tool_selected_initial">
+ <transition target="no_nodes_selected" cond="selectedNodes.length === 0"/>
+ <transition target="nodes_selected" cond="selectedNodes.length !== 0"/>
+ </initial>
+
+ <state id="no_nodes_selected">
+ <transition target="nodes_selected" event="NODES_SELECTED_WITH_CLICK"/>
+ <transition target="nodes_selected_history" event="NODES_SELECTED_WITH_DRAG"/>
+ </state>
+
+ <state id="nodes_selected" initial="ready_to_scale">
+
+ <onentry>
+ <assign location="cachedCenterPoint" expr="getAggregateCenterPoint(selectedNodes,transformModule)"/>
+ <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
+ <script>
+ updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
+ </script>
+ </onentry>
+
+ <history type="shallow" id="nodes_selected_history">
+ <transition target="ready_to_scale"/>
+ </history>
+
+ <state id="ready_to_rotate">
+ <onentry>
+ <script>
+ rotationHandle.setAttributeNS(null,"visibility","visible");
+ </script>
+ </onentry>
+ <onexit>
+ <script>
+ rotationHandle.setAttributeNS(null,"visibility","hidden");
+ </script>
+ </onexit>
+ <transition target="ready_to_scale" event="TOGGLE_TRANSFORM"/>
+ </state>
+
+ <state id="ready_to_scale">
+ <onentry>
+ <script>
+ scaleHandle.setAttributeNS(null,"visibility","visible");
+ </script>
+ </onentry>
+ <onexit>
+ <script>
+ scaleHandle.setAttributeNS(null,"visibility","hidden");
+ </script>
+ </onexit>
+ <transition target="ready_to_rotate" event="TOGGLE_TRANSFORM"/>
+ </state>
+
+ <transition target="no_nodes_selected" event="CHECK_NODES" cond="selectedNodes.length === 0"/>
+
+ </state>
+
+ <transition target="ellipse_tool_selected" event="mousedown" cond="_event.data.target === ellipseIcon"/>
+ <transition target="rect_tool_selected" event="mousedown" cond="_event.data.target === rectIcon"/>
+ </state>
+
+ <state id="drawing_tool_selected">
+ <state id="ellipse_tool_selected">
+ <onentry>
+ <script>
+ //$(ellipseButton).addClass("selected");
+ ellipseButton.setAttributeNS(null,"class","selected");
+ </script>
+ </onentry>
+ <onexit>
+ <script>
+ //$(ellipseButton).removeClass("selected");
+ ellipseButton.removeAttributeNS(null,"class");
+ </script>
+ </onexit>
+
+ <transition target="rect_tool_selected" event="mousedown" cond="_event.data.target === rectIcon"/>
+ </state>
+
+ <state id="rect_tool_selected">
+ <onentry>
+ <script>
+ //$(rectButton).addClass("selected");
+ rectButton.setAttributeNS(null,"class","selected");
+ </script>
+ </onentry>
+ <onexit>
+ <script>
+ //$(rectButton).removeClass("selected");
+ rectButton.removeAttributeNS(null,"class");
+ </script>
+ </onexit>
+
+ <transition target="ellipse_tool_selected" event="mousedown" cond="_event.data.target === ellipseIcon"/>
+ </state>
+
+ <!-- TODO: add reference to transform button handle -->
+ <transition target="transform_tool_selected" event="mousedown" cond="_event.data.target === transformIcon"/>
+ </state>
+ </state>
+
+ <state id="processing_events" initial="ready">
+ <datamodel>
+ <data id="clickedNode"/>
+
+ <data id="firstEvent"/>
+ <data id="eventStamp"/>
+ <data id="tDelta"/>
+ <data id="rDelta"/>
+ <data id="cachedCenterPoint"/>
+ <data id="cachedBBox"/>
+
+ <data id="nodeBeingDrawn"/>
+ </datamodel>
+
+ <state id="ready">
+ <onexit>
+ <assign location="clickedNode" expr="_event.data.target"/>
+
+ <assign location="firstEvent" expr="_event.data"/>
+ <assign location="eventStamp" expr="_event.data"/>
+ </onexit>
+ <onentry>
+ <script>
+ updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
+ </script>
+ </onentry>
+
+ <transition target="after_mousedown_on_selected_nodes" event="mousedown"
+ cond="selectedNodes.indexOf(_event.data.target) !== -1
+ &amp;&amp; !_event.data.shiftKey"/>
+
+ <transition target="after_mousedown_with_shift_key_on_selected_nodes" event="mousedown"
+ cond="selectedNodes.indexOf(_event.data.target) !== -1
+ &amp;&amp; _event.data.shiftKey"/>
+
+ <transition target="after_mousedown_on_nonselected_nodes" event="mousedown"
+ cond="allNodes.indexOf(_event.data.target) !== -1
+ &amp;&amp; !_event.data.shiftKey"/>
+
+ <transition target="after_mousedown_with_shift_key_on_nonselected_nodes" event="mousedown"
+ cond="allNodes.indexOf(_event.data.target) !== -1
+ &amp;&amp; _event.data.shiftKey"/>
+
+ <transition target="after_mousedown_on_canvas" event="mousedown" cond="_event.data.target === svg.root()"/>
+
+ <transition target="rotating" event="mousedown"
+ cond="_event.data.target === rotationHandle
+ &amp;&amp; In('ready_to_rotate')"/>
+
+ <transition target="scaling" event="mousedown"
+ cond="_event.data.target === scaleHandle
+ &amp;&amp; In('ready_to_scale')"/>
+ </state>
+
+ <state id="after_mousedown" initial="after_mousedown_on_selected_nodes">
+
+ <state id="after_mousedown_on_selected_nodes">
+ <transition target="ready" event="mouseup" >
+ <if cond="In('transform_tool_selected')">
+ <send event="TOGGLE_TRANSFORM"/>
+ </if>
+ </transition>
+
+ <transition target="dragging" event="mousemove" cond="In('transform_tool_selected')">
+ <!-- TODO: add dragging behaviour -->
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ </transition>
+ </state>
+
+ <state id="after_mousedown_with_shift_key_on_selected_nodes">
+ <transition target="ready" event="mouseup">
+ <script>
+ //$(clickedNode).removeClass("selected");
+ clickedNode.removeAttributeNS(null,"class");
+
+ selectedNodes.splice(selectedNodes.indexOf(clickedNode),1);
+ </script>
+ <send event="CHECK_NODES"/>
+ </transition>
+
+ <!-- TODO: add marquee-drawing logic -->
+ <transition target="drawing_marquee" event="mousemove" cond="In('transform_tool_selected')">
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ </transition>
+
+ </state>
+
+ <state id="after_mousedown_on_nonselected_nodes">
+ <transition target="ready" event="mouseup">
+ <script>
+ //$(selectedNodes).removeClass("selected");
+ //$(clickedNode).addClass("selected");
+ selectedNodes.forEach(function(n){n.removeAttributeNS(null,"class")})
+ clickedNode.setAttributeNS(null,"class","selected");
+ </script>
+ <assign location="selectedNodes" expr="[clickedNode]"/>
+ <send event="NODES_SELECTED_WITH_CLICK"/>
+ </transition>
+ <transition target="dragging" event="mousemove" cond="In('transform_tool_selected')">
+ <script>
+ //$(selectedNodes).removeClass("selected");
+ //$(clickedNode).addClass("selected");
+ selectedNodes.forEach(function(n){n.removeAttributeNS(null,"class","selected")})
+ clickedNode.setAttributeNS(null,"class","selected");
+ </script>
+ <assign location="selectedNodes" expr="[clickedNode]"/>
+ <send event="NODES_SELECTED_WITH_DRAG"/>
+ <!-- TODO: add dragging logic -->
+
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ </transition>
+
+ </state>
+
+ <!-- TODO-->
+ <state id="after_mousedown_with_shift_key_on_nonselected_nodes">
+ <transition target="ready" event="mouseup">
+ <script>
+ //$(clickedNode).addClass("selected");
+ clickedNode.setAttributeNS(null,"class","selected");
+
+ selectedNodes.push(clickedNode);
+ </script>
+ <send event="NODES_SELECTED_WITH_CLICK"/>
+ </transition>
+
+ <!-- TODO: add marquee-drawing logic -->
+ <transition target="drawing_marquee" event="mousemove" cond="In('transform_tool_selected')">
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ </transition>
+
+ </state>
+
+ <state id="after_mousedown_on_canvas">
+ <transition target="ready" event="mouseup">
+ <script>
+ //$(selectedNodes).removeClass("selected");
+ selectedNodes.forEach(function(n){n.removeAttributeNS(null,"class")});
+ </script>
+ <assign location="selectedNodes" expr="[]"/>
+ <send event="CHECK_NODES"/>
+ </transition>
+
+ <transition target="drawing_marquee" event="mousemove" cond="In('transform_tool_selected')">
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ </transition>
+
+ </state>
+
+ <transition target="drawing_rect" event="mousemove" cond="In('rect_tool_selected')">
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ <assign location="nodeBeingDrawn" expr="svg.rect(_event.data.clientX,_event.data.clientY,1,1,{'fill':'red','stroke':'black'})"/>
+ </transition>
+ <transition target="drawing_ellipse" event="mousemove" cond="In('ellipse_tool_selected')">
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ <assign location="nodeBeingDrawn" expr="svg.ellipse(_event.data.clientX,_event.data.clientY,1,1,{'fill':'blue','stroke':'black'})"/>
+ </transition>
+
+ </state>
+
+ <state id="dragging">
+ <transition target="dragging" event="mousemove">
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ <assign location="eventStamp" expr="_event.data"/>
+ <script><![CDATA[
+ for(var i=0,l=selectedNodes.length; i < l; i++){
+ var n = selectedNodes[i];
+
+ transformModule.translate(n,tDelta);
+ }
+ ]]></script>
+ </transition>
+ <transition target="ready" event="mouseup">
+ <assign location="tDelta" expr="computeTDelta(firstEvent,eventStamp)"/>
+ <assign location="cachedCenterPoint" expr="getAggregateCenterPoint(selectedNodes,transformModule)"/>
+ <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
+ <!-- TODO -->
+ <script>
+ updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
+ </script>
+ </transition>
+ </state>
+
+ <state id="rotating">
+ <transition target="ready" event="mouseup">
+ <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
+ <script>
+ updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
+ </script>
+ </transition>
+
+ <transition target="rotating" event="mousemove">
+ <assign location="rDelta" expr="computeRDelta(eventStamp,_event.data,cachedCenterPoint)"/>
+ <assign location="eventStamp" expr="_event.data"/>
+ <script><![CDATA[
+ for(var i=0,l=selectedNodes.length; i < l; i++){
+ var n = selectedNodes[i];
+
+ transformModule.rotateRadians(n,rDelta,cachedCenterPoint.x,cachedCenterPoint.y);
+ }
+
+ transformModule.rotateRadians(rotationHandle,rDelta,cachedCenterPoint.x,cachedCenterPoint.y);
+ ]]></script>
+ </transition>
+ </state>
+
+ <state id="scaling">
+ <transition target="ready" event="mouseup">
+ <assign location="cachedCenterPoint" expr="getAggregateCenterPoint(selectedNodes,transformModule)"/>
+ <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
+ <script>
+ updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
+ </script>
+ </transition>
+ <transition target="scaling" event="mousemove">
+ <script><![CDATA[
+ for(var i=0,l=selectedNodes.length; i < l; i++){
+ var n = selectedNodes[i];
+
+ transformModule.scale(n,eventStamp,_event.data,cachedBBox)
+ }
+ ]]></script>
+ <assign location="cachedBBox" expr="getAggregateBBox(selectedNodes,transformModule)"/>
+ <assign location="eventStamp" expr="_event.data"/>
+ <script>
+ updateTransformHandles(selectedNodes,scaleHandle,rotationHandle,transformModule);
+ </script>
+ </transition>
+ </state>
+
+
+ <!-- TODO: add marquee-drawing logic -->
+ <state id="drawing_marquee">
+ <transition target="ready" event="mouseup">
+ <!-- TODO: select what is inside marquee -->
+ <send event="CHECK_NODES"/>
+ </transition>
+
+ <transition target="drawing_marquee" event="mousemove"/>
+ </state>
+
+ <state id="drawing">
+ <state id="drawing_ellipse">
+ <transition target="drawing_ellipse" event="mousemove">
+ <script>
+ updateCircle(nodeBeingDrawn,eventStamp,_event.data);
+ </script>
+ </transition>
+ </state>
+
+ <state id="drawing_rect">
+ <transition target="drawing_rect" event="mousemove">
+ <assign location="tDelta" expr="computeTDelta(eventStamp,_event.data)"/>
+ <script>
+ updateRect(nodeBeingDrawn,tDelta);
+ </script>
+ </transition>
+ </state>
+
+ <transition target="ready" event="mouseup">
+ <script>
+ //$(selectedNodes).removeClass("selected");
+ selectedNodes.forEach(function(n){n.removeAttributeNS(null,"class")});
+ </script>
+ <script>
+ selectedNodes = [nodeBeingDrawn];
+
+ allNodes.push(nodeBeingDrawn);
+
+ //$(nodeBeingDrawn).addClass("selected");
+ nodeBeingDrawn.setAttributeNS(null,"class","selected");
+ </script>
+ </transition>
+ </state>
+ </state>
+ </parallel>
</scxml>
View
324 demo/drawing-tool/drawing-tool.html
@@ -61,168 +61,168 @@
<script>
$(document).ready(function(){
- //hook up minimal console api
- if(typeof console == "undefined"){
- console = {};
- ["log","info","error","dirxml"].forEach(function(m){console[m] = console[m] || function(){} });
- }
-
- var scxmlns = "http://www.w3.org/2005/07/scxml";
- var svgns = "http://www.w3.org/2000/svg";
-
- $("#toolbarDiv").svg({
- onLoad:function(toolbar){
- $(toolbar.root()).attr({
- "width":"150px",
- "height":"50px"
- });
-
- $(document.body).svg({
- onLoad:function(svg){
-
- $(svg.root()).attr({
- "width":"100%",
- "height":"100%"
- });
-
- var toolbarOutlineRect = toolbar.rect(0,0,150,50,{
- fill:"white",
- stroke:"black"
- }) ;
-
- var transformButton = toolbar.group();
-
- var transformButtonBackground = toolbar.rect(transformButton,0,0,50,50,{
- class:"background"
- });
-
- //TODO: make proper icon
- var transformButtonIcon = toolbar.path(transformButton,"M 10.020877,9.916493 10.125261,39.874739 16.962422,26.878914 29.958246,39.87474 39.979123,29.958246 26.983298,16.858038 40.083507,9.916493 l -30.06263,0 z",{
- fill:"black",
- stroke:"black"
- });
-
- var rectButton = toolbar.group({"transform":"translate(50,0)"});
- var rectButtonBackground = toolbar.rect(rectButton,0,0,50,50,{
- class:"background"
- });
- var rectButtonIcon = toolbar.rect(rectButton,10,10,30,30,{
- fill:"red",
- stroke:"black"
- });
-
- var ellipseButton = toolbar.group({"transform":"translate(100,0)"});
-
- var ellipseButtonBackground = toolbar.rect(ellipseButton,0,0,50,50,{
- class:"background"
- });
-
- var ellipseButtonIcon = toolbar.circle(ellipseButton,25,25,15,{
- fill:"blue",
- stroke:"black"
- });
-
- //workaround for webkit: svg root element does not receive events on its own,
- //so we create a white background rect, and proxy events to svg element
- /*
- if($.browser.webkit){
- var backgroundRect = svg.rect(0,0,"100%","100%",{
- stroke:"none",
- fill:"white"
- })
- console.log(backgroundRect);
-
- $(["mousedown","mouseup","mousemove"]).each(function(index,eventName){
- backgroundRect.addEventListener(eventName,function(e){
- svg.root().dispatchEvent(e);
- },false)
- });
- }
- */
-
- var scaleHandle = svg.path("M 0 0 L -4 6 L -2 6 L -2 12 L -4 12 L 0 18 L 4 12 L 2 12 L 2 6 L 4 6 L 0 0 z",{
- transform:"rotate(-45)",
- visibility:"hidden"
- })
-
- var rotationHandle = svg.path("M 12 0 L 17 5 L 15 5 Q 15 15 5 15 L 5 17 L 0 12 L 5 7 L 5 9 Q 9 9 9 5 L 7 5 L 12 0 z",{
- visibility:"hidden",
- transform:"translate(0,0)"
- })
-
-
- //the steps 1-7 referenced here are described in full detail in src/main/coffeescript/util/browser/parseOnLoad.coffee
- require(["scxml/SCXML","util/annotate-scxml-json","scxml/json2model","scxml/event","lib/JsonML_DOM"],function(scxml,jsonAnnotator,json2model,SCEvent,JsonML){
- var BrowserInterpreter = scxml.BrowserInterpreter;
-
- function hookUpDOMEvents(node,interpreter){
- //hook up DOM events
- ["mousedown","mouseup","mousemove"].forEach(function(eventName){
- node.addEventListener(eventName,function(e){
- e.preventDefault();
- interpreter.gen(new SCEvent(eventName,e));
- },false);
- });
- }
-
-
- //step 1 - get the scxml document
- jQuery.get("behaviour/canvas.xml" , function(scxmlToTransform, textStatus, jqXHR){
-
- console.log("scxmlToTransform",scxmlToTransform);
-
- //step 2 - transform scxmlToTransform to JSON
- var arr = JsonML.parseDOM(scxmlToTransform);
- var scxmlJson = arr[1];
- console.log("scxmlJson",scxmlJson);
-
- //step 3 - transform the parsed JSON model so it is friendlier to interpretation
- var annotatedScxmlJson = jsonAnnotator(scxmlJson);
- console.log("annotatedScxmlJson",annotatedScxmlJson);
-
- //step 4 - initialize sc object model
- var model = json2model(annotatedScxmlJson);
- console.log("model",model);
-
- //step 5 - instantiate statechart
- var interpreter = new BrowserInterpreter(model,
- {
- //globalEval is used to execute any top-level script children of the scxml element
- //use of jQuery's global-eval is optional
- //TODO: cite that blog post about global-eval
- globalEval : jQuery.globalEval
- });
- console.log("interpreter",interpreter);
-
-
- svg.statechart = interpreter; //hook up dom node reference
-
- //step 7 - start statechart
- interpreter.start()
-
- hookUpDOMEvents(svg.root(),interpreter);
- hookUpDOMEvents(toolbar.root(),interpreter);
-
- //pass in reference to rect
- interpreter.gen(new SCEvent("init",{
- svg:svg,
- transformModule:svgLib,
- scaleHandle:scaleHandle,
- rotationHandle:rotationHandle,
- ellipseButton:ellipseButton,
- rectButton:rectButton,
- transformButton:transformButton,
- ellipseIcon:ellipseButtonIcon,
- rectIcon:rectButtonIcon,
- transformIcon:transformButtonIcon
- }));
- });
- });
-
- }
- });
- }
- });
+ //hook up minimal console api
+ if(typeof console == "undefined"){
+ console = {};
+ ["log","info","error","dirxml"].forEach(function(m){console[m] = console[m] || function(){} });
+ }
+
+ var scxmlns = "http://www.w3.org/2005/07/scxml";
+ var svgns = "http://www.w3.org/2000/svg";
+
+ $("#toolbarDiv").svg({
+ onLoad:function(toolbar){
+ $(toolbar.root()).attr({
+ "width":"150px",
+ "height":"50px"
+ });
+
+ $(document.body).svg({
+ onLoad:function(svg){
+
+ $(svg.root()).attr({
+ "width":"100%",
+ "height":"100%"
+ });
+
+ var toolbarOutlineRect = toolbar.rect(0,0,150,50,{
+ fill:"white",
+ stroke:"black"
+ }) ;
+
+ var transformButton = toolbar.group();
+
+ var transformButtonBackground = toolbar.rect(transformButton,0,0,50,50,{
+ class:"background"
+ });
+
+ //TODO: make proper icon
+ var transformButtonIcon = toolbar.path(transformButton,"M 10.020877,9.916493 10.125261,39.874739 16.962422,26.878914 29.958246,39.87474 39.979123,29.958246 26.983298,16.858038 40.083507,9.916493 l -30.06263,0 z",{
+ fill:"black",
+ stroke:"black"
+ });
+
+ var rectButton = toolbar.group({"transform":"translate(50,0)"});
+ var rectButtonBackground = toolbar.rect(rectButton,0,0,50,50,{
+ class:"background"
+ });
+ var rectButtonIcon = toolbar.rect(rectButton,10,10,30,30,{
+ fill:"red",
+ stroke:"black"
+ });
+
+ var ellipseButton = toolbar.group({"transform":"translate(100,0)"});
+
+ var ellipseButtonBackground = toolbar.rect(ellipseButton,0,0,50,50,{
+ class:"background"
+ });
+
+ var ellipseButtonIcon = toolbar.circle(ellipseButton,25,25,15,{
+ fill:"blue",
+ stroke:"black"
+ });
+
+ //workaround for webkit: svg root element does not receive events on its own,
+ //so we create a white background rect, and proxy events to svg element
+ /*
+ if($.browser.webkit){
+ var backgroundRect = svg.rect(0,0,"100%","100%",{
+ stroke:"none",
+ fill:"white"
+ })
+ console.log(backgroundRect);
+
+ $(["mousedown","mouseup","mousemove"]).each(function(index,eventName){
+ backgroundRect.addEventListener(eventName,function(e){
+ svg.root().dispatchEvent(e);
+ },false)
+ });
+ }
+ */
+
+ var scaleHandle = svg.path("M 0 0 L -4 6 L -2 6 L -2 12 L -4 12 L 0 18 L 4 12 L 2 12 L 2 6 L 4 6 L 0 0 z",{
+ transform:"rotate(-45)",
+ visibility:"hidden"
+ })
+
+ var rotationHandle = svg.path("M 12 0 L 17 5 L 15 5 Q 15 15 5 15 L 5 17 L 0 12 L 5 7 L 5 9 Q 9 9 9 5 L 7 5 L 12 0 z",{
+ visibility:"hidden",
+ transform:"translate(0,0)"
+ })
+
+
+ //the steps 1-7 referenced here are described in full detail in src/main/coffeescript/util/browser/parseOnLoad.coffee
+ require(["scxml/SCXML","util/annotate-scxml-json","scxml/json2model","scxml/event","lib/JsonML_DOM"],function(scxml,jsonAnnotator,json2model,SCEvent,JsonML){
+ var BrowserInterpreter = scxml.BrowserInterpreter;
+
+ function hookUpDOMEvents(node,interpreter){
+ //hook up DOM events
+ ["mousedown","mouseup","mousemove"].forEach(function(eventName){
+ node.addEventListener(eventName,function(e){
+ e.preventDefault();
+ interpreter.gen(new SCEvent(eventName,e));
+ },false);
+ });
+ }
+
+
+ //step 1 - get the scxml document
+ jQuery.get("behaviour/canvas.xml" , function(scxmlToTransform, textStatus, jqXHR){
+
+ console.log("scxmlToTransform",scxmlToTransform);
+
+ //step 2 - transform scxmlToTransform to JSON
+ var arr = JsonML.parseDOM(scxmlToTransform);
+ var scxmlJson = arr[1];
+ console.log("scxmlJson",scxmlJson);
+
+ //step 3 - transform the parsed JSON model so it is friendlier to interpretation
+ var annotatedScxmlJson = jsonAnnotator(scxmlJson);
+ console.log("annotatedScxmlJson",annotatedScxmlJson);
+
+ //step 4 - initialize sc object model
+ var model = json2model(annotatedScxmlJson);
+ console.log("model",model);
+
+ //step 5 - instantiate statechart
+ var interpreter = new BrowserInterpreter(model,
+ {
+ //globalEval is used to execute any top-level script children of the scxml element
+ //use of jQuery's global-eval is optional
+ //TODO: cite that blog post about global-eval
+ globalEval : jQuery.globalEval
+ });
+ console.log("interpreter",interpreter);
+
+
+ svg.statechart = interpreter; //hook up dom node reference
+
+ //step 7 - start statechart
+ interpreter.start()
+
+ hookUpDOMEvents(svg.root(),interpreter);
+ hookUpDOMEvents(toolbar.root(),interpreter);
+
+ //pass in reference to rect
+ interpreter.gen(new SCEvent("init",{
+ svg:svg,
+ transformModule:svgLib,
+ scaleHandle:scaleHandle,
+ rotationHandle:rotationHandle,
+ ellipseButton:ellipseButton,
+ rectButton:rectButton,
+ transformButton:transformButton,
+ ellipseIcon:ellipseButtonIcon,
+ rectIcon:rectButtonIcon,
+ transformIcon:transformButtonIcon
+ }));
+ });
+ });
+
+ }
+ });
+ }
+ });
});
View
6 demo/drawing-tool/lib/jquery.svg.css
@@ -6,10 +6,10 @@
Please attribute the author if you use it. */
svg\:svg {
- display: none;
+ display: none;
}