drawing.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. this.initialize = function() {
  2. this.drawing_private = {};
  3. this.future(0).clientWatch();
  4. };
  5. this.clientWatch = function() {
  6. var clients = this.find( "doc('http://vwf.example.com/clients.vwf')" )[0];
  7. if ( clients !== undefined ) {
  8. clients.children.added = clients.events.add( function( index, child ) {
  9. this.clientJoin( this.moniker );
  10. }, this );
  11. clients.children.removed = clients.events.add( function( index, child ) {
  12. this.clientLeave( this.moniker );
  13. }, this );
  14. }
  15. };
  16. // this.isValid = function( obj ) {
  17. // var objType = ( {} ).toString.call( obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
  18. // return ( objType != 'null' && objType != 'undefined' );
  19. // };
  20. this.clientJoin = function( moniker ) {
  21. function isValid( obj ) {
  22. var objType = ( {} ).toString.call( obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
  23. return ( objType != 'null' && objType != 'undefined' );
  24. };
  25. // mirrors the initial state of the toolbar
  26. if ( !isValid( this.drawing_clients ) ) {
  27. this.drawing_clients = {};
  28. }
  29. if ( this.drawing_clients[ moniker ] === undefined ) {
  30. this.drawing_clients[ moniker ] = {
  31. "drawing_mode": 'none',
  32. "drawing_visible": 'inherit',
  33. "drawing_color": 'black',
  34. "drawing_width": 4,
  35. "drawing_parentPath": '/',
  36. "drawing_opacity": 1.0,
  37. "nameIndex": 1,
  38. "fontSize": 16,
  39. "angle": 30
  40. };
  41. }
  42. this.drawing_clients = this.drawing_clients;
  43. };
  44. this.clientLeave = function( moniker ) {
  45. if ( this.drawing_clients[ moniker ] !== undefined ) {
  46. delete this.drawing_clients[ moniker ];
  47. this.drawing_clients = this.drawing_clients;
  48. }
  49. if ( this.drawing_private[ moniker ] !== undefined ) {
  50. delete this.drawing_private[ moniker ];
  51. }
  52. };
  53. this.setUpPrivate = function( moniker ) {
  54. if ( this.drawing_private === undefined ) {
  55. this.drawing_private = {};
  56. }
  57. if ( this.drawing_private[ moniker ] === undefined ) {
  58. this.drawing_private[ moniker ] = {
  59. "drawingObject": null,
  60. "initialDownPoint": [ -1, -1 ],
  61. "previousPoint": [ -1, -1 ],
  62. "mouseDown": false
  63. };
  64. }
  65. };
  66. this.setClientUIState = function( stateObj ) {
  67. function isValid( obj ) {
  68. var objType = ( {} ).toString.call( obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
  69. return ( objType != 'null' && objType != 'undefined' );
  70. };
  71. //console.info( "setClientUIState " + JSON.stringify( stateObj ) );
  72. if ( stateObj !== undefined ) {
  73. if ( !isValid( this.drawing_clients ) ||
  74. !isValid( this.drawing_clients[ this.client ] ) ) {
  75. this.clientJoin( this.client );
  76. }
  77. var clients = this.drawing_clients;
  78. var userState = clients[ this.client ];
  79. for ( var property in stateObj ) {
  80. userState[ property ] = stateObj[ property ];
  81. }
  82. this.drawing_clients = clients;
  83. }
  84. };
  85. this.down = function( eventData, nodeData, touch ) {
  86. function isValid( obj ) {
  87. var objType = ( {} ).toString.call( obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
  88. return ( objType != 'null' && objType != 'undefined' );
  89. };
  90. if ( !isValid( this.drawing_clients ) ||
  91. !isValid( this.drawing_clients[ this.client ] ) ) {
  92. this.clientJoin( this.client );
  93. }
  94. if ( !isValid( this.drawing_private ) ||
  95. !isValid( this.drawing_private[ this.client ] ) ) {
  96. this.setUpPrivate( this.client );
  97. }
  98. var userState = this.drawing_clients[ this.client ];
  99. var privateState = this.drawing_private[ this.client ];
  100. var drawingMode = userState.drawing_mode;
  101. if ( privateState.drawingObject !== null || drawingMode === 'none' ) {
  102. return;
  103. }
  104. var compExtends = undefined;
  105. var groupExtends = undefined;
  106. var section = "/shapes";
  107. if ( drawingMode === "freeDraw" ) {
  108. section = "/lines";
  109. }
  110. switch ( drawingMode ) {
  111. case "arc":
  112. case "circle":
  113. case "ellipse":
  114. case "regularPolygon":
  115. case "rect":
  116. case "ring":
  117. case "star":
  118. case "wedge":
  119. compExtends = [ "http://vwf.example.com/kinetic/", drawingMode, ".vwf" ].join('');
  120. break;
  121. case "sprite":
  122. case "text":
  123. case "image":
  124. groupExtends = "http://vwf.example.com/kinetic/drawingGroup.vwf";
  125. compExtends = {
  126. "border": "http://vwf.example.com/kinetic/line.vwf",
  127. "content": [ "http://vwf.example.com/kinetic/", drawingMode, ".vwf" ].join('')
  128. };
  129. break;
  130. case "arrow":
  131. groupExtends = "http://vwf.example.com/kinetic/drawingGroup.vwf";
  132. compExtends = {
  133. "line": "http://vwf.example.com/kinetic/line.vwf",
  134. "head": "http://vwf.example.com/kinetic/regularPolygon.vwf"
  135. };
  136. break;
  137. case "thickArrow":
  138. groupExtends = "http://vwf.example.com/kinetic/drawingGroup.vwf";
  139. compExtends = {
  140. "line": "http://vwf.example.com/kinetic/line.vwf",
  141. "head": "http://vwf.example.com/kinetic/regularPolygon.vwf"
  142. };
  143. break;
  144. case "borderRect":
  145. case "line":
  146. case "freeDraw":
  147. compExtends = "http://vwf.example.com/kinetic/line.vwf";
  148. break;
  149. case 'none':
  150. default:
  151. break;
  152. }
  153. var getDefaultProperties = function( drawingMode, groupParent, eventPoint ) {
  154. var retObj = {
  155. "visible": 'inherit',
  156. "listening": 'inherit',
  157. "opacity": userState.drawing_opacity,
  158. "z-index": 4
  159. };
  160. switch( drawingMode ) {
  161. case "sprite":
  162. //case "text":
  163. case "image":
  164. retObj.opacity = 1.0;
  165. retObj.scaleOnLoad = true;
  166. break;
  167. default:
  168. retObj.fill = userState.drawing_color;
  169. break;
  170. }
  171. if ( groupParent ) {
  172. retObj.x = 0;
  173. retObj.y = 0;
  174. retObj.position = [ 0, 0 ];
  175. } else {
  176. retObj.x = eventPoint[ 0 ];
  177. retObj.y = eventPoint[ 1 ];
  178. retObj.position = eventPoint;
  179. }
  180. return retObj;
  181. };
  182. var eventPointDown = eventData.stageRelative;
  183. if ( groupExtends !== undefined ) {
  184. privateState.initialDownPoint = eventPointDown;
  185. var parentPath = userState.drawing_parentPath + section ;
  186. var parents = this.find( parentPath );
  187. // find was failing 9/2/14, and the code below
  188. // was a backup, going to leave this in until we feel good
  189. // about the issues we saw are no longer a problem
  190. if ( parents === undefined ) {
  191. parents = [ this.findChild( this, parentPath.split( '/' ) ) ];
  192. }
  193. var parent = parents.length > 0 ? parents[ 0 ] : this;
  194. var groupDef = {
  195. "extends": groupExtends,
  196. "properties": {
  197. "visible": false,
  198. "listening": false,
  199. "position": eventPointDown
  200. },
  201. "children": {}
  202. };
  203. for ( var def in compExtends ) {
  204. groupDef.children[ def ] = {
  205. "extends": compExtends[ def ],
  206. "properties": getDefaultProperties( drawingMode, true, eventPointDown )
  207. }
  208. }
  209. var self = this;
  210. var selfMoniker = this.client;
  211. var name = drawingMode + this.drawing_index;
  212. this.drawing_index = this.drawing_index + 1;
  213. parent.children.create( name, groupDef, function( child ) {
  214. self.drawing_private[ selfMoniker ].drawingObject = child;
  215. } );
  216. } else if ( compExtends !== undefined ) {
  217. privateState.initialDownPoint = eventPointDown;
  218. var parentPath = userState.drawing_parentPath + section;
  219. var parents = this.find( parentPath );
  220. // find was failing 9/2/14, and the code below
  221. // was a backup, going to leave this in until we feel good
  222. // about the issues we saw are no longer a problem
  223. if ( parents === undefined ) {
  224. parents = [ this.findChild( this, parentPath.split( '/' ) ) ];
  225. }
  226. var parent = parents.length > 0 ? parents[ 0 ] : this;
  227. var shapeDef = {
  228. "extends": compExtends,
  229. "properties": getDefaultProperties( drawingMode, false, eventPointDown )
  230. };
  231. var self = this;
  232. var selfMoniker = this.client;
  233. var name = drawingMode + this.drawing_index;
  234. this.drawing_index = this.drawing_index + 1;
  235. parent.children.create( name, shapeDef, function( child ) {
  236. self.drawing_private[ selfMoniker ].drawingObject = child;
  237. } );
  238. }
  239. };
  240. this.move = function( eventData, nodeData, touch ) {
  241. function isValid( obj ) {
  242. var objType = ( {} ).toString.call( obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
  243. return ( objType != 'null' && objType != 'undefined' );
  244. };
  245. if ( !isValid( this.drawing_clients ) ||
  246. !isValid( this.drawing_clients[ this.client ] ) ) {
  247. this.clientJoin( this.client );
  248. }
  249. if ( this.drawing_private === undefined ||
  250. this.drawing_private[ this.client ] === undefined ) {
  251. this.setUpPrivate( this.client );
  252. }
  253. var userState = this.drawing_clients[ this.client ];
  254. if ( userState.drawing_mode === 'none' ) {
  255. return;
  256. }
  257. this.update( eventData, nodeData, false );
  258. };
  259. this.up = function( eventData, nodeData, touch ) {
  260. if ( this.drawing_private[ this.client ] !== undefined &&
  261. this.drawing_private[ this.client ].drawingObject !== null ) {
  262. var drawingObject = this.drawing_private[ this.client ].drawingObject;
  263. this.update( eventData, nodeData, true );
  264. this.drawingObjectCreated( drawingObject.id );
  265. var userState = this.drawing_clients[ this.client ];
  266. if ( this.moniker === this.client ) {
  267. switch( userState.drawing_mode ) {
  268. case "text":
  269. this.textCreated( drawingObject.content.id );
  270. break;
  271. case "sprite":
  272. case "image":
  273. this.imageCreated( drawingObject.content.id );
  274. break;
  275. }
  276. }
  277. switch( userState.drawing_mode ) {
  278. case "text":
  279. case "sprite":
  280. case "image":
  281. drawingObject.border.visible = false;
  282. break;
  283. }
  284. this.drawing_private[ this.client ].drawingObject = null;
  285. }
  286. };
  287. this.update = function( eventData, nodeData, upEvent ) {
  288. function isValid( obj ) {
  289. var objType = ( {} ).toString.call( obj ).match( /\s([a-zA-Z]+)/ )[ 1 ].toLowerCase();
  290. return ( objType != 'null' && objType != 'undefined' );
  291. };
  292. if ( this.drawing_private === undefined ||
  293. this.drawing_private[ this.client ] === undefined ||
  294. !isValid( this.drawing_clients ) ) {
  295. return;
  296. }
  297. if ( this.drawing_private[ this.client ].drawingObject !== null ) {
  298. var eventPoint = eventData.stageRelative;
  299. var userState = this.drawing_clients[ this.client ];
  300. var privateState = this.drawing_private[ this.client ];
  301. var drawingObject = privateState.drawingObject;
  302. var pointAccepted = true;
  303. if ( drawingObject.visible !== userState.drawing_visible ) {
  304. drawingObject.visible = userState.drawing_visible;
  305. }
  306. if ( drawingObject.listening !== userState.drawing_listening ) {
  307. drawingObject.listening = userState.drawing_listening;
  308. }
  309. var diffX = eventPoint[ 0 ] - privateState.initialDownPoint[ 0 ];
  310. var diffY = eventPoint[ 1 ] - privateState.initialDownPoint[ 1 ];
  311. var pos = [ privateState.initialDownPoint[ 0 ], privateState.initialDownPoint[ 1 ] ];
  312. var width = diffX;
  313. var height = diffY;
  314. var dist = Math.sqrt( ( diffX * diffX ) + ( diffY * diffY ) );
  315. //console.info( "== "+userState.drawing_mode +" ==" );
  316. //console.info( "== pos: " + pos + " diffX: " + diffX + " diffY: " + diffY );
  317. // this keeps the pos as the top left corner for the
  318. // rectangular objects
  319. switch ( userState.drawing_mode ) {
  320. case "line":
  321. case "arrow":
  322. case "thickArrow":
  323. case "freeDraw":
  324. break;
  325. default:
  326. if ( diffX < 0 ) {
  327. pos[ 0 ] += diffX;
  328. width = Math.abs( diffX );
  329. }
  330. if ( diffY < 0 ) {
  331. pos[ 1 ] += diffY;
  332. height = Math.abs( diffY );
  333. }
  334. drawingObject.position = pos;
  335. drawingObject.width = width;
  336. drawingObject.height = height;
  337. break;
  338. }
  339. //console.info( "== pos: " + pos + " diffX: " + diffX + " diffY: " + diffY );
  340. switch ( userState.drawing_mode ) {
  341. case "arc":
  342. drawingObject.angle = userState.angle ? userState.angle : 30;
  343. if ( dist > this.drawing_width ) {
  344. drawingObject.innerRadius = dist - this.drawing_width;
  345. drawingObject.outerRadius = dist;
  346. }
  347. break;
  348. case "ellipse":
  349. drawingObject.radius = { "x": width * 0.5, "y": height * 0.5 };
  350. break;
  351. case "circle":
  352. drawingObject.radius = dist;
  353. break;
  354. case "line":
  355. drawingObject.stroke = userState.drawing_color;
  356. drawingObject.strokeWidth = userState.drawing_width;
  357. drawingObject.points = [ 0, 0, diffX, diffY ];
  358. break;
  359. case "freeDraw":
  360. drawingObject.stroke = userState.drawing_color;
  361. drawingObject.strokeWidth = userState.drawing_width;
  362. var isFirstStrokeOfNewLine = ( drawingObject.points.length === 0 );
  363. var posX = eventPoint[ 0 ] - drawingObject.x;
  364. var posY = eventPoint[ 1 ] - drawingObject.y;
  365. if ( isFirstStrokeOfNewLine ) {
  366. if ( Math.abs( posX ) + Math.abs( posY ) > 0 ) {
  367. drawingObject.points = [ 0, 0, posX, posY ];
  368. } else {
  369. pointAccepted = false;
  370. }
  371. } else {
  372. var dragDiff = [
  373. posX - privateState.previousPoint[ 0 ],
  374. posY - privateState.previousPoint[ 1 ]
  375. ];
  376. if ( Math.abs( dragDiff[0] ) + Math.abs( dragDiff[1] ) > 0 ) {
  377. drawingObject.points.push( posX );
  378. drawingObject.points.push( posY );
  379. } else {
  380. pointAccepted = false;
  381. }
  382. }
  383. break;
  384. case "regularPolygon":
  385. // needs defining
  386. break;
  387. case "ring":
  388. if ( dist > userState.drawing_width ) {
  389. drawingObject.innerRadius = dist - userState.drawing_width;
  390. drawingObject.outerRadius = dist;
  391. }
  392. break;
  393. case "star":
  394. drawingObject.points = 5;
  395. drawingObject.innerRadius = dist * 80;
  396. drawingObject.outerRadius = dist;
  397. break;
  398. case "wedge":
  399. // needs defining
  400. drawingObject.angle = userState.angle ? userState.angle : 30;
  401. drawingObject.radius = dist;
  402. drawingObject.clockwise = false;
  403. break;
  404. case "borderRect":
  405. drawingObject.stroke = userState.drawing_color;
  406. drawingObject.strokeWidth = userState.drawing_width;
  407. drawingObject.points = [ 0, 0, width, 0, width, height, 0, height, 0, 0 ];
  408. break;
  409. case "arrow":
  410. drawingObject.x = drawingObject.position[ 0 ];
  411. drawingObject.y = drawingObject.position[ 1 ];
  412. drawingObject.line.stroke = userState.drawing_color;
  413. drawingObject.line.strokeWidth = userState.drawing_width;
  414. drawingObject.line.position = [ 0, 0 ];
  415. drawingObject.head.sides = 3;
  416. drawingObject.head.radius = userState.drawing_width * 3;
  417. var endPoint = goog.vec.Vec2.createFloat32FromValues( 0, 0 );
  418. var relativeXDiff = eventPoint[ 0 ] - drawingObject.x;
  419. var relativeYDiff = eventPoint[ 1 ] - drawingObject.y;
  420. var headOffset = ( userState.drawing_width * 3 ) * Math.sin( Math.PI / 6 );
  421. var dir = goog.vec.Vec2.createFloat32FromValues( relativeXDiff, relativeYDiff );
  422. var len = goog.vec.Vec2.distance( goog.vec.Vec2.createFloat32FromValues( 0, 0 ), dir );
  423. goog.vec.Vec2.normalize( dir, dir );
  424. drawingObject.head.rotation = Math.atan2( dir[1], dir[0] ) * ( 180 / Math.PI ) - 30;
  425. goog.vec.Vec2.scale( dir, len - ( userState.drawing_width * 3 ), endPoint );
  426. drawingObject.head.position = [ endPoint[0], endPoint[1] ];
  427. goog.vec.Vec2.scale( dir, len - ( ( userState.drawing_width * 3 ) + headOffset ), endPoint );
  428. drawingObject.line.points = [ 0, 0, endPoint[0], endPoint[1] ];
  429. break;
  430. case "thickArrow":
  431. drawingObject.x = drawingObject.position[ 0 ];
  432. drawingObject.y = drawingObject.position[ 1 ];
  433. drawingObject.line.stroke = userState.drawing_color;
  434. drawingObject.line.strokeWidth = userState.drawing_width * 8;
  435. drawingObject.line.position = [ 0, 0 ];
  436. drawingObject.head.sides = 3;
  437. drawingObject.head.radius = userState.drawing_width * 8;
  438. var endPoint = goog.vec.Vec2.createFloat32FromValues( 0, 0 );
  439. var relativeXDiff = eventPoint[ 0 ] - drawingObject.x;
  440. var relativeYDiff = eventPoint[ 1 ] - drawingObject.y;
  441. var headOffset = ( userState.drawing_width * 8 ) * Math.sin( Math.PI / 6 );
  442. var dir = goog.vec.Vec2.createFloat32FromValues( relativeXDiff, relativeYDiff );
  443. var len = goog.vec.Vec2.distance( goog.vec.Vec2.createFloat32FromValues( 0, 0 ), dir );
  444. goog.vec.Vec2.normalize( dir, dir );
  445. drawingObject.head.rotation = Math.atan2( dir[1], dir[0] ) * ( 180 / Math.PI ) - 30;
  446. goog.vec.Vec2.scale( dir, len - ( userState.drawing_width * 8 ), endPoint );
  447. drawingObject.head.position = [ endPoint[0], endPoint[1] ];
  448. goog.vec.Vec2.scale( dir, len - ( ( userState.drawing_width * 8 ) + headOffset ), endPoint );
  449. drawingObject.line.points = [ 0, 0, endPoint[0], endPoint[1] ];
  450. break;
  451. case "sprite":
  452. case "image":
  453. drawingObject.border.stroke = userState.drawing_color;
  454. drawingObject.border.strokeWidth = 4;
  455. drawingObject.border.points = [ 0, 0, width, 0, width, height, 0, height, 0, 0 ];
  456. drawingObject.content.width = width;
  457. drawingObject.content.height = height;
  458. break;
  459. case "text":
  460. drawingObject.border.stroke = userState.drawing_color;
  461. drawingObject.border.strokeWidth = 4;
  462. drawingObject.border.points = [ 0, 0, width, 0, width, height, 0, height, 0, 0 ];
  463. drawingObject.content.fontSize = userState.fontSize ? userState.fontSize : 16;
  464. break;
  465. case "rect":
  466. default:
  467. break;
  468. }
  469. if ( pointAccepted ) {
  470. privateState.previousPoint = eventPoint;
  471. }
  472. }
  473. };
  474. this.pointerDown = function( eventData, nodeData ) {
  475. this.down( eventData, nodeData, false );
  476. };
  477. this.pointerMove = function( eventData, nodeData ) {
  478. this.move( eventData, nodeData, false );
  479. };
  480. this.pointerUp = function( eventData, nodeData ) {
  481. this.up( eventData, nodeData, false );
  482. };
  483. this.touchStart = function( eventData, nodeData ) {
  484. this.down( eventData, nodeData, true );
  485. };
  486. this.touchMove = function( eventData, nodeData ) {
  487. this.move( eventData, nodeData, true );
  488. };
  489. this.touchEnd = function( eventData, nodeData ) {
  490. this.up( eventData, nodeData, true );
  491. };
  492. this.findChild = function( parent, names ) {
  493. if ( names.length > 0 ) {
  494. var childName = names.shift();
  495. while ( childName === "" ) {
  496. childName = names.shift();
  497. }
  498. if ( parent.children[ childName ] ) {
  499. if ( names.length === 0 ) {
  500. return parent.children[ childName ];
  501. } else {
  502. return this.findChild( parent.children[ childName ], names );
  503. }
  504. }
  505. else {
  506. return undefined;
  507. }
  508. }
  509. return undefined;
  510. }
  511. //@ sourceURL=kinetic_drawing.js