{"id":218,"date":"2011-01-13T15:22:57","date_gmt":"2011-01-13T14:22:57","guid":{"rendered":"http:\/\/www.capri-soft.de\/blog\/?p=218"},"modified":"2011-04-12T09:16:20","modified_gmt":"2011-04-12T07:16:20","slug":"flex-3-bemalbares-canvas-mit-fluorinefx-messaging-montagsmaler","status":"publish","type":"post","link":"https:\/\/www.capri-soft.de\/blog\/?p=218","title":{"rendered":"Flex 3: Bemalbares mx:Canvas mit FluorineFX-Messaging (Montagsmaler)"},"content":{"rendered":"<h1>Aufgabenstellung<\/h1>\n<p>Unter Verwendung der FluorineFX Messaging-API soll eine Montagsmaler-Anwendung implementiert werden. Dies bedeutet dass ein User auf eine Leinwand zeichnet und die anderen Seitenbesucher in Echtzeit eine Aktualisierung auf dem Bildschirm erhalten. Dies kann auch als Grundlage f\u00fcr weitere Kollaborationsanwendungen genutzt werden, in denen man gemeinsam ein Dokument konstruieren m\u00f6chte. <\/p>\n<h1>Ansatz<\/h1>\n<p>Nachdem die Zeichnenfunktionalit\u00e4t implementiert ist, werden die Bildpunkte beim loslassen der Maustaste (MOUSE_RELEASE_EVENT) an alle Clients \u00fcbertragen. Die Clients reagieren bei einer einkommenden Menge an Bildpunkten und zeichnen sofort auf die Leinwand. Es wird immer die komplette Leinwand mit allen Bildpunkten beim Mouse-Release gesendet. <\/p>\n<p>Durch das Publisher\/Subscriber-Prinzip abonniert die Flex-Anwendung beim Start sofort die Datenquelle &#8222;<strong>painter<\/strong>&#8222;. Die Datenquelle erh\u00e4lt Bildpunkte und verteilt sie an alle Abonennten, wenn diese nach dem zeichnen die Maus gesehn lassen. <\/p>\n<h1>Vorraussetzungen<\/h1>\n<p>Die FluorineFX-Konfigurationsdatei wird angepasst, so das es eine neue Messaging Quelle &#8222;painter&#8220; existiert. <\/p>\n<h2>Konfiguration des Backends<\/h2>\n<p>services-config.xml:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt; \r\n&lt;services-config&gt;\r\n    &lt;services&gt;\r\n        &lt;service-include file-path=&quot;remoting-config.xml&quot; \/&gt;\r\n        &lt;service-include file-path=&quot;messaging-config.xml&quot; \/&gt;\r\n    &lt;\/services&gt;\r\n    \r\n    &lt;!-- Custom authentication --&gt;\r\n    &lt;security&gt;\r\n    &lt;\/security&gt;\r\n    \r\n    &lt;channels&gt;\r\n        &lt;channel-definition id=&quot;my-amf&quot; class=&quot;mx.messaging.channels.AMFChannel&quot;&gt;\r\n           &lt;endpoint uri=&quot;http:\/\/{server.name}:{server.port}\/{context.root}\/Gateway.aspx&quot; \r\n             class=&quot;flex.messaging.endpoints.AMFEndpoint&quot;\/&gt; \r\n            &lt;properties&gt;\r\n            &lt;\/properties&gt;\r\n        &lt;\/channel-definition&gt;\r\n\r\n        &lt;channel-definition id=&quot;my-rtmp&quot; class=&quot;mx.messaging.channels.RTMPChannel&quot;&gt;\r\n            &lt;endpoint uri=&quot;rtmp:\/\/{server.name}:2037&quot; \r\n            class=&quot;flex.messaging.endpoints.RTMPEndpoint&quot;\/&gt;\r\n            &lt;properties&gt;\r\n                &lt;idle-timeout-minutes&gt;20&lt;\/idle-timeout-minutes&gt;\r\n            &lt;\/properties&gt;\r\n        &lt;\/channel-definition&gt;\r\n\r\n    &lt;\/channels&gt;\r\n&lt;\/services-config&gt;\r\n<\/pre>\n<p>messaging-config.xml:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;\r\n&lt;service id=&quot;message-service&quot; class=&quot;flex.messaging.services.MessageService&quot; \r\n    messageTypes=&quot;flex.messaging.messages.AsyncMessage&quot;&gt;\r\n\r\n     &lt;!-- DO NOT CHANGE &lt;adapters&gt; SECTION--&gt;\r\n    &lt;adapters&gt;\r\n\t&lt;adapter-definition id=&quot;messagingAdapter&quot; \r\n             class=&quot;FluorineFx.Messaging.Services.Messaging.MessagingAdapter&quot; \r\n             default=&quot;true&quot;\/&gt;\r\n    &lt;\/adapters&gt;\r\n    &lt;destination id=&quot;chat&quot;&gt;\r\n\t&lt;adapter ref=&quot;messagingAdapter&quot;\/&gt;\r\n        &lt;properties&gt;\r\n            &lt;network&gt;\r\n                &lt;session-timeout&gt;0&lt;\/session-timeout&gt;\r\n            &lt;\/network&gt;\r\n        &lt;\/properties&gt;\r\n        &lt;channels&gt;\r\n            &lt;channel ref=&quot;my-rtmp&quot;\/&gt;\r\n        &lt;\/channels&gt;\r\n    &lt;\/destination&gt;\r\n    &lt;destination id=&quot;textchat&quot;&gt;\r\n\t&lt;adapter ref=&quot;messagingAdapter&quot;\/&gt;\r\n        &lt;properties&gt;\r\n            &lt;network&gt;\r\n                &lt;session-timeout&gt;0&lt;\/session-timeout&gt;\r\n            &lt;\/network&gt;\r\n        &lt;\/properties&gt;\r\n        &lt;channels&gt;\r\n            &lt;channel ref=&quot;my-rtmp&quot;\/&gt;\r\n        &lt;\/channels&gt;\r\n    &lt;\/destination&gt;\r\n    &lt;destination id=&quot;painter&quot;&gt;\r\n\t&lt;adapter ref=&quot;messagingAdapter&quot;\/&gt;\r\n        &lt;properties&gt;\r\n            &lt;network&gt;\r\n                &lt;session-timeout&gt;0&lt;\/session-timeout&gt;\r\n            &lt;\/network&gt;\r\n        &lt;\/properties&gt;\r\n        &lt;channels&gt;\r\n            &lt;channel ref=&quot;my-rtmp&quot;\/&gt;\r\n        &lt;\/channels&gt;\r\n    &lt;\/destination&gt;\r\n    &lt;destination id=&quot;opminboxrefresher&quot;&gt;\r\n\t&lt;adapter ref=&quot;messagingAdapter&quot;\/&gt;\r\n    \t&lt;properties&gt;\r\n\t    &lt;network&gt;\r\n            \t&lt;session-timeout&gt;0&lt;\/session-timeout&gt;\r\n            &lt;\/network&gt;\r\n    \t&lt;\/properties&gt;\r\n    \t&lt;channels&gt;\r\n         \t&lt;channel ref=&quot;my-rtmp&quot;\/&gt;\r\n    \t&lt;\/channels&gt;\r\n    &lt;\/destination&gt; \r\n&lt;\/service&gt;\r\n<\/pre>\n<h2>Konfiguration des Frontends<\/h2>\n<p>Bei den Frontend Konfigurationsdateien kann einfach die Datei services-config.xml und die Datei messaging-config.xml kopiert werden. Es k\u00f6nnen aber absolute Pfade anstelle der Platzhalter wie {server.name},{server.port},{context.root} genutzt werden. Hierdurch ist eine lokale Entwicklung der Flex-Anwendungen mit einem entfernten IIS Server m\u00f6glich. <\/p>\n<h1>L\u00f6sung<\/h1>\n<p>PaintMessaging.mxml (Projektdatei)<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;mx:Application creationComplete=&quot;{init()}&quot; xmlns:mx=&quot;http:\/\/www.adobe.com\/2006\/mxml&quot; \r\n\tlayout=&quot;absolute&quot; xmlns:components=&quot;components.*&quot;&gt;\r\n\t&lt;mx:Script&gt;\r\n\t\t&lt;!&amp;#91;CDATA&amp;#91;\r\n\t\t\timport models.ModelLocator;\r\n\t\t\timport mx.controls.Alert;\r\n\t\t\timport mx.messaging.events.MessageFaultEvent;\r\n\t\t\timport mx.messaging.events.MessageEvent;\r\n\t\t\timport mx.messaging.messages.AsyncMessage;\r\n\t\t\timport mx.managers.CursorManager;\r\n\t\t\t&amp;#91;Bindable&amp;#93;\r\n            &amp;#91;Embed(source=&quot;..\/assets\/stiftklein.png&quot;)&amp;#93;\r\n            private var stift:Class;\r\n            \r\n            public var cursorID:int;\r\n            \r\n            public function init():void \r\n            {\r\n            \tconsumer.subscribe();\r\n            }\r\n            \r\n            public function mouseOverHandler(event:MouseEvent):void\r\n            {\r\n            \t\r\n            }\r\n            \r\n            public function downEvent(event:MouseEvent):void \r\n            {\r\n            \t\r\n            } \r\n            \r\n            public function upEvent(event:MouseEvent):void\r\n            {\r\n            \t\r\n            }\r\n            \r\n\tprivate function messageHandler(event:MessageEvent):void\r\n    \t{\r\n    \t    ModelLocator.getInstance().lines=event.message.body as Array;\r\n    \t    dc_main.invalidateDisplayList();\r\n    \t}\r\n   \r\n   \tprivate function messagefaultHandler(event:MessageFaultEvent):void\r\n   \t{ \r\n   \t   Alert.show(event.faultCode+&#039; &#039;+event.faultDetail+&#039; &#039;+event.faultString); \r\n   \t}     \t\t\r\n            \r\n\t&amp;#93;&amp;#93;&gt;\r\n\t&lt;\/mx:Script&gt;\r\n\t&lt;mx:Consumer id=&quot;consumer&quot; destination=&quot;painter&quot; \r\n\t\tmessage=&quot;messageHandler(event)&quot; fault=&quot;messagefaultHandler(event)&quot;\/&gt;\r\n    &lt;mx:Producer id=&quot;producer&quot; destination=&quot;painter&quot; \r\n    \tfault=&quot;messagefaultHandler(event)&quot;\/&gt;\t\t\r\n\r\n    &lt;mx:Panel mouseOver=&quot;{ cursorID = CursorManager.setCursor(stift); }&quot; \r\n    \tmouseOut=&quot;{CursorManager.removeCursor(cursorID);}&quot; \r\n    \tlayout=&quot;absolute&quot; \r\n    \ttitle=&quot;Montagsmaler by Bj\u00f6rn Karpenstein&quot; \r\n    \tbackgroundColor=&quot;#ffffff&quot; \r\n    \tborderThicknessBottom=&quot;10&quot; left=&quot;20&quot; \r\n    \tright=&quot;20&quot; top=&quot;20&quot; bottom=&quot;20&quot;&gt;\r\n       &lt;components:DrawableCanvas id=&quot;dc_main&quot; backgroundColor=&quot;#ffff80&quot; \r\n       \tbackgroundAlpha=&quot;0&quot; width=&quot;100%&quot; height=&quot;100%&quot; y=&quot;0&quot; x=&quot;0&quot;&gt;\r\n       &lt;\/components:DrawableCanvas&gt;\r\n    &lt;\/mx:Panel&gt;\r\n\t\t\r\n&lt;\/mx:Application&gt;\r\n<\/pre>\n<p>DrawableCanvas.mxml<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;\r\n&lt;mx:Canvas xmlns:mx=&quot;http:\/\/www.adobe.com\/2006\/mxml&quot; width=&quot;400&quot; height=&quot;300&quot; \r\n       creationComplete=&quot;init()&quot;&gt;\r\n    \r\n    &lt;mx:Script&gt;\r\n        &lt;!&amp;#91;CDATA&amp;#91;\r\n            \r\n            public var lineWidth:Number = 5;\r\n            \r\n            public var lineColour:uint = 1;\r\n            \r\n            public var lineAlpha:Number = 1;\r\n            \r\n            \r\n            private var enabler:DrawingEnabler;\r\n            \r\n            private function init():void\r\n            {\r\n                enabler = new DrawingEnabler(this);\r\n            }            \r\n            \r\n            protected override function updateDisplayList(unscaledWidth:Number,\r\n                            unscaledHeight:Number):void\r\n            {\r\n                super.updateDisplayList(unscaledWidth, unscaledHeight);\r\n            \r\n                if( enabler != null ) enabler.drawLines(graphics, lineWidth, \r\n                lineColour, lineAlpha);\r\n            }\r\n        &amp;#93;&amp;#93;&gt;\r\n    &lt;\/mx:Script&gt;\r\n&lt;\/mx:Canvas&gt;\r\n<\/pre>\n<p>DrawingEnabler.as<\/p>\n<p>package components<br \/>\n{<br \/>\n   import flash.display.Graphics;<br \/>\n   import flash.events.MouseEvent;<\/p>\n<p>   import models.ModelLocator;<\/p>\n<p>   import mx.core.Application;<br \/>\n   import mx.core.UIComponent;<br \/>\n   import mx.messaging.messages.AsyncMessage;<\/p>\n<p>    public class DrawingEnabler<br \/>\n    {<br \/>\n        private var _target:UIComponent;<\/p>\n<p>        private var _curentLine:Array;<\/p>\n<p>        public function DrawingEnabler( target:UIComponent ):void<br \/>\n        {<br \/>\n            _target = target;<br \/>\n            _target.addEventListener(MouseEvent.MOUSE_DOWN, downEvent);<br \/>\n            _target.addEventListener(MouseEvent.MOUSE_UP, upEvent);<br \/>\n            _target.addEventListener(MouseEvent.MOUSE_OUT, upEvent);<br \/>\n        }<\/p>\n<p>\t\tpublic function sendMessage(stream:Array):void<br \/>\n    \t{<br \/>\n   \t\t\tvar message:AsyncMessage = new AsyncMessage();<br \/>\n   \t\t\tmessage.body = stream;<br \/>\n   \t\t\tApplication.application.producer.send(message);<br \/>\n   \t\t}                  <\/p>\n<p>        public function newLine():void<br \/>\n        {<br \/>\n            _curentLine = new Array();<br \/>\n            ModelLocator.getInstance().lines.push( _curentLine );<\/p>\n<p>            if( ModelLocator.getInstance().lines.length > 10 )<br \/>\n                ModelLocator.getInstance().lines.shift();<br \/>\n        }<\/p>\n<p>        public function addPoint(xIN:int, yIN:int):void<br \/>\n        {<br \/>\n            _curentLine.push( { x:xIN, y:yIN } );<br \/>\n            _target.invalidateDisplayList();<br \/>\n        }<\/p>\n<p>        public function drawLines(graphics:Graphics,lw:Number,lc:uint,la:Number):void<br \/>\n        {<br \/>\n            graphics.clear();<br \/>\n            graphics.lineStyle(lw,lc,la);<\/p>\n<p>            for( var j:int = 0; j<ModelLocator.getInstance().lines.length; j++ )\n            {\n                var line:Array = ModelLocator.getInstance().lines[j];\n                \n                for( var i:int = 0; i<line.length; i++ )\n                {\n                    var p:Object = line[i];\n                    if( i == 0 )\n                    {\n                        graphics.moveTo( p.x, p.y );\n                    }    \n                    else\n                    {\n                        graphics.lineTo( p.x, p.y );\n                    }    \n                }\n            }\n        }\n        \n        private function moveEvent(event:MouseEvent):void\n        {\n            addPoint( event.localX, event.localY );                \n        }\n        \n        private function downEvent(event:MouseEvent):void\n        {\n            _target.addEventListener(MouseEvent.MOUSE_MOVE, moveEvent);\n\n            newLine();\n        }\n        \n        private function upEvent(event:MouseEvent):void\n        {\n            _target.removeEventListener(MouseEvent.MOUSE_MOVE, moveEvent);\n            sendMessage(ModelLocator.getInstance().lines);\n        }\n    }\n\n}\n[\/javascript]\n<\/p>\n<iframe src=\"http:\/\/www.facebook.com\/plugins\/like.php?href=https%3A%2F%2Fwww.capri-soft.de%2Fblog%2F%3Fp%3D218&amp;layout=standard&amp;show_faces=true&amp;width=450&amp;action=like&amp;colorscheme=light\" scrolling=\"no\" frameborder=\"0\" allowTransparency=\"true\" style=\"border:none; overflow:hidden; width:450px;margin-top:5px;\"><\/iframe>","protected":false},"excerpt":{"rendered":"<p>Aufgabenstellung Unter Verwendung der FluorineFX Messaging-API soll eine Montagsmaler-Anwendung implementiert werden. Dies bedeutet dass ein User auf eine Leinwand zeichnet und die anderen Seitenbesucher in Echtzeit eine Aktualisierung auf dem Bildschirm erhalten. Dies kann auch als Grundlage f\u00fcr weitere Kollaborationsanwendungen genutzt werden, in denen man gemeinsam ein Dokument konstruieren m\u00f6chte. Ansatz Nachdem die Zeichnenfunktionalit\u00e4t implementiert &hellip; <a href=\"https:\/\/www.capri-soft.de\/blog\/?p=218\" class=\"more-link\"><span class=\"screen-reader-text\">Flex 3: Bemalbares mx:Canvas mit FluorineFX-Messaging (Montagsmaler)<\/span> weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[4,5],"tags":[],"class_list":["post-218","post","type-post","status-publish","format-standard","hentry","category-net","category-adobe-flex"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4yGeN-3w","jetpack_likes_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/218","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=218"}],"version-history":[{"count":12,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/218\/revisions"}],"predecessor-version":[{"id":362,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=\/wp\/v2\/posts\/218\/revisions\/362"}],"wp:attachment":[{"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=218"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=218"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.capri-soft.de\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=218"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}