<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>@GreWeb</title>
	<atom:link href="http://blog.greweb.fr/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.greweb.fr</link>
	<description>embrace standard web technologies for web, games and mobile apps</description>
	<lastBuildDate>Tue, 15 May 2012 06:12:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Minimize your Javascript files with cURL</title>
		<link>http://blog.greweb.fr/2012/05/minimize-your-javascript-files-with-curl/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=minimize-your-javascript-files-with-curl</link>
		<comments>http://blog.greweb.fr/2012/05/minimize-your-javascript-files-with-curl/#comments</comments>
		<pubDate>Sat, 12 May 2012 18:50:55 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Bash Tips]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Closure]]></category>
		<category><![CDATA[cURL]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[WOA]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1713</guid>
		<description><![CDATA[I&#8217;ve always been fascinated by the power of using existing web applications as external tools: you don&#8217;t need to install anything on your computer but you can rely on the web. We can externalize the intelligence of applications in servers and easily make updates, while having any terminal consuming them with a minimal OS environment. <a href='http://blog.greweb.fr/2012/05/minimize-your-javascript-files-with-curl/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve always been fascinated by the power of <strong>using existing web applications as external tools</strong>: you don&#8217;t need to install anything on your computer but you can <strong>rely on the web</strong>.</p>
<p>We can <strong>externalize the intelligence of applications in servers</strong> and <strong>easily make updates</strong>, while having any terminal consuming them with a <strong>minimal OS environment</strong>.<br />
<em>Cloud</em> or whatever you call it, it&#8217;s awesome.</p>
<p><abbr title="Web Oriented Architecture">WOA</abbr> is our common architecture for making applications. Clients of web servers can be anything you want, not only desktop browsers, but also mobiles, tablets, other web services, and&#8230; <strong>command-line</strong>!</p>
<p>And today, as an example, we will use <a href="https://developers.google.com/closure/compiler/docs/api-ref">Google Closure Compiler web service</a> to <strong>minimize a Javascript file with only cURL</strong>.</p>
<p><span id="more-1713"></span></p>
<p><strong>cURL</strong> is a <abbr title="Command-line">CLI</abbr> swiss army knife of transferring data and it is perfect for testing, debugging and consuming web services.</p>
<p><strong>Google Closure Compiler</strong> check and &#8220;compile&#8221; your Javascript file. By compile, it means optimizing its size by renaming variables and removing spaces and comments. Javascript compilation has because an essential phase of major javascript libraries.</p>
<h2>Bash script examples</h2>
<h3>Download and minimize the last version of Illuminated.js</h3>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #007800;">URL</span>=https:<span style="color: #000000; font-weight: bold;">//</span>raw.github.com<span style="color: #000000; font-weight: bold;">/</span>gre<span style="color: #000000; font-weight: bold;">/</span>illuminated.js<span style="color: #000000; font-weight: bold;">/</span>master<span style="color: #000000; font-weight: bold;">/</span>src<span style="color: #000000; font-weight: bold;">/</span>illuminated.js<br />
<span style="color: #007800;">OUTPUT</span>=illuminated.min.js<br />
curl <span style="color: #660033;">-d</span> <span style="color: #007800;">compilation_level</span>=SIMPLE_OPTIMIZATIONS <span style="color: #660033;">-d</span> <span style="color: #007800;">output_format</span>=text <span style="color: #660033;">-d</span> <span style="color: #007800;">output_info</span>=compiled_code <span style="color: #660033;">-d</span> <span style="color: #007800;">code_url</span>=<span style="color: #007800;">$URL</span> http:<span style="color: #000000; font-weight: bold;">//</span>closure-compiler.appspot.com<span style="color: #000000; font-weight: bold;">/</span>compile <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #007800;">$OUTPUT</span></div></div>
<h3>Minimize a local JS file</h3>
<div class="codecolorer-container bash default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #007800;">LOCAL_FILE</span>=.<span style="color: #000000; font-weight: bold;">/</span>mysuperlib.js<br />
<span style="color: #007800;">OUTPUT</span>=mysuperlib.min.js<br />
curl <span style="color: #660033;">-d</span> <span style="color: #007800;">compilation_level</span>=SIMPLE_OPTIMIZATIONS <span style="color: #660033;">-d</span> <span style="color: #007800;">output_format</span>=text <span style="color: #660033;">-d</span> <span style="color: #007800;">output_info</span>=compiled_code <span style="color: #660033;">--data-urlencode</span> <span style="color: #ff0000;">&quot;js_code@<span style="color: #007800;">${LOCAL_FILE}</span>&quot;</span> http:<span style="color: #000000; font-weight: bold;">//</span>closure-compiler.appspot.com<span style="color: #000000; font-weight: bold;">/</span>compile <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #007800;">$OUTPUT</span></div></div>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1713&amp;md5=89c73bb795dcf3d03da71a948e5d3eb3" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/05/minimize-your-javascript-files-with-curl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F05%2Fminimize-your-javascript-files-with-curl%2F&amp;language=fr_FR&amp;category=text&amp;title=Minimize+your+Javascript+files+with+cURL&amp;description=I%26%238217%3Bve+always+been+fascinated+by+the+power+of+using+existing+web+applications+as+external+tools%3A+you+don%26%238217%3Bt+need+to+install+anything+on+your+computer+but+you+can+rely+on+the...&amp;tags=Closure%2CcURL%2Cjavascript%2CWOA%2Cblog" type="text/html" />
	</item>
		<item>
		<title>Illuminated.js &#8211; 2D lights and shadows rendering engine for HTML5 applications</title>
		<link>http://blog.greweb.fr/2012/05/illuminated-js-2d-lights-and-shadows-rendering-engine-for-html5-applications/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=illuminated-js-2d-lights-and-shadows-rendering-engine-for-html5-applications</link>
		<comments>http://blog.greweb.fr/2012/05/illuminated-js-2d-lights-and-shadows-rendering-engine-for-html5-applications/#comments</comments>
		<pubDate>Thu, 10 May 2012 17:00:39 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[library]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1589</guid>
		<description><![CDATA[Click on the image to open it! Wow! what&#8217;s this? It&#8217;s a 2D scene containing 2 lights and 13 different objects rendered in real-time by a Javascript library I made called Illuminated.js. The library is designed to add some awesome effects to your existing applications. Adding a cool atmosphere for your applications and games can <a href='http://blog.greweb.fr/2012/05/illuminated-js-2d-lights-and-shadows-rendering-engine-for-html5-applications/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://bit.ly/LZ2dq1" target="_blank"><img src="http://blog.greweb.fr/wp-content/uploads/2012/05/illuminatedjs.jpg" alt="" title="illuminatedjs" width="600" height="400" class="alignnone size-full wp-image-1590" /><br />
Click on the image to open it!</a></p>
<h2>Wow! what&#8217;s this?</h2>
<p>It&#8217;s a <strong>2D scene</strong> containing 2 <strong>lights</strong> and 13 different <strong>objects</strong> rendered in <strong>real-time</strong> by a <strong>Javascript library</strong> I made called <strong>Illuminated.js</strong>.</p>
<p>The library is designed to add some <strong>awesome effects to your existing applications</strong>. Adding <strong>a cool atmosphere for your applications and games</strong> can make the difference!</p>
<p><strong><a target="_blank" href="http://demo.greweb.fr/illuminated.js">Try the editor</a></strong> and <strong><a target="_blank" href="http://github.com/gre/illuminated.js">Get the source code</a></strong>.</p>
<p>In this article, we will introduce the basic usages of <em>Illuminated.js</em> and APIs, and then explain how the engine works step-by-step.</p>
<ul>
<li><a href="http://blog.greweb.fr/?p=1589#gettingstarted">API &#8211; Getting started</a></li>
<li><a href="http://blog.greweb.fr/?p=1589#underthehood">Technical notes &#8211; how does it work?</a></li>
</ul>
<p> <iframe src="http://demo.greweb.fr/illuminated.js/announcement.html" style="width: 240px; height: 240px" frameborder="0"></iframe></p>
<p><span id="more-1589"></span></p>
<h2>How can I use it?</h2>
<p>The library uses <a href="http://en.wikipedia.org/wiki/Canvas_element">HTML5 Canvas</a> to draw lights and shadows &#8211; so you can simply drop it straight into your existing Canvas applications: you just need to add some code in your render function and maintaining a binding between your application logic and the <em>Illuminated.js</em> objects.<br />
Not using canvas? No worries! In theory, if you have an existing application or game made in full DOM, you could use <em>Illuminated.js</em> behind this, playing with z-index.</p>
<h2 id="gettingstarted">Getting started</h2>
<h3>Basic concepts</h3>
<p>All the classes of the package live in <code class="codecolorer javascript default"><span class="javascript">window.<span style="color: #660066;">illuminated</span></span></code>.</p>
<p>A <strong>Light</strong> describes a light emit source.<br />
An <strong>OpaqueObject</strong> specifies an 2D object used by a Lighting.<br />
A <strong>Lighting</strong> defines the lighting of a light through a set of opaque objects, each object stops the light and casts shadows.<br />
A <strong>DarkMask</strong> defines a dark layer which hides dark area not lighted by a set of lights. It should be drown on the top-layer to hide objects which are far from the light. This effect produces a better atmosphere and is perfect for game where light are essential (where hiding invisible area is part of the difficulty).</p>
<h3>Example of a basic scene rendering</h3>
<p><a href="http://demo.greweb.fr/illuminated.js/gettingstarted.html" target="_blank"><br />
Click here to open this example.<br />
<img src="http://blog.greweb.fr/wp-content/uploads/2012/05/gettingstarted.jpg" alt="" title="gettingstarted" width="400" height="300" class="alignnone size-full wp-image-1633" /><br />
</a></p>
<h2>Lights and Objects</h2>
<h3>Vec2</h3>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">new</span> Vec2<span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span></div></div>
<p>Vec2 represents a 2d position or a 2d vector. It is used everywhere in <em>Illuminated.js</em>.</p>
<p>Vec2 is inspired from Box2d&#8217;s Vec2 except that in <em>Illuminated.js</em> a Vec2 vector is immutable. It means every methods create a new Vec2 instance and you can safely use a same Vec2 instance everywhere because the immutability guarantees the non-modification of properties.</p>
<h3>Lights</h3>
<p>For now, we have only implemented one kind of light: a <strong>Lamp</strong> which is basically a radial gradient. A Lamp can also be &#8220;oriented&#8221;, it means lighting more far in a given direction.</p>
<h4>Lamp</h4>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">new</span> Lamp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></div></div>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">new</span> Lamp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> position<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">new</span> Vec2<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">12</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">34</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></div></div>
<p>every parameters:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">new</span> Lamp<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; position<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">new</span> Vec2<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">12</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">34</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><br />
&nbsp; distance<span style="color: #339933;">:</span> <span style="color: #CC0000;">100</span><span style="color: #339933;">,</span><br />
&nbsp; diffuse<span style="color: #339933;">:</span> <span style="color: #CC0000;">0.8</span><span style="color: #339933;">,</span><br />
&nbsp; color<span style="color: #339933;">:</span> <span style="color: #3366CC;">'rgba(250,220,150,0.8)'</span><span style="color: #339933;">,</span><br />
&nbsp; radius<span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><br />
&nbsp; samples<span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">,</span><br />
&nbsp; angle<span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><br />
&nbsp; roughness<span style="color: #339933;">:</span> <span style="color: #CC0000;">0</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></div></div>
<p>It defines a <strong>Lamp</strong> placed at a <strong>position</strong>, with a maximum emiting <strong>distance</strong>, a <strong>diffuse</strong> parameters to define the light penetration in objects.<br />
The <strong>radius</strong> defines the size of the light. Bigger the size is, Higher shadows are smoothed. The <strong>samples</strong> is an important parameters to define the quality of this smooth.<br />
The <strong>angle</strong> and <strong>roughness</strong> parameters are used for oriented lamp: angle defines the orientation while roughness defines the roughness of the effect.</p>
<h3>Light methods</h3>
<p>You can easily create your own Light type by implementing its methods.</p>
<h4>.mask(ctx)</h4>
<p>Render a mask representing the visibility (used by DarkMask).</p>
<h4>.render(ctx)</h4>
<p>Render the light (without any shadows).</p>
<h4>.bounds()</h4>
<p>Return the Rectangle bound of the light representing where the light emission limit. <code class="codecolorer javascript default"><span class="javascript"><span style="color: #009900;">&#123;</span> topleft<span style="color: #339933;">:</span> vec2<span style="color: #339933;">,</span> bottomright<span style="color: #339933;">:</span> vec2 <span style="color: #009900;">&#125;</span></span></code></p>
<h4>.forEachSample(fn)</h4>
<p>Apply a function fn for each light sample position. By default it&#8217;s called once with the light position.</p>
<h3>Opaque Objects</h3>
<p>In <em>Illuminated.js</em>, an object which cast shadows is called an opaque object. That&#8217;s why every types inherits OpaqueObject. </p>
<p>DiscObject and PolygonObject are the two available primitive objects.</p>
<h4>DiscObject</h4>
<p>A &#8220;DiscObject&#8221; is basically a 2D circlar object. You must define its center <strong>position</strong> and its <strong>radius</strong>:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">new</span> DiscObject<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> position<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">new</span> Vec2<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">80</span><span style="color: #339933;">,</span><span style="color: #CC0000;">50</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> radius<span style="color: #339933;">:</span> <span style="color: #CC0000;">20</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></div></div>
<h4>PolygonObject</h4>
<p>PolygonObject also has some derivated classes you can use: <strong>RectangleObject</strong>, <strong>LineObject</strong>.</p>
<p>You can instanciate these different objects like this:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">new</span> PolygonObject<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#91;</span> <span style="color: #003366; font-weight: bold;">new</span> Vec2<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">new</span> Vec2<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">10</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> ... <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #006600; font-style: italic;">// an array of points</span><br />
<span style="color: #003366; font-weight: bold;">new</span> RectangleObject<span style="color: #009900;">&#40;</span>topleft<span style="color: #339933;">,</span> bottomright<span style="color: #009900;">&#41;</span> <span style="color: #006600; font-style: italic;">// topleft and bottomright positions of the rectangle</span><br />
<span style="color: #003366; font-weight: bold;">new</span> LineObject<span style="color: #009900;">&#40;</span>a<span style="color: #339933;">,</span> b<span style="color: #009900;">&#41;</span> <span style="color: #006600; font-style: italic;">// an object defined by the line from a to b.</span></div></div>
<h3>OpaqueObject methods</h3>
<p>You can easily create your own object type by implementing OpaqueObject methods.</p>
<h4>.bounds()</h4>
<p>Return the Rectangle bound of the object. <code class="codecolorer javascript default"><span class="javascript"><span style="color: #009900;">&#123;</span> topleft<span style="color: #339933;">:</span> vec2<span style="color: #339933;">,</span> bottomright<span style="color: #339933;">:</span> vec2 <span style="color: #009900;">&#125;</span></span></code></p>
<h4>.contains(point)</h4>
<p>Return <code class="codecolorer javascript default"><span class="javascript"><span style="color: #003366; font-weight: bold;">true</span></span></code> if the object contains a <strong>point</strong>.</p>
<h4>.path(ctx)</h4>
<p>Build the path of the object shape in a 2d context <strong>ctx</strong>.</p>
<h4>.cast(ctx, origin, bounds)</h4>
<p>Fill every shadows with <strong>ctx</strong> projected by the <strong>origin</strong> point in the object and in a given <strong>bounds</strong>.</p>
<h2>Lighting and DarkMask</h2>
<p>Previous defined classes was representing datas we will now use to perform lightings and masks.</p>
<h3>Lighting</h3>
<p>A Lighting defines the lighting of one light through a set of opaque objects.</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">new</span> Lighting<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> light<span style="color: #339933;">:</span> light<span style="color: #339933;">,</span> objects<span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span> object1<span style="color: #339933;">,</span> object2<span style="color: #339933;">,</span> ... <span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></div></div>
<h4>.compute(width, height)</h4>
<p>will compute shadows casting.</p>
<h4>.cast(ctx)</h4>
<p>will draw black shadows on the <strong>ctx</strong> canvas 2d context.<br />
You usually don&#8217;t have to use it if you use <code class="codecolorer javascript default"><span class="javascript">render<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code>.</p>
<h4>.render(ctx)</h4>
<p>will draw the light with its shadows on <strong>ctx</strong> canvas 2d context.</p>
<h3>DarkMask</h3>
<p>A DarkMask defines a dark layer which hides dark area not lighted by a set of lights.</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">new</span> DarkMask<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span> lights<span style="color: #339933;">:</span> <span style="color: #009900;">&#91;</span>light1<span style="color: #339933;">,</span> light2<span style="color: #339933;">,</span> ...<span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> color<span style="color: #339933;">:</span> <span style="color: #3366CC;">'rgba(0,0,0,0.9)'</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span></div></div>
<h4>.compute(width, height)</h4>
<p>will compute the dark mask.</p>
<h4>.render(ctx)</h4>
<p>will draw the computed dark mask on <strong>ctx</strong> canvas 2d context.</p>
<h3>about compute and render</h3>
<p>Both Lighting and DarkMask objects have <code class="codecolorer javascript default"><span class="javascript">compute<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> and <code class="codecolorer javascript default"><span class="javascript">render<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> methods.</p>
<p>We think that <strong>you</strong> know the best when to recompute the lights because it&#8217;s closely link to the application you are making (we will not check at each time if something has changed, you know it).<br />
Call the <code class="codecolorer javascript default"><span class="javascript">compute<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span></span></code> method when something has changed in your scene so we can recompute lights and shadows.</p>
<h2 id="underthehood">How does it work under the hood?</h2>
<p><em>Illuminated.js</em> divides its work into several layers.</p>
<h3>Real-time example</h3>
<p><iframe src="http://demo.greweb.fr/illuminated.js/howdoesitwork.html" border="0" height="2700" width="450"></iframe></p>
<h3>The art of composing layers</h3>
<p>The layers are all stored in a Canvas which allows us to cache it. The light is drawn using a Canvas Radial Gradient in a cache canvas only once. This is interesting because canvas gradient are processor intensive<br />
At the end, layers are combine on the global canvas with <code class="codecolorer javascript default"><span class="javascript">drawImage</span></code>.<br />
But the library lets you reuse these layers to combine them the way you want.</p>
<p>Canvas&#8217; <code class="codecolorer javascript default"><span class="javascript">globalCompositeOperation</span></code> is very useful to compose layers together.<br />
For instance, in the following example, the &#8220;Light shadow casting&#8221; layer is combined with the &#8220;Light rendering&#8221; layer to generate the &#8220;Light rendering with shadows&#8221; layer. The composition mode used is &#8220;destination-out&#8221; which remove the color of the destination image where the source image has color.</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">light.<span style="color: #660066;">render</span><span style="color: #009900;">&#40;</span>ctx<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
ctx.<span style="color: #660066;">globalCompositeOperation</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;destination-out&quot;</span><span style="color: #339933;">;</span><br />
<span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">cast</span><span style="color: #009900;">&#40;</span>ctx<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>Another very useful composite operation is <code class="codecolorer javascript default"><span class="javascript"><span style="color: #3366CC;">&quot;lighter&quot;</span></span></code> which adds color values. It is used to combine two lightings.</p>
<h3>How shadows are projected</h3>
<p>Some rendering engine use <a href="http://en.wikipedia.org/wiki/Ray_tracing_%28graphics%29">ray tracing</a> to render a scene, a concept very close to physics which trace from a light source a lot of rays with different paths which will collide with object and will be subject of absorption/diffraction/reflexion in accordance with the object properties&#8230;<br />
Ray casting is a very <strong>realistic</strong> rendering solution <strong>but consuming</strong> (you need a lot of rays to avoid noises in the result image).<br />
<em>Illuminated.js</em> doesn&#8217;t use ray tracing because it aims to be efficient for a real-time usage. It uses some heuristics for casting shadows.</p>
<h4>Let&#8217;s see how shadows are projected for a polygon object.</h4>
<p>We have a scene with a light and a triangle.</p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/05/step11.jpg" alt="" /></p>
<p>We select each edge of the polygon which is visible by the light (and in the light bounds).</p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/05/step21.jpg" alt="" /></p>
<p>For every selected edge, we project it to generate a polygon area. </p>
<blockquote><p><strong>N.B.</strong> In the current implementation, we generate an hexagon projection to ensure it goes outside of the light bounds because a quadrilateral didn&#8217;t garantee it, if a light is very close to it. The projecting vector used is enough big to work for most case, but it&#8217;s still an heuristic.</p></blockquote>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/05/step31.jpg" alt="" /></p>
<p>We draw black color in this polygon area. Some improvments can be made by not drawing black in the shape / ajusting the opacity of the color.</p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/05/step4.jpg" alt="" /></p>
<p>For casting blured shadows, we repeat this algorithm for each &#8220;samples&#8221; of the light. Samples are distribute around the light with a <a href="http://blog.marmakoide.org/?p=1">&#8220;spiral algorithm&#8221;</a>.</p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/05/sampling.jpg" alt="" /></p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">var</span> GOLDEN_ANGLE <span style="color: #339933;">=</span> Math.<span style="color: #660066;">PI</span> <span style="color: #339933;">*</span> <span style="color: #009900;">&#40;</span><span style="color: #CC0000;">3</span> <span style="color: #339933;">-</span> Math.<span style="color: #660066;">sqrt</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">5</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
Lamp.<span style="color: #660066;">prototype</span>.<span style="color: #660066;">forEachSample</span> <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>f<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> s<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> s<span style="color: #339933;">&lt;</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">samples</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>s<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> a <span style="color: #339933;">=</span> s <span style="color: #339933;">*</span> GOLDEN_ANGLE<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> r <span style="color: #339933;">=</span> Math.<span style="color: #660066;">sqrt</span><span style="color: #009900;">&#40;</span>s<span style="color: #339933;">/</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">samples</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">radius</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> delta <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> Vec2<span style="color: #009900;">&#40;</span> Math.<span style="color: #660066;">cos</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>r<span style="color: #339933;">,</span> Math.<span style="color: #660066;">sin</span><span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>r <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; f<span style="color: #009900;">&#40;</span> <span style="color: #000066; font-weight: bold;">this</span>.<span style="color: #660066;">position</span>.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span>delta<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<h2>To be continued&#8230;</h2>
<p>The current version of <em>Illuminated.js</em> needs more work, I&#8217;m aware of some bugs and some parts I need to improve:</p>
<ul>
<li>Implementing new kinds of lights like &#8220;Spot&#8221;, &#8220;Neon&#8221;, &#8230;</li>
<li>The dark mask doesn&#8217;t follow the Lamp orientation.</li>
<li>The shadow casting of Circle objects are not projected nicely, I need to compute <a href="http://en.wikipedia.org/wiki/Tangent_lines_to_circles">tangent lines to the circle</a>.</li>
<li>Shadows go sometimes wrong especially when having objects behind objects</li>
<li>The shadow sampling implementation is a bit hacky and wrong (changing the samples parameter changes the shadow opacity&#8230;)</li>
</ul>
<h2>Get involved</h2>
<p><strong><a target="_blank" href="http://demo.greweb.fr/illuminated.js">Try the editor</a></strong> and <strong><a target="_blank" href="http://github.com/gre/illuminated.js">Get the source code</a></strong>.</p>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1589&amp;md5=4a79a55d7a8a1703bd6901b340917415" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/05/illuminated-js-2d-lights-and-shadows-rendering-engine-for-html5-applications/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F05%2Filluminated-js-2d-lights-and-shadows-rendering-engine-for-html5-applications%2F&amp;language=fr_FR&amp;category=text&amp;title=Illuminated.js+%26%238211%3B+2D+lights+and+shadows+rendering+engine+for+HTML5+applications&amp;description=Click+on+the+image+to+open+it%21+Wow%21+what%26%238217%3Bs+this%3F+It%26%238217%3Bs+a+2D+scene+containing+2+lights+and+13+different+objects+rendered+in+real-time+by+a+Javascript+library+I+made...&amp;tags=canvas%2Cjavascript%2Clibrary%2CWeb%2Cblog" type="text/html" />
	</item>
		<item>
		<title>HTML5 Canvas as a color converter</title>
		<link>http://blog.greweb.fr/2012/05/html5-canvas-as-a-color-converter/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=html5-canvas-as-a-color-converter</link>
		<comments>http://blog.greweb.fr/2012/05/html5-canvas-as-a-color-converter/#comments</comments>
		<pubDate>Thu, 03 May 2012 20:15:58 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[color]]></category>
		<category><![CDATA[hackability]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1523</guid>
		<description><![CDATA[I&#8217;m currently working on the User Interface of a scene editor for my Illuminated.js library with some color and alpha picker. HTML5 now have the &#60;input type=&#34;color&#34; /&#62; and &#60;input type=&#34;range&#34; /&#62; which is nice. It works on Chrome and there are some polyfills to make it working on older browsers. We will now see <a href='http://blog.greweb.fr/2012/05/html5-canvas-as-a-color-converter/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/05/color-alpha-options.png" alt="" title="color-alpha-options" width="198" height="76" class="alignleft size-full wp-image-1526" /><br />
I&#8217;m currently working on the User Interface of a scene editor for my <a href="http://demo.greweb.fr/illuminated.js/">Illuminated.js library</a> with some color and alpha picker.</p>
<p>HTML5 now have the <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">input</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;color&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span></span></code> and <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">input</span> <span style="color: #000066;">type</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;range&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span></span></code> which is nice. It works on Chrome and there are some <a href="https://github.com/bgrins/spectrum">polyfills</a> to make it working on older browsers.</p>
<p>We will now see how we can easily <strong>retrieve a rgba color from such an UI</strong>, regardless of the color format given by the color picker and <strong>combine the alpha component from the alpha range picker</strong>.</p>
<blockquote><p>We can implement an <strong>anythingToRGBA converter</strong> in 10 lines of Javascript!</p></blockquote>
<p><span id="more-1523"></span></p>
<h2>What?</h2>
<p>Basically, for instance, you have this: <code class="codecolorer javascript default"><span class="javascript"><span style="color: #3366CC;">&quot;#ff6432&quot;</span></span></code> and <code class="codecolorer javascript default"><span class="javascript"><span style="color: #CC0000;">0.8</span></span></code></p>
<p>and you want this: <code class="codecolorer javascript default"><span class="javascript"><span style="color: #3366CC;">&quot;rgba(255,100,50,0.8)&quot;</span></span></code></p>
<p>which is this color: <span style="background-color: rgba(255,100,50,0.8); width: 20px; height: 20px; display: inline-block">&nbsp;&nbsp;&nbsp;&nbsp;</span>.</p>
<blockquote><p>Well, of course, we could use a library with regexp parsers!</p></blockquote>
<p>But there is a lot of different formats available especially if you want to convert a color from <a href="http://www.w3.org/TR/css3-color/">CSS</a>!</p>
<p>Only for the <span style="color: blue">blue</span> color, you have at least 7 different representations: <code class="codecolorer text default"><span class="text">#00F</span></code>, <code class="codecolorer text default"><span class="text">#0000FF</span></code>, <code class="codecolorer text default"><span class="text">rgb(0,0,255)</span></code>, <code class="codecolorer text default"><span class="text">rgba(0,0,255,1)</span></code>, <code class="codecolorer text default"><span class="text">hsl(255,100%,50%)</span></code>, <code class="codecolorer text default"><span class="text">hsla(255,100%,50%,1)</span></code>,<br />
and&#8230; <code class="codecolorer text default"><span class="text">blue</span></code>!</p>
<blockquote><p>Ouch, so let&#8217;s make a huge converter library!</p></blockquote>
<p>Nope! </p>
<p>All of these are color formats are supported by CSS and also Canvas.<br />
<strong>So, why not just re-using what the browser can do?</strong></p>
<h2>How?</h2>
<p>Because we have access to Canvas in Javascript, <strong>we can implement an anythingToRGBA converter in a few line of Javascript</strong>:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">var</span> getRGBA <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> canvas <span style="color: #339933;">=</span> document.<span style="color: #660066;">createElement</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;canvas&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; canvas.<span style="color: #660066;">width</span> <span style="color: #339933;">=</span> canvas.<span style="color: #660066;">height</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> ctx <span style="color: #339933;">=</span> canvas.<span style="color: #660066;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;2d&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>color<span style="color: #339933;">,</span> alpha<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; ctx.<span style="color: #660066;">clearRect</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ctx.<span style="color: #660066;">fillStyle</span> <span style="color: #339933;">=</span> color<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ctx.<span style="color: #660066;">fillRect</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> d <span style="color: #339933;">=</span> ctx.<span style="color: #660066;">getImageData</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">data</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">'rgba('</span><span style="color: #339933;">+</span><span style="color: #009900;">&#91;</span> d<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> d<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> d<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> alpha <span style="color: #009900;">&#93;</span><span style="color: #339933;">+</span><span style="color: #3366CC;">')'</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<p>You have now a ready to use Javascript color library! </p>
<p><code class="codecolorer javascript default"><span class="javascript">getRGBA<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;#ff6432&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0.8</span><span style="color: #009900;">&#41;</span></span></code> will returns <code class="codecolorer javascript default"><span class="javascript"><span style="color: #3366CC;">&quot;rgba(255,100,50,0.8)&quot;</span></span></code>.<br />
<code class="codecolorer javascript default"><span class="javascript">getRGBA<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;red&quot;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0.5</span><span style="color: #009900;">&#41;</span></span></code> will returns <code class="codecolorer javascript default"><span class="javascript"><span style="color: #3366CC;">&quot;rgba(255,0,0,0.5)&quot;</span></span></code>.</p>
<p>You can &#8220;standardize&#8221; your color and use it anywhere!</p>
<p><strong>Feel free to adapt the code to any other desired format.</strong></p>
<p>We can easily make the reverse (give a rgba color and get the #RRGGBB and alpha values):</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:350px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">var</span> extractColorAndAlpha <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> canvas <span style="color: #339933;">=</span> document.<span style="color: #660066;">createElement</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;canvas&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; canvas.<span style="color: #660066;">width</span> <span style="color: #339933;">=</span> canvas.<span style="color: #660066;">height</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> ctx <span style="color: #339933;">=</span> canvas.<span style="color: #660066;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;2d&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
&nbsp; <span style="color: #003366; font-weight: bold;">function</span> toHex <span style="color: #009900;">&#40;</span>value<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> s <span style="color: #339933;">=</span> value.<span style="color: #660066;">toString</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">16</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span><span style="color: #009900;">&#40;</span>s.<span style="color: #660066;">length</span><span style="color: #339933;">==</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span> s <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;0&quot;</span><span style="color: #339933;">+</span>s<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> s<span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>color<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; ctx.<span style="color: #660066;">clearRect</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ctx.<span style="color: #660066;">fillStyle</span> <span style="color: #339933;">=</span> color<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; ctx.<span style="color: #660066;">fillRect</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> d <span style="color: #339933;">=</span> ctx.<span style="color: #660066;">getImageData</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #339933;">,</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">data</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; color<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;#&quot;</span><span style="color: #339933;">+</span>toHex<span style="color: #009900;">&#40;</span>d<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>toHex<span style="color: #009900;">&#40;</span>d<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span>toHex<span style="color: #009900;">&#40;</span>d<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span><br />
&nbsp; &nbsp; &nbsp; alpha<span style="color: #339933;">:</span> Math.<span style="color: #660066;">round</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1000</span><span style="color: #339933;">*</span>d<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">3</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">/</span><span style="color: #CC0000;">255</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">/</span><span style="color: #CC0000;">1000</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1523&amp;md5=8be88f8d63797e73450629fe33754bf3" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/05/html5-canvas-as-a-color-converter/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F05%2Fhtml5-canvas-as-a-color-converter%2F&amp;language=fr_FR&amp;category=text&amp;title=HTML5+Canvas+as+a+color+converter&amp;description=I%26%238217%3Bm+currently+working+on+the+User+Interface+of+a+scene+editor+for+my+Illuminated.js+library+with+some+color+and+alpha+picker.+HTML5+now+have+the+%26lt%3Binput+type%3D%26quot%3Bcolor%26quot%3B+%2F%26gt%3B+and+%26lt%3Binput...&amp;tags=canvas%2Ccolor%2Chackability%2Cblog" type="text/html" />
	</item>
		<item>
		<title>Work in &lt;progress /&gt;</title>
		<link>http://blog.greweb.fr/2012/04/work-in-progress/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=work-in-progress</link>
		<comments>http://blog.greweb.fr/2012/04/work-in-progress/#comments</comments>
		<pubDate>Thu, 26 Apr 2012 16:04:35 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[progress]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1465</guid>
		<description><![CDATA[Did you know browsers now have a built-in HTML tag for making progress bar? (progress is not supported) How cool is that! It is perfect for making web applications loading bar in just one line of HTML and a few Javascript code. A progress tag will be displayed on recent browsers with a OS-native progress <a href='http://blog.greweb.fr/2012/04/work-in-progress/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><strong>Did you know browsers now have a built-in HTML tag for making progress bar?</strong> </p>
<div style="text-align: center">
<progress style="width: 50%">(progress is not supported)</progress>
</div>
<p>How cool is that!</p>
<p>It is perfect for making web applications loading bar in just one line of HTML and a few Javascript code.</p>
<p>A progress tag will be displayed on recent browsers with a OS-native progress bar representing a loading. Like many HTML tag, if it is not supported, it fallbacks nicely by displaying its inner content. This fallback content should either be your own designed progress bar or simply display a percentage.</p>
<p>It is today supported by Firefox 9+, Chrome, Opera and IE10.<br />
<span id="more-1465"></span></p>
<h2>Example</h2>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;progress <span style="color: #000066;">value</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;23&quot;</span> max<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;100&quot;</span>&gt;</span>23 %<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>progress&gt;</span></div></div>
<h3>On your browser:</h3>
<progress value="23" max="100">23 %</progress>
<h3>On Linux / Firefox (with GNOME)</h3>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/progress.png" alt="" title="progress" width="145" height="20" class="alignnone size-full wp-image-1514" /></p>
<h3>On Mac OS / Chrome:</h3>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/Capture-d’écran-2012-04-26-à-14.59.37.png" alt="" title="progress_23" width="145" height="22" class="alignnone size-full wp-image-1476" /></p>
<h3>On IE 6:</h3>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/Capture-d’écran-2012-04-26-à-15.20.32.png" alt="" title="progress_23_IE" width="39" height="23" class="alignnone size-full wp-image-1480" /></p>
<h2>Let&#8217;s see some cases:</h2>
<h3>waiting</h3>
<p><code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;progress max<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;1000&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>progress&gt;</span></span></code>
<progress style="float: right" max="1000"></progress>
<h3>starting</h3>
<p><code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;progress <span style="color: #000066;">value</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;0&quot;</span> max<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;1000&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>progress&gt;</span></span></code>
<progress style="float: right" value="0" max="1000"></progress>
<h3>in progress:</h3>
<p><code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;progress <span style="color: #000066;">value</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;500&quot;</span> max<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;1000&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>progress&gt;</span></span></code>
<progress style="float: right" value="500" max="1000"></progress>
<h3>finished:</h3>
<p><code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;progress <span style="color: #000066;">value</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;1000&quot;</span> max<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;1000&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>progress&gt;</span></span></code>
<progress style="float: right" value="1000" max="1000"></progress>
<h2>Making a download bar</h2>
<p>When you need to load big resource like images, videos, or 3D materials, you usually want to display the progress of the download.<br />
You could still do it using some divs and CSS + Javascript, but this is now much simpler to use a  &lt;progress /&gt; :</p>
<h3>One line of HTML:</h3>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;progress <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;download&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>progress&gt;</span></div></div>
<h3>And the Javascript:</h3>
<p>(for more convenience, we are using jQuery)</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">var</span> totalBytes <span style="color: #339933;">=</span> <span style="color: #CC0000;">10000000</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// CHANGE ME WITH THE SIZE OF THE RESOURCE</span><br />
<span style="color: #003366; font-weight: bold;">var</span> req <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> XMLHttpRequest<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">var</span> progress <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#download'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
progress.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;max&quot;</span><span style="color: #339933;">,</span> totalBytes<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
req.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;progress&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; progress.<span style="color: #660066;">attr</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;value&quot;</span><span style="color: #339933;">,</span> e.<span style="color: #660066;">loaded</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">text</span><span style="color: #009900;">&#40;</span>Math.<span style="color: #660066;">floor</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">100</span><span style="color: #339933;">*</span>e.<span style="color: #660066;">loaded</span><span style="color: #339933;">/</span>totalBytes<span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #3366CC;">&quot; %&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp;<br />
req.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;load&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>e<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #006600; font-style: italic;">// THE RESOURCE IS LOADED</span><br />
&nbsp; progress.<span style="color: #660066;">replaceWith</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;&lt;div&gt;Downloaded!&lt;/div&gt;&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
req.<span style="color: #000066;">open</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;GET&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;resource.dat&quot;</span><span style="color: #339933;">,</span><span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
req.<span style="color: #660066;">send</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<div style="text-align: center">
<strong><a href="http://greweb.fr/progress/" target="_blank">See it in action here.</a></strong>
</div>
<p>It is quite easy to extend my code to support multiple files to download.</p>
<p>It is also easy to use this progress bar for anything else, but remember it represents a progress. If you want to represent some kind of stats, refer to the dedicated &lt;meter /&gt; tag.</p>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1465&amp;md5=391dfae99c6d5478337c5e81b8491d89" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/04/work-in-progress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F04%2Fwork-in-progress%2F&amp;language=fr_FR&amp;category=text&amp;title=Work+in+%26lt%3Bprogress+%2F%26gt%3B&amp;description=Did+you+know+browsers+now+have+a+built-in+HTML+tag+for+making+progress+bar%3F+%28progress+is+not+supported%29+How+cool+is+that%21+It+is+perfect+for+making+web+applications+loading...&amp;tags=html5%2Cjavascript%2Cprogress%2Cblog" type="text/html" />
	</item>
		<item>
		<title>Blender as a 2D game level editor &#8211; Proof Of Concept</title>
		<link>http://blog.greweb.fr/2012/04/blender-as-a-2d-game-map-editor-proof-of-concept/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=blender-as-a-2d-game-map-editor-proof-of-concept</link>
		<comments>http://blog.greweb.fr/2012/04/blender-as-a-2d-game-map-editor-proof-of-concept/#comments</comments>
		<pubDate>Mon, 09 Apr 2012 20:54:18 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[game development]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[3D]]></category>
		<category><![CDATA[BBG]]></category>
		<category><![CDATA[blender]]></category>
		<category><![CDATA[game]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1386</guid>
		<description><![CDATA[A long time ago, video games were only two-dimensional. Of-course this was due to our poor hardware capabilities, but when computers became faster and faster 3D games appeared in mass. Did it kill 2D games? Nope. They continue to exist because it offer a different gameplay and are easier to make. Maybe also a bit <a href='http://blog.greweb.fr/2012/04/blender-as-a-2d-game-map-editor-proof-of-concept/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>A long time ago, video games were only two-dimensional. Of-course this was due to our poor hardware capabilities, but when computers became faster and faster 3D games appeared in mass.<br />
<strong>Did it kill 2D games? Nope.</strong> They continue to exist because it offer a different gameplay and are easier to make. Maybe also a bit because we are nostalgic of old-school games!</p>
<p>We can distinguish two kinds of 2D games:</p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/bomberman93.jpg" alt="" title="bomberman93" width="200" class="alignleft size-full wp-image-1403" /><br />
<a href="http://www.tonypa.pri.ee/tbw/tut00.html"><strong>Tile based games</strong></a> where the game world is simplified with a big grid &#8211; each grid position has some properties.<br />
A map editor is not always needed for tile based games, because the map can be straighforward to represent and maintain like in a <em>Bomberman</em> or in a <em>Pacman</em>. A simple editor is generally used to make graphism with sprites.<br />
<br style="clear: both" /></p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/woarpc001.jpg" alt="" title="woarpc001" width="200" class="alignleft size-full wp-image-1404" /><br />
<strong>Non-tile based games</strong>, which can be called &#8220;polygon based games&#8221; are more complex.<br />
In such game, like a <em>Worms</em> or a <em>Sonic</em>, it&#8217;s totally crazy to write the map by hand (objects positions, polygons coordinates, &#8230;). The alternative, is not to use predefined maps, but on-the-fly generated maps which doesn&#8217;t fit every games.<br />
<br style="clear: both" /></p>
<p><strong>Making the game engine</strong> is one thing, but <strong>designing the game levels</strong> can be one big work too and <strong>we need tools to make it easier</strong>.</p>
<p><span id="more-1386"></span></p>
<h2>Tile based game maps</h2>
<p>In tile based games, maps are usually quite simple to represent.</p>
<p>For instance, here is how we can code the maze of <a href="http://www.masswerk.at/JavaPac/JS-PacMan2.html">Pacman</a>:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#91;</span><br />
<span style="color: #3366CC;">&quot;ahhhhhgxbhhdxehhhhhc&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;vp....o......o....pv&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;v.lhm...lhhm...lhm.v&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;v.....n......n.....v&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;v.n.n.v.ahhc.v.n.n.v&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;d.v.o.v.vxxq.v.o.v.b&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;x.v...v.vxxt.v...v.x&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;c.bhm.o.bhhr.o.lhd.a&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;v........x.........v&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;em.lc.am.lm.lc.am.lg&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;v...v.v......v.v...v&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;v.k.o.o.lhhm.o.o.k.v&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;vp................pv&quot;</span><span style="color: #339933;">,</span><br />
<span style="color: #3366CC;">&quot;bhhhhhcxahhcxahhhhhd&quot;</span><br />
<span style="color: #009900;">&#93;</span></div></div>
<p>where every character is a tile and has a given meaning.</p>
<p>For more complex games, we can also represent the map with a set of objects, and each object has position and size properties (x, y, width, height) and other properties for the game logic.</p>
<p>For instance, see the <em>ImpactJS</em> tile based games editor:</p>
<p><a href="http://impactjs.com/documentation/weltmeister"><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/weltmeister-tutorial-entities.png" alt="" title="weltmeister-tutorial-entities" width="600" height="355" class="size-full wp-image-1390" /></a></p>
<h2>But what about polygons based game?</h2>
<p>Well, some have tried to make dedicated 2D game map editor like shown in this video:</p>
<p><iframe width="420" height="315" src="http://www.youtube.com/embed/kvvEmm2Vyoc" frameborder="0" allowfullscreen></iframe></p>
<p>but it sounds a bit unfinished and specific.</p>
<h3>Do it yourself, but don&#8217;t reinvent the wheel.</h3>
<p><strong>But finally, isn&#8217;t it what a 3D editor is doing?</strong></p>
<p>Isn&#8217;t it the most generic tool we can find?</p>
<p>They have done a lot of awesome work in term of user interface, polygon modeling, textures (procedural / bitmap), &#8230;let&#8217;s profit of all this work to generate awesome texture map while exporting polygons.</p>
<p>Relying on such tools, you don&#8217;t have to learn a brand new map editor, you can relax on what you know if you have the chance to know Blender or Maya or anything.</p>
<h3>The Z magic</h3>
<p>Let&#8217;s ignore the Z dimension, or rather, let&#8217;s <strong>use the Z-dimension as a way to represent the semantics of the game map!</strong></p>
<p>This is the map I made for <a href="http://greweb.fr/blazing-race">Blazing Race</a>, a HTML5 against-the-clock platform game where you control a fireball:</p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/zs.png" alt="" title="zs" width="663" height="642" class="size-full wp-image-1417" /></p>
<p>For my game needs, I used <strong>different Z layers to represent different kind of materials and game objects</strong>:</p>
<ul>
<li>z=1 : candles&#8217; position &#8211; the objective of the game is to light them all</li>
<li>z=0 : the game grounds &#8211; where collision occurs</li>
<li>z=-1 : the water areas &#8211; where your flame dies</li>
<li>z=-2 : special areas where you miss oxgyen &#8211; your flame dies in a few seconds</li>
</ul>
<p>But I also used <strong>objects ids</strong> as an another way to distinguish objects:<br />
a &#8220;start&#8221; object to define the game start position and two &#8220;topleft&#8221; and &#8220;bottomright&#8221; objects to define the game bound.</p>
<h3>Maintain your map source in one file</h3>
<p>Another powerful feature of this, is you can maintain your map polygons AND your map textures in a single way. Use your 3D editor as a polygon editor and use its render engine to generate textures:</p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/map1.png" alt="" title="map" width="494" height="751" class="size-full wp-image-1425" /></p>
<p>Take benefits from what your 3D editor can do.</p>
<h3>Export polygons to the Javascript game</h3>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/04/path4850.png" alt="" title="path4850" width="400" height="59" class="size-full wp-image-1422" /></p>
<p>I&#8217;ve made a transformer which take a COLLADA file in input (the most commonly supported standard format to describe a 3D scene, you can export it from any 3D editor like Blender, Maya, 3DS&#8230;) which extract and transform relevant informations from it and give you a json map for your game in output.</p>
<p><em>It was quite simple to implement, thanks to the Three.js COLLADA importer <img src='http://blog.greweb.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </em></p>
<p>Here is the current (unfinished) interface for this:</p>
<p><a href="http://greweb.fr/blazing-race/maps/converter/"><br />
<img src="http://blog.greweb.fr/wp-content/uploads/2012/04/demo_screenshot.png" alt="" title="demo_screenshot" width="639" height="1516" class="alignnone size-full wp-image-1434" /><br />
</a></p>
<p>As a proof of usability of the output JSON map, the preview was only made in a few lines of Javascript code.</p>
<p>Extract:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:350px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">function</span> draw <span style="color: #009900;">&#40;</span>map<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> container <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#viewport'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'#legend'</span><span style="color: #009900;">&#41;</span>.<span style="color: #660066;">empty</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; a <span style="color: #339933;">=</span> <span style="color: #CC0000;">0</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> w <span style="color: #339933;">=</span> <span style="color: #CC0000;">500</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> h <span style="color: #339933;">=</span> Math.<span style="color: #660066;">floor</span><span style="color: #009900;">&#40;</span>w <span style="color: #339933;">*</span> map.<span style="color: #660066;">height</span><span style="color: #339933;">/</span>map.<span style="color: #660066;">width</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> CROSS_SIZE <span style="color: #339933;">=</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> canvas <span style="color: #339933;">=</span> $<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;canvas width=&quot;'</span><span style="color: #339933;">+</span>w<span style="color: #339933;">+</span><span style="color: #3366CC;">'&quot; height=&quot;'</span><span style="color: #339933;">+</span>h<span style="color: #339933;">+</span><span style="color: #3366CC;">'&quot;&gt;&lt;/canvas&gt;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> ctx <span style="color: #339933;">=</span> canvas<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;2d&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> <span style="color: #000066;">name</span> <span style="color: #000066; font-weight: bold;">in</span> map<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> objs <span style="color: #339933;">=</span> map<span style="color: #009900;">&#91;</span><span style="color: #000066;">name</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>objs<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&amp;&amp;</span> objs<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">faces</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> color <span style="color: #339933;">=</span> randomColor<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">70</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">0.8</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">fillStyle</span> <span style="color: #339933;">=</span> color<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span>objs.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> obj <span style="color: #339933;">=</span> objs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> f<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> f<span style="color: #339933;">&lt;</span>obj.<span style="color: #660066;">faces</span>.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>f<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> face <span style="color: #339933;">=</span> obj.<span style="color: #660066;">faces</span><span style="color: #009900;">&#91;</span>f<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">beginPath</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> v<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> v<span style="color: #339933;">&lt;</span>face.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>v<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> vertice <span style="color: #339933;">=</span> obj.<span style="color: #660066;">vertices</span><span style="color: #009900;">&#91;</span>face<span style="color: #009900;">&#91;</span>v<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> x <span style="color: #339933;">=</span> ctx.<span style="color: #660066;">canvas</span>.<span style="color: #660066;">width</span><span style="color: #339933;">*</span>vertice.<span style="color: #660066;">x</span><span style="color: #339933;">/</span>map.<span style="color: #660066;">width</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> y <span style="color: #339933;">=</span> ctx.<span style="color: #660066;">canvas</span>.<span style="color: #660066;">height</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">-</span>vertice.<span style="color: #660066;">y</span><span style="color: #339933;">/</span>map.<span style="color: #660066;">height</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>v<span style="color: #339933;">==</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">moveTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">lineTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">fill</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; addLegend<span style="color: #009900;">&#40;</span>color<span style="color: #339933;">,</span> <span style="color: #000066;">name</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> <span style="color: #000066;">name</span> <span style="color: #000066; font-weight: bold;">in</span> map<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> objs <span style="color: #339933;">=</span> map<span style="color: #009900;">&#91;</span><span style="color: #000066;">name</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>objs<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&amp;&amp;</span> objs<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">x</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> color <span style="color: #339933;">=</span> randomColor<span style="color: #009900;">&#40;</span><span style="color: #CC0000;">50</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">strokeStyle</span> <span style="color: #339933;">=</span> color<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">lineWidth</span> <span style="color: #339933;">=</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #000066; font-weight: bold;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">var</span> i<span style="color: #339933;">=</span><span style="color: #CC0000;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">&lt;</span>objs.<span style="color: #660066;">length</span><span style="color: #339933;">;</span> <span style="color: #339933;">++</span>i<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> p <span style="color: #339933;">=</span> objs<span style="color: #009900;">&#91;</span>i<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> x <span style="color: #339933;">=</span> ctx.<span style="color: #660066;">canvas</span>.<span style="color: #660066;">width</span><span style="color: #339933;">*</span>p.<span style="color: #660066;">x</span><span style="color: #339933;">/</span>map.<span style="color: #660066;">width</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #003366; font-weight: bold;">var</span> y <span style="color: #339933;">=</span> ctx.<span style="color: #660066;">canvas</span>.<span style="color: #660066;">height</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">-</span>p.<span style="color: #660066;">y</span><span style="color: #339933;">/</span>map.<span style="color: #660066;">height</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">beginPath</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">moveTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">-</span>CROSS_SIZE<span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">lineTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">+</span>CROSS_SIZE<span style="color: #339933;">,</span> y<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">moveTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> y<span style="color: #339933;">-</span>CROSS_SIZE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">lineTo</span><span style="color: #009900;">&#40;</span>x<span style="color: #339933;">,</span> y<span style="color: #339933;">+</span>CROSS_SIZE<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; ctx.<span style="color: #660066;">stroke</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; addLegend<span style="color: #009900;">&#40;</span>color<span style="color: #339933;">,</span> <span style="color: #000066;">name</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; <span style="color: #009900;">&#125;</span><br />
&nbsp; container.<span style="color: #660066;">append</span><span style="color: #009900;">&#40;</span>canvas<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<h2>What is next?</h2>
<p>Blazing Race, is not finished yet, I need to improve a lot of things <img src='http://blog.greweb.fr/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>I&#8217;ll try to release a standalone version of this converter soon with tutorials and examples.</p>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1386&amp;md5=2c2556d00a78a66918b711c32f801419" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/04/blender-as-a-2d-game-map-editor-proof-of-concept/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F04%2Fblender-as-a-2d-game-map-editor-proof-of-concept%2F&amp;language=fr_FR&amp;category=text&amp;title=Blender+as+a+2D+game+level+editor+%26%238211%3B+Proof+Of+Concept&amp;description=A+long+time+ago%2C+video+games+were+only+two-dimensional.+Of-course+this+was+due+to+our+poor+hardware+capabilities%2C+but+when+computers+became+faster+and+faster+3D+games+appeared+in+mass....&amp;tags=3D%2CBBG%2Cblender%2Cgame%2Cjavascript%2Cblog" type="text/html" />
	</item>
		<item>
		<title>Play Painter &#8211; how i&#8217;ve improved the 30 minutes prototyped version</title>
		<link>http://blog.greweb.fr/2012/03/play-painter-how-ive-improved-the-30-minutes-prototyped-version/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=play-painter-how-ive-improved-the-30-minutes-prototyped-version</link>
		<comments>http://blog.greweb.fr/2012/03/play-painter-how-ive-improved-the-30-minutes-prototyped-version/#comments</comments>
		<pubDate>Sat, 17 Mar 2012 20:52:43 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[playframework]]></category>
		<category><![CDATA[WebSocket]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1286</guid>
		<description><![CDATA[One week ago, I&#8217;ve released a technical web experiment featuring a collaborative real-time Paint-like application I&#8217;ve called Play Painter. It has been made with Play Framework 2 and rely on WebSocket and HTML5 Canvas Javascript APIs. Thanks to everyone having tested my Play Painter experiment, you helped me figure out bugs and bottlenecks and to <a href='http://blog.greweb.fr/2012/03/play-painter-how-ive-improved-the-30-minutes-prototyped-version/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p>One week ago, I&#8217;ve released a <a href="http://blog.greweb.fr/2012/03/30-minutes-to-make-a-multi-user-real-time-paint-with-play-2-framework-canvas-and-websocket/">technical web experiment</a> featuring <strong>a collaborative real-time Paint-like application I&#8217;ve called Play Painter</strong>. It has been made with <a href="http://playframework.org/">Play Framework 2</a> and rely on WebSocket and HTML5 Canvas Javascript APIs.</p>
<p>Thanks to everyone having tested my Play Painter experiment, you helped me figure out bugs and bottlenecks and to benchmark the application running on my tiny server.<br />
The first version of Play Painter has been improved with some optimizations. </p>
<p>Explanation&#8230;</p>
<p><a href="https://twitter.com/#!/greweb/status/179194592481116160/photo/1"><img src="http://blog.greweb.fr/wp-content/uploads/2012/03/twitt_playpainter.png" alt="" title="twitt_playpainter" width="508" height="490" class=" size-full wp-image-1287" /></a></p>
<p><span id="more-1286"></span></p>
<h2>In brief</h2>
<ul>
<li><strong>80 twitts</strong>, <strong>3500 unique visitors</strong> in a few days.</li>
<li>a peak of about <strong>80 simultaneous painters</strong>.</li>
<li>about <strong>200 WebSocket messages per second</strong> when 3-4 users are drawing => bottleneck found.</li>
<li>when it occurs, 100% CPU and about <strong>1500 system interrupts per second</strong> on my poor Atom 1.2 Ghz server.</li>
</ul>
<h2>Some reasons</h2>
<p>The initial version of Play Painter was a basic fast-prototyped version:</p>
<p>First, It was <strong>spreading every mouse events</strong> (down, up, move) to all clients <strong>as fast as it comes</strong>. It means that, depending on the computer and browser performance, a huge number of events could have been triggered and spread to all connected users.</p>
<p>We solved this by <strong>Chunking draw events</strong>.</p>
<p>Second, <strong>a lot of informations was repeated in WebSocket messages.</strong> No datas were stored on the server-side so to be sure a new user see the right draws, player name, brush color and size was sent in every message. Multiply this by the number of mouse events and you get a lot of useless information!</p>
<p>We are now <strong>Storing painters information</strong>.</p>
<h2>Chunking draw events</h2>
<p>When an user starts drawing, mouse events give the brush positions (x, y). But instead of sending a websocket message for each of these new positions, they are stored, and every <strong>X</strong> milliseconds, are sent in a websocket message. Such message contains all points of the draw from the last sent draw message.</p>
<p>The <strong>X</strong> value has currently been fixed to <strong>50 milliseconds</strong> because it&#8217;s enough for the human eye: It means about 20 messages per second for one painter. In movies we usually have a 24 frame rate.</p>
<p>The same principle has been applied on the painter brush positions.</p>
<h3>Example</h3>
<p><strong>Before</strong><br />
13 WebSocket messages:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">181</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">259</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">183</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">259</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">184</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">257</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">187</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">257</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">188</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">257</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">191</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">256</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">192</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">255</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">192</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">255</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">192</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">254</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">193</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">254</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">195</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">254</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">196</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">253</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;lineTo&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">196</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">253</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span></div></div>
<p><strong>After</strong><br />
2 WebSocket messages: (50 ms apart)</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;trace&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;points&quot;</span><span style="color: #339933;">:</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">181</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">259</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">183</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">259</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">184</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">257</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">187</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">257</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">188</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">257</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">191</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">256</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">192</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">255</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;trace&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;points&quot;</span><span style="color: #339933;">:</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">192</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">255</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">192</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">254</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">193</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">254</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">195</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">254</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">195</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">253</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">196</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">253</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">196</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">253</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span></div></div>
<h3>To a variable frame rate?</h3>
<p>I am also thinking about a variable rate depending of the number of active painters. In fact, the more we have painters, the more we will have messages, and the more the server will have system interrupts, we could then decrease the frame rate per second to reduce this load.</p>
<p>The problem of this extreme approach is the degradation of the feeling of real-time.</p>
<p>For now, I&#8217;m keeping the constant frame rate version, we will see how far it goes.</p>
<h2>Storing painters information</h2>
<p>As I said, <strong>a lot of informations was repeated in WebSocket messages.</strong> In every draw events, painter name, brush size and brush color was sent from the client to the server, and the spread into all connected clients.</p>
<p>This was ok for prototyping but we have now optimize this by storing these painter generic informations in the server and sending them when a new WebSocket connection is opened.</p>
<h3>Example</h3>
<p>This is what a client can receive when a websocket is connected:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;youAre&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">24</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;john&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;color&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;red&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;size&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;painter&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">21</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;gre&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;color&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;red&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;size&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;painter&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">24</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;peter&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;color&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;red&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;size&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;painter&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">4</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;paul&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;color&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;red&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;size&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;painter&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">6</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;name&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;jack&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;color&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;red&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;size&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">5</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;painter&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#125;</span></div></div>
<p>and then&#8230;</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;type&quot;</span><span style="color: #339933;">:</span><span style="color: #3366CC;">&quot;trace&quot;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;points&quot;</span><span style="color: #339933;">:</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">181</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">259</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">183</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">259</span><span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><span style="color: #009900;">&#123;</span><span style="color: #3366CC;">&quot;x&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">184</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;y&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">257</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span><span style="color: #3366CC;">&quot;pid&quot;</span><span style="color: #339933;">:</span><span style="color: #CC0000;">19</span><span style="color: #009900;">&#125;</span><br />
...</div></div>
<p>By knowing all painter properties, when someone will draw something, he will not have to repeat which color and size its brush has.</p>
<h3>Server side</h3>
<p>It was quite interesting to implement the server part with <a href="https://github.com/playframework/Play20/wiki/Iteratees">Play2&#8242;s Iteratees</a>, a new way of handling I/O &#8211; not so new in fact because it is directly related to Haskell Iteratee concepts.</p>
<p>To implement a WebSocket connection, you will provide an <strong>Iteratee</strong> for consuming the <strong>input</strong> and an <strong>Enumerator</strong> for producing the <strong>output</strong>.</p>
<p>Enumerator are chainable, this is how I firstly send the painter id and painters informations:</p>
<div class="codecolorer-container scala default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="scala codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #008000; font-style: italic;">// out: handle messages to send to the painter</span><br />
<span style="color: #0000ff; font-weight: bold;">val</span> out <span style="color: #000080;">=</span><br />
&nbsp; <span style="color: #008000; font-style: italic;">// Inform the painter who he is (which pid, he can them identify himself)</span><br />
&nbsp; Enumerator<span style="color: #F78811;">&#40;</span>JsObject<span style="color: #F78811;">&#40;</span>Seq<span style="color: #F78811;">&#40;</span><span style="color: #6666FF;">&quot;type&quot;</span> -<span style="color: #000080;">&gt;</span> JsString<span style="color: #F78811;">&#40;</span><span style="color: #6666FF;">&quot;youAre&quot;</span><span style="color: #F78811;">&#41;</span>, <span style="color: #6666FF;">&quot;pid&quot;</span> -<span style="color: #000080;">&gt;</span> JsNumber<span style="color: #F78811;">&#40;</span>pid<span style="color: #F78811;">&#41;</span><span style="color: #F78811;">&#41;</span><span style="color: #F78811;">&#41;</span>.<span style="color: #000000;">as</span><span style="color: #F78811;">&#91;</span>JsValue<span style="color: #F78811;">&#93;</span><span style="color: #F78811;">&#41;</span> <span style="color: #000080;">&gt;&gt;&gt;</span><br />
&nbsp; <span style="color: #008000; font-style: italic;">// Inform the list of other painters</span><br />
&nbsp; Enumerator<span style="color: #F78811;">&#40;</span>painters.<span style="color: #000000;">map</span> <span style="color: #F78811;">&#123;</span> <span style="color: #0000ff; font-weight: bold;">case</span> <span style="color: #F78811;">&#40;</span>id, painter<span style="color: #F78811;">&#41;</span> <span style="color: #000080;">=&gt;</span><br />
&nbsp; &nbsp; <span style="color: #F78811;">&#40;</span>painter.<span style="color: #000000;">toJson</span> ++ JsObject<span style="color: #F78811;">&#40;</span>Seq<span style="color: #F78811;">&#40;</span><span style="color: #6666FF;">&quot;type&quot;</span> -<span style="color: #000080;">&gt;</span> JsString<span style="color: #F78811;">&#40;</span><span style="color: #6666FF;">&quot;painter&quot;</span><span style="color: #F78811;">&#41;</span>, <span style="color: #6666FF;">&quot;pid&quot;</span> -<span style="color: #000080;">&gt;</span> JsNumber<span style="color: #F78811;">&#40;</span>id<span style="color: #F78811;">&#41;</span><span style="color: #F78811;">&#41;</span><span style="color: #F78811;">&#41;</span><span style="color: #F78811;">&#41;</span>.<span style="color: #000000;">as</span><span style="color: #F78811;">&#91;</span>JsValue<span style="color: #F78811;">&#93;</span><br />
&nbsp; <span style="color: #F78811;">&#125;</span> toList <span style="color: #000080;">:</span> <span style="color: #000080;">_*</span><span style="color: #F78811;">&#41;</span> <span style="color: #000080;">&gt;&gt;&gt;</span><br />
&nbsp; <span style="color: #008000; font-style: italic;">// Stream the hub</span><br />
&nbsp; hub.<span style="color: #000000;">getPatchCord</span><span style="color: #F78811;">&#40;</span><span style="color: #F78811;">&#41;</span></div></div>
<p>The <strong>>>></strong> operator is a shortcut to the <strong>andThen</strong> method which is the way to chain enumerators.</p>
<p>For more details, <a href="https://github.com/gre/playpainter/blob/master/scala/app/controllers/Application.scala">see the scala code of the controller</a>.</p>
<h2>Other features</h2>
<p>The application has been improved in many other ways.</p>
<ul>
<li><strong>A &#8220;buffering&#8221; Canvas</strong> in the foreground has been add <strong>for the user draws</strong>. It brings client-side reactivity and helps to avoid unpleasant lag feeling when drawing. When the user draw events are coming from the server and no other user events has been sent since, it&#8217;s synchronized and we can clean this buffer.</li>
<li><strong>Painter positions are show with their names</strong>.</li>
<li>It should now work properly on <strong>smartphones and tablets</strong>. Try on iPad and iPhone, and maybe on recent version of Android (WebSocket support required).</li>
<li><strong>Keyboard shortcut</strong>: using arrows to change brush size and color.</li>
<li>The <strong><a href="http://github.com/gre/playpainter">source code</a> has been polished and commented</strong> especially the server side part (it&#8217;s probably the hardest part if you don&#8217;t know Play framework).</li>
<li>Error message displayed when a technology is not supported and when the WebSocket connection goes down (with a reconnecting try loop).</li>
</ul>
<h2>The demo is still online!</h2>
<p style="text-align: center"><a href="http://greweb.fr:9090/"><strong>greweb.fr:9090</strong></a></p>
<h2>Future</h2>
<p>With these two optimizations, I&#8217;ve reduce the global <strong>number of socket messages</strong> and also the <strong>size of each message</strong>.</p>
<p>The first benchmark sounds good, 3 painters was simultaneously crazily painting while the server application was only using less than 10% of CPU.</p>
<p>Now, the most challenging part would be to scale the application to a huge number of connections, but having maybe solved this bottleneck, it&#8217;s maybe now more a matter of system architecture than the application itself.</p>
<p>This experiment gave me a lot of interest in <strong>WebSocket</strong> and also in <strong>the powerful way WebSockets are handled in Play framework</strong>.</p>
<p><del datetime="2012-03-19T18:33:52+00:00">If anyone want to start a Java version of the application, please go on! <a href="https://github.com/gre/playpainter/issues/1">(this was requested on Github)</a></del></p>
<p>Thanks to <a href="https://twitter.com/dbathily">@dbathily</a>, we know have both Scala and Java version!</p>
<h3>Next experiment</h3>
<p>I am thinking about making a multiplayer game on the web.<br />
It would be something like a shooter survival game (like Counter Strike Zombie Mod) + a multi-plateform 2D side view game (like Mario) !</p>
<p>You will know more about this soon <img src='http://blog.greweb.fr/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1286&amp;md5=7275315bad53cd069dd836acaef41564" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/03/play-painter-how-ive-improved-the-30-minutes-prototyped-version/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F03%2Fplay-painter-how-ive-improved-the-30-minutes-prototyped-version%2F&amp;language=fr_FR&amp;category=text&amp;title=Play+Painter+%26%238211%3B+how+i%26%238217%3Bve+improved+the+30+minutes+prototyped+version&amp;description=One+week+ago%2C+I%26%238217%3Bve+released+a+technical+web+experiment+featuring+a+collaborative+real-time+Paint-like+application+I%26%238217%3Bve+called+Play+Painter.+It+has+been+made+with+Play+Framework+2+and+rely+on...&amp;tags=playframework%2CWebSocket%2Cblog" type="text/html" />
	</item>
		<item>
		<title>30 minutes to make a multi user real time paint with Play 2 framework, Canvas and WebSocket.</title>
		<link>http://blog.greweb.fr/2012/03/30-minutes-to-make-a-multi-user-real-time-paint-with-play-2-framework-canvas-and-websocket/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=30-minutes-to-make-a-multi-user-real-time-paint-with-play-2-framework-canvas-and-websocket</link>
		<comments>http://blog.greweb.fr/2012/03/30-minutes-to-make-a-multi-user-real-time-paint-with-play-2-framework-canvas-and-websocket/#comments</comments>
		<pubDate>Mon, 12 Mar 2012 07:00:22 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutoriels Vidéos]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[playframework]]></category>
		<category><![CDATA[WebSocket]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1191</guid>
		<description><![CDATA[I will show you how to implement a multi user paint using latest web technologies like Play framework (version 2), HTML5 Canvas and WebSocket. Let&#8217;s see how to implement this from scratch in about 30 minutes&#8230; and read how I&#8217;ve improved this initial version&#8230; or try the demo below&#8230; Fork me on Github.]]></description>
			<content:encoded><![CDATA[<p><a href="http://greweb.fr:9090/"><br />
<img src="http://blog.greweb.fr/wp-content/uploads/2012/03/playpainter_teaser2.png" alt="" title="playpainter_teaser" width="184" height="170" class="alignright size-full wp-image-1262" /><br />
</a></p>
<blockquote><p><em>I will show you how to <strong>implement a multi user paint</strong> using latest web technologies like <a href="http://playframework.org">Play framework</a> (version 2), <a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html">HTML5 Canvas</a> and <a href="http://dev.w3.org/html5/websockets/">WebSocket</a>.</em></p></blockquote>
<p>Let&#8217;s see how to implement this from scratch in about 30 minutes&#8230;</p>
<p><iframe width="560" height="315" src="http://www.youtube.com/embed/NHEbm-WEbRw" frameborder="0" allowfullscreen></iframe></p>
<p><a href="http://blog.greweb.fr/2012/03/play-painter-how-ive-improved-the-30-minutes-prototyped-version/">and read how I&#8217;ve improved this initial version&#8230;</a></p>
<p><a href="http://greweb.fr:9090">or try the demo below&#8230;</a></p>
<p><span id="more-1191"></span></p>
<p><iframe frameborder="0" src="http://greweb.fr:9090/" width="550" height="400" style="overflow: hidden"></iframe></p>
<p><a href="https://github.com/gre/playpainter">Fork me on Github.</a></p>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1191&amp;md5=ebdfc67b2eb68448d3fc347ebb47d9a9" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/03/30-minutes-to-make-a-multi-user-real-time-paint-with-play-2-framework-canvas-and-websocket/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F03%2F30-minutes-to-make-a-multi-user-real-time-paint-with-play-2-framework-canvas-and-websocket%2F&amp;language=sq_AL&amp;category=text&amp;title=30+minutes+to+make+a+multi+user+real+time+paint+with+Play+2+framework%2C+Canvas+and+WebSocket.&amp;description=I+will+show+you+how+to+implement+a+multi+user+paint+using+latest+web+technologies+like+Play+framework+%28version+2%29%2C+HTML5+Canvas+and+WebSocket.+Let%26%238217%3Bs+see+how+to+implement+this...&amp;tags=canvas%2Cplayframework%2CWebSocket%2Cblog" type="text/html" />
	</item>
		<item>
		<title>Chart libraries headaches &#8211; finding the best grid step</title>
		<link>http://blog.greweb.fr/2012/03/chart-libraries-headaches-finding-the-best-grid-step/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=chart-libraries-headaches-finding-the-best-grid-step</link>
		<comments>http://blog.greweb.fr/2012/03/chart-libraries-headaches-finding-the-best-grid-step/#comments</comments>
		<pubDate>Tue, 06 Mar 2012 21:22:22 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[chart]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[math]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1091</guid>
		<description><![CDATA[If you have ever made a chart library in your life, you&#8217;ve probably asked yourself how to find the best scale for the grid in order to have nice values to display in the axis. Most of the time, data ranges are unknown, hence we need to adapt the grid step to provide the best <a href='http://blog.greweb.fr/2012/03/chart-libraries-headaches-finding-the-best-grid-step/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/02/wrong-chart-scale.png" alt="" title="wrong-chart-scale" width="250" class="alignleft size-full wp-image-1189" /><br />
If you have ever made a chart library in your life, you&#8217;ve probably asked yourself how to find the best scale for the grid in order to have <strong>nice values to display in the axis</strong>.</p>
<p>Most of the time, <strong>data ranges are unknown</strong>, hence we need to <strong>adapt the grid step</strong> to provide the best display.</p>
<h2>Check this out</h2>
<p><iframe src="http://greweb.fr/grid-utils/" frameborder="0" width="525" height="140"></iframe></p>
<p>Let&#8217;s explain the algorithm&#8230;</p>
<p><span id="more-1091"></span></p>
<h2>About scientific notation</h2>
<p>Any number can be formatted in scientific notation. It is written in the form of <strong>A x 10<sup>N</sup></strong> and is noted <strong>AeN</strong>.</p>
<p>For instance, 2300 becomes <strong>2.3e3</strong> (because 2300 = 2.3 x 10<sup>3</sup>), 12 becomes <strong>1.2e1</strong>, and 0.23 becomes <strong>2.3e-1</strong>.</p>
<p>Scientific notation is exactly made for <strong>displaying huge or tiny values in a few characters</strong>.<br />
We can use the same principle for finding good values for the step scale, we can just <strong>keep the pow of 10</strong> part (<strong>N</strong>) and <strong>round the value part</strong> (<strong>A</strong>). </p>
<h2>Magic numbers</h2>
<p>But <strong>rounding is not enough</strong>, I have found that good pattern numbers of step range is those divisible by 2, 5 and 10.</p>
<p>In math term, we need to find a step range <em>sr</em>, where</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">∀ n ∈ |N, ∀ a ∈ {1, 2, 5}, ∃ sr, sr = a x 10^n</div></div>
<p>This is basically because 2 x 5 = 10 : using a step of 5 we have a 10 modularity every 2 step, and, using a step of 2 we have a 10 modularity every 5 step.</p>
<p><strong> 2 step:</strong> 0 2 4 6 8 <strong>10</strong> 12 14 16 18 <strong>20</strong> &#8230;<br />
<strong> 5 step:</strong> 0 5 <strong>10</strong> 15 <strong>20</strong> 25 <strong>30</strong> 35 <strong>40</strong> 45 &#8230;<br />
<strong>10 step:</strong> <strong>0 10 20 30 40 50 60 70 80 90</strong> &#8230;</p>
<p>For any dataset, we need to fallback on the closest step range in all of possible step ranges: &#8230; 0.002, 0.02, 0.2, 2, 20, 200, &#8230;, &#8230; 0.005, 0.05, 0.5, 5, 50, 500, &#8230;,  and &#8230; 0.001, 0.01, 0.1, 1, 10, 100, &#8230;, </p>
<h3>Calculate the pow of 10</h3>
<p>To get the <strong>N</strong> value of the <strong>A x 10<sup>N</sup></strong> form, we can use the log of 10:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">N <span style="color: #339933;">=</span> Math.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span>number<span style="color: #009900;">&#41;</span> <span style="color: #339933;">/</span> Math.<span style="color: #660066;">log</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span></div></div>
<h3>Calculate the value modulo 10</h3>
<p>To get the <strong>A</strong> value of the <strong>A x 10<sup>N</sup></strong> form, we can just divide the number by <strong>10<sup>N</sup></strong>:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">A <span style="color: #339933;">=</span> number <span style="color: #339933;">/</span> Math.<span style="color: #660066;">pow</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">10</span><span style="color: #339933;">,</span> N<span style="color: #009900;">&#41;</span></div></div>
<h3>&#8216;Rounding&#8217; the number</h3>
<p>We know just need to change the value of <strong>A</strong> and make it more &#8220;readable&#8221;.<br />
We can map the value as follow:</p>
<div class="codecolorer-container text default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">if A ∈ [0, 1.5[ then A becomes 1<br />
if A ∈ [1.5, 3.5[ then A becomes 2<br />
if A ∈ [3.5, 7.5[ then A becomes 5<br />
if A ∈ [7.5, 10[ then A becomes 10</div></div>
<p>Note that these rules may probably be improved, I would love if someone could improve this (because I use a arithmetic mean approach and it should probably be arithmetic).</p>
<h2>Implementation</h2>
<h3>Scala</h3>
<p><script src="https://gist.github.com/1987311.js?file=GridUtils.scala"></script></p>
<h3>Javascript</h3>
<p><script src="https://gist.github.com/1987311.js?file=GridUtils.js"></script></p>
<p><strong>Usage example:</strong></p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">GridUtils.<span style="color: #660066;">findNiceRoundStep</span> <span style="color: #009900;">&#40;</span>xMax<span style="color: #339933;">,</span> <span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span></div></div>
<p>where <em>xMax</em> is the scale of the axis, and <em>10</em> is the desired number of graduation split.</p>
<h2>Conclusion</h2>
<p>Finding the best grid step is finally a simple thing to implement but is an essential feature every chart libraries should have.</p>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1091&amp;md5=a2c3c143af6d87245cca0bd530de998b" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/03/chart-libraries-headaches-finding-the-best-grid-step/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F03%2Fchart-libraries-headaches-finding-the-best-grid-step%2F&amp;language=sq_AL&amp;category=text&amp;title=Chart+libraries+headaches+%26%238211%3B+finding+the+best+grid+step&amp;description=If+you+have+ever+made+a+chart+library+in+your+life%2C+you%26%238217%3Bve+probably+asked+yourself+how+to+find+the+best+scale+for+the+grid+in+order+to+have+nice+values...&amp;tags=chart%2Cjavascript%2Cmath%2Cblog" type="text/html" />
	</item>
		<item>
		<title>Bezier Curve based easing functions &#8211; from concept to implementation</title>
		<link>http://blog.greweb.fr/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=bezier-curve-based-easing-functions-from-concept-to-implementation</link>
		<comments>http://blog.greweb.fr/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation/#comments</comments>
		<pubDate>Wed, 29 Feb 2012 11:00:50 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[animation]]></category>
		<category><![CDATA[bezier]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=1041</guid>
		<description><![CDATA[Many animation libraries are today using easing functions &#8211; functions of time returning a progression percentage value. This is required to perform such cool effects: But most of these libraries implement a huge collection of functions. We will see how we can generalize them with bezier curves. For instance, we use to do this: EasingFunctions <a href='http://blog.greweb.fr/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/02/Capture-d’écran-2012-02-29-à-11.26.01.png" alt="" title="Bezier example" width="239" height="235" class="alignleft size-full wp-image-1159" /></p>
<p>Many animation libraries are today using <strong>easing functions</strong> &#8211; functions of time returning a progression percentage value. This is required to perform such cool effects:</p>
<p><iframe src="http://greweb.fr/ease-animation/" frameborder="0" height="40" width="300"></iframe> </p>
<p><br style="clear: left" /></p>
<p>But most of these libraries implement a huge collection of functions. We will see how we can generalize them with bezier curves.</p>
<p><span id="more-1041"></span></p>
<p>For instance, we use to do this:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">EasingFunctions <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; linear<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeInQuad<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeOutQuad<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">-</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeInOutQuad<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">&lt;</span>.5 <span style="color: #339933;">?</span> <span style="color: #CC0000;">2</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #339933;">:</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #339933;">+</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">4</span><span style="color: #339933;">-</span><span style="color: #CC0000;">2</span><span style="color: #339933;">*</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeInCubic<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeOutCubic<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">--</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">+</span><span style="color: #CC0000;">1</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeInOutCubic<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">&lt;</span>.5 <span style="color: #339933;">?</span> <span style="color: #CC0000;">4</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #339933;">:</span> <span style="color: #009900;">&#40;</span>t<span style="color: #339933;">-</span><span style="color: #CC0000;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">*</span>t<span style="color: #339933;">-</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">2</span><span style="color: #339933;">*</span>t<span style="color: #339933;">-</span><span style="color: #CC0000;">2</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">+</span><span style="color: #CC0000;">1</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeInQuart<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeOutQuart<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">-</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">--</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeInOutQuart<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">&lt;</span>.5 <span style="color: #339933;">?</span> <span style="color: #CC0000;">8</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">-</span><span style="color: #CC0000;">8</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">--</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeInQuint<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeOutQuint<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">+</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">--</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span><br />
&nbsp; easeInOutQuint<span style="color: #339933;">:</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">&lt;</span>.5 <span style="color: #339933;">?</span> <span style="color: #CC0000;">16</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #339933;">:</span> <span style="color: #CC0000;">1</span><span style="color: #339933;">+</span><span style="color: #CC0000;">16</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">--</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>Defining such functions is lot of math fun but it is very <strong>specific</strong> and not really customizable. Hopefully, we can generalize these easing functions. With <strong>Bezier curves</strong>.</p>
<p>In fact, this work has already been done in CSS Transitions and CSS Animations specifications! You can use <code class="codecolorer css default"><span class="css">transition-timing-function</span></code> CSS property and give a <code class="codecolorer css default"><span class="css">cubic-bezier<span style="color: #00AA00;">&#40;</span>x1<span style="color: #00AA00;">,</span> y1<span style="color: #00AA00;">,</span> x2<span style="color: #00AA00;">,</span> y2<span style="color: #00AA00;">&#41;</span></span></code> value (all <strong>ease, linear, ease-in, ease-out, ease-in-out</strong> values are just fallbacking on this cubic-bezier usage).</p>
<p><img src="http://blog.greweb.fr/wp-content/uploads/2012/02/TimingFunction.png" alt="" width="300" class="alignleft size-full wp-image-1093" /></p>
<p>In a bezier curve based easing function, the X axis is the <strong>time axis</strong> whereas the Y axis represents the <strong>percentage of progress</strong> of the animation.<br />
The two points P1 and P2 are called <strong>handles</strong> and you can (exclusively) control their X and Y positions to generate every possible cubic timing function.</p>
<p><br style="clear: left" /></p>
<h3>Live demo</h3>
<p>Try to interact with the handles:<br />
<iframe src="http://greweb.fr/bezier-easing/" frameborder="0" width="560" height="400"></iframe></p>
<h2>Implementation</h2>
<p>Ok, so, this bezier curve concept is great but how can I implement it?</p>
<p>I&#8217;ve read <a href="http://13thparallel.com/archive/bezier-curves/">here</a>  how simple is it to <strong>compute many points of a Bezier curve</strong> and potentially draw them:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">function</span> B1<span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t <span style="color: #009900;">&#125;</span><br />
<span style="color: #003366; font-weight: bold;">function</span> B2<span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span>t<span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">-</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><br />
<span style="color: #003366; font-weight: bold;">function</span> B3<span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #CC0000;">3</span><span style="color: #339933;">*</span>t<span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">-</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">-</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><br />
<span style="color: #003366; font-weight: bold;">function</span> B4<span style="color: #009900;">&#40;</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">-</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">-</span>t<span style="color: #009900;">&#41;</span><span style="color: #339933;">*</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">1</span><span style="color: #339933;">-</span>t<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><br />
<span style="color: #003366; font-weight: bold;">function</span> getBezier<span style="color: #009900;">&#40;</span>percent<span style="color: #339933;">,</span>C1<span style="color: #339933;">,</span>C2<span style="color: #339933;">,</span>C3<span style="color: #339933;">,</span>C4<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #003366; font-weight: bold;">var</span> pos <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> coord<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pos.<span style="color: #660066;">x</span> <span style="color: #339933;">=</span> C1.<span style="color: #660066;">x</span><span style="color: #339933;">*</span>B1<span style="color: #009900;">&#40;</span>percent<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> C2.<span style="color: #660066;">x</span><span style="color: #339933;">*</span>B2<span style="color: #009900;">&#40;</span>percent<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> C3.<span style="color: #660066;">x</span><span style="color: #339933;">*</span>B3<span style="color: #009900;">&#40;</span>percent<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> C4.<span style="color: #660066;">x</span><span style="color: #339933;">*</span>B4<span style="color: #009900;">&#40;</span>percent<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; pos.<span style="color: #660066;">y</span> <span style="color: #339933;">=</span> C1.<span style="color: #660066;">y</span><span style="color: #339933;">*</span>B1<span style="color: #009900;">&#40;</span>percent<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> C2.<span style="color: #660066;">y</span><span style="color: #339933;">*</span>B2<span style="color: #009900;">&#40;</span>percent<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> C3.<span style="color: #660066;">y</span><span style="color: #339933;">*</span>B3<span style="color: #009900;">&#40;</span>percent<span style="color: #009900;">&#41;</span> <span style="color: #339933;">+</span> C4.<span style="color: #660066;">y</span><span style="color: #339933;">*</span>B4<span style="color: #009900;">&#40;</span>percent<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> pos<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
<p>But it&#8217;s not enough. We need to project a point to the Bezier curve, in other words, we need to get the Y of a given X in the bezier curve, and we can&#8217;t just get it with the <code class="codecolorer javascript default"><span class="javascript">percent</span></code> parameter of the Bezier computation.<br />
<strong>We need an interpolation.</strong></p>
<h3>Deep into Firefox implementation</h3>
<p>In Mozilla Firefox, The bezier curve interpolation is implemented in nsSMILKeySpline.cpp : <a href="https://gist.github.com/1925793">https://gist.github.com/1925793</a>.</p>
<p>What we can learn from it is:</p>
<ul>
<li>A first optimization store <strong>sample values of the bezier curve</strong> in a small table used to roughly find a initial X guess.</li>
<li>Then, it use two different implementation strategies: One use the <a href="http://en.wikipedia.org/wiki/Newton%27s_method">Newton&#8217;s method</a> and the other is just a <a href="http://en.wikipedia.org/wiki/Dichotomic_search">dichotomic search</a> (binary subdivision).</li>
<li>A <strong>criteria</strong> based on the <strong>slope</strong> give the best strategy to take.</li>
</ul>
<p>These sub-optimizations probably make the difference for the C++ version but are not really relevant for the JavaScript implementation. Moreover, I have only used the Newton&#8217;s method algorithm.<br />
And this is the code:</p>
<p><script src="https://gist.github.com/1926947.js?file=KeySpline.js"></script></p>
<p>Now we can just alias some classic easing function &#8211; like CSS does.</p>
<p><script src="https://gist.github.com/1926947.js?file=EasingFunctions.json"></script></p>
<p>I&#8217;m working on the next version of <a href="http://sliderjs.org/">Slider.JS</a> which relies on 3 different technologies for image transitions: <strong>CSS Transitions</strong>, <strong>Canvas</strong> and <strong>GLSL shaders (from WebGL)</strong>.<br />
I have now found <strong>a common way to describe easing functions for both CSS-based and Javascript-based animations</strong>!</p>
<p>This example has shown that sometimes, finding a larger solution for a problem is more interesting than having specific solutions.<br />
<strong>This is called the <a href="http://en.wikipedia.org/wiki/Inventor's_paradox">Inventor&#8217;s paradox</a>.</strong></p>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=1041&amp;md5=f7f6bbca724badaddb881ed997cf548a" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/02/bezier-curve-based-easing-functions-from-concept-to-implementation/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F02%2Fbezier-curve-based-easing-functions-from-concept-to-implementation%2F&amp;language=sq_AL&amp;category=text&amp;title=Bezier+Curve+based+easing+functions+%26%238211%3B+from+concept+to+implementation&amp;description=Many+animation+libraries+are+today+using+easing+functions+%26%238211%3B+functions+of+time+returning+a+progression+percentage+value.+This+is+required+to+perform+such+cool+effects%3A+But+most+of+these+libraries...&amp;tags=animation%2Cbezier%2Ccss%2Cjavascript%2Cblog" type="text/html" />
	</item>
		<item>
		<title>CSS-selector-based templating system for scalable JavaScript applications</title>
		<link>http://blog.greweb.fr/2012/02/css-selector-based-templating-example-with-javascript/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=css-selector-based-templating-example-with-javascript</link>
		<comments>http://blog.greweb.fr/2012/02/css-selector-based-templating-example-with-javascript/#comments</comments>
		<pubDate>Sat, 04 Feb 2012 13:30:45 +0000</pubDate>
		<dc:creator>Gaetan</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[scalable]]></category>
		<category><![CDATA[templating]]></category>

		<guid isPermaLink="false">http://blog.greweb.fr/?p=987</guid>
		<description><![CDATA[In this article, we will focus on the power of CSS as a descriptive language, current template system approach and their problems with modularity and extensibility, and try to mix both features from the concept to a concrete implementation. What is CSS ? CSS is an extremely powerful descriptive language. It helps to define how <a href='http://blog.greweb.fr/2012/02/css-selector-based-templating-example-with-javascript/' class='excerpt-more'>[...]</a>]]></description>
			<content:encoded><![CDATA[<p><img alt="" src="http://blog.greweb.fr/wp-content/uploads/2012/02/218px-Mir_diagram-fr.svg_.png" title="Mir station modularity" class="alignleft" width="218" height="240" /> In this article, we will focus on the power of <strong>CSS as a descriptive language</strong>, current template system approach and their problems with <strong>modularity</strong> and <strong>extensibility</strong>, and try to mix both features from the <strong>concept</strong> to a <strong>concrete implementation</strong>.</p>
<p><br style="clear: both" /><br />
<span id="more-987"></span></p>
<h2>What is <abbr title="Cascading Style Sheets">CSS</abbr> ?</h2>
<p><abbr title="Cascading Style Sheets">CSS</abbr> is an extremely powerful descriptive language.<br />
It helps to define <strong>how to display a document</strong> (e.g. a web page).</p>
<p>A style sheet contains a set of <strong>CSS rules</strong>.<br />
Each CSS rule has a <strong>CSS selector</strong> associated with a set of <strong>declarations</strong>.<br />
You can see a CSS selector as a selection filter applied on every HTML element. A few element can match a CSS selector if they fit the structure describes in this selector.<br />
Each <strong>declaration</strong> is composed of a couple (<strong>property</strong> : <strong>value</strong>).<br />
The <strong>CSS property</strong> is a predefined property related to a display or layout behavior.<br />
The <strong>value</strong> will apply a custom value for the property on all elements matching the CSS selector.</p>
<p>Let&#8217;s focus on some advantages of this descriptive language:</p>
<h3>A CSS rule is independant from others.</h3>
<p>The order of CSS rules <em>(selector + declarations)</em> <strong>really</strong> does not matter.<br />
The priority between CSS rules is based on the selector itself and not on their arrangement.</p>
<h3>You can &#8220;mix&#8221; CSS rule</h4>
<p>2 CSS rules can have the same CSS selector. An element can be matched with multiple CSS rules. CSS rules are merged, it&#8217;s called the cascading.<br />
This is the most important feature of CSS.<br />
It implies a very modular and extensible language.</p>
<h4>Example</h4>
<div class="codecolorer-container css default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="css codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">a <span style="color: #00AA00;">&#123;</span> <br />
&nbsp; <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#33CC00</span><span style="color: #00AA00;">;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">text-decoration</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">none</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
a<span style="color: #3333ff;">:hover </span><span style="color: #00AA00;">&#123;</span> <span style="color: #000000; font-weight: bold;">text-decoration</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">underline</span><span style="color: #00AA00;">;</span> <span style="color: #00AA00;">&#125;</span><br />
<span style="color: #cc00cc;">#articles</span> <span style="color: #00AA00;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">font-size</span><span style="color: #00AA00;">:</span> <span style="color: #933;">12px</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span><br />
<span style="color: #cc00cc;">#articles</span> a <span style="color: #00AA00;">&#123;</span><br />
&nbsp; <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">red</span><span style="color: #00AA00;">;</span> <span style="color: #808080; font-style: italic;">/* overriding the generic color of a */</span><br />
<span style="color: #00AA00;">&#125;</span></div></div>
<h2>Some limitations of today&#8217;s template system</h2>
<p>Most of template system are based on inherence between templates.</p>
<ul>
<li>You have usually an &#8220;inclusion&#8221; approach: a template will &#8220;include&#8221; multiple external template. <em>(Many template into Many template)</em></li>
<li>And an &#8220;extension&#8221; approach: You define in a main template an area where you can append a template. Others templates &#8220;extend&#8221; your main template. <em>(One main template for Many template)</em></li>
</ul>
<p>These approaches aims to factorize template codes and that&#8217;s great.</p>
<p>But it doesn&#8217;t fit my needs:</p>
<ul>
<li>It brings <strong>dependencies between templates</strong>. </li>
<li>If you add a new template, you have to modify existing templates.<br />
If your application tend to go modules based, this is going to be unmaintainable.
</li>
</ul>
<blockquote><p>
<strong>web application module (n)</strong><br />
1 : an independent unit of functionality that is part of the total structure of a web application
</p></blockquote>
<h3>A solution for scalable applications and libraries</h3>
<p>I&#8217;ve recently started to rewrite my <a href="http://sliderjs.org/">SliderJS</a> library and I needed to split it into very modular features and having loose coupling between each component.</p>
<p>I followed this <a href="http://www.ubelly.com/2011/11/scalablejs/">Scalable JavaScript Application Architecture</a> article.</p>
<p>So, <strong>how to bring loose coupling in templating?</strong>.<br />
Each module have its own template and know where to append. Bringing this logic in a main template would break the independency and if I need to add new modules soon, it will not working without modifiyng it.<br />
How to keep the scalability of the main template without modifying it?</p>
<p><!--<br />
A first solution I found was to use some "dom created" events triggered each time a module has templated its HTML and appended into the DOM. This solution was bad and bring 2 issues:<br />
You can't easily define the position of your node, for instance if 3 modules need to append in a same container, you don't know what will result about their appending order.<br />
It brings more dependency between modules, it's not so loosely-coupled.<br />
--></p>
<p>The best solution I found is to combine <strong>CSS selectors</strong> concepts with <strong>template system</strong> approaches.</p>
<h2>CSS concepts applied on templating</h2>
<p>I&#8217;ve decided to inspire from CSS: <strong>attaching a CSS selector with a template</strong>.<br />
It benefits from some CSS advantages explained before.</p>
<h3>Simple twitter widget example</h3>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitter&quot;</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h1</span>&gt;</span>Twitter<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h1</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitts&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitt&quot;</span>&gt;</span>Hello world!<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;footer&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://twitter.com/greweb&quot;</span>&gt;</span>Follow me on twitter<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span>footer&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></div>
<h4>Classical approach</h4>
<p>The way to template it with the classical approach would be:</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitter&quot;</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h1</span>&gt;</span>Twitter<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h1</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitts&quot;</span>&gt;</span><br />
&nbsp; &nbsp; {for twitt in twitts}<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitt&quot;</span>&gt;</span>{twitt}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; {/for}<br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;footer&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://twitter.com/{me}&quot;</span>&gt;</span>Follow me on twitter<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span>footer&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></div>
<h4>CSS selector based approach</h4>
<p>But we can also split the original &#8220;template&#8221; in small fragments and mix all of them.<br />
It helps to define each templates independently.</p>
<p><strong>We can identify:</strong></p>
<p>- A <strong>root template fragment</strong>:</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitter&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></div>
<p>- A <strong>header fragment</strong> appended with <code class="codecolorer css default"><span class="css">.twitter</span></code> selector and with an <strong>high priority</strong>:</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h1</span>&gt;</span>Twitter<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h1</span>&gt;</span></div></div>
<p>- A <strong>twitts list fragment</strong> appended with <code class="codecolorer css default"><span class="css">.twitter</span></code> selector:</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitts&quot;</span>&gt;</span><br />
&nbsp; {for twitt in twitts}<br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;twitt&quot;</span>&gt;</span>{twitt}<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; {/for}<br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span></div></div>
<p>with <strong>parameters</strong> <code class="codecolorer javascript default"><span class="javascript">twitts <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span> <span style="color: #3366CC;">&quot;Hello world!&quot;</span> <span style="color: #009900;">&#93;</span></span></code></p>
<p>- An empty <strong>footer fragment</strong> appended with <code class="codecolorer css default"><span class="css">.twitter</span></code> selector and with a <strong>low</strong> priority:</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;footer&gt;&lt;<span style="color: #66cc66;">/</span>footer&gt;</span></div></div>
<p>- A &#8220;follow me&#8221; <strong>link fragment</strong> appended with <code class="codecolorer css default"><span class="css"><span style="color: #6666ff;">.twitter</span> footer</span></code> selector:</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;http://twitter.com/{me}&quot;</span>&gt;</span>Follow me on twitter<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span></div></div>
<p>with <strong>parameters</strong> <code class="codecolorer javascript default"><span class="javascript">me <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;greweb&quot;</span></span></code></p>
<h3>Advanced example</h3>
<p>This is another example with a slider. </p>
<p>Let&#8217;s conceptually imagine the following template language:</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:350px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@root { html: <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slider&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span> }<br />
<br />
.slider {<br />
&nbsp; html: <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slides&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
}<br />
<br />
.slider div.slides {<br />
&nbsp; html: <span style="color: #009900;">&lt;canvas <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slides&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>canvas&gt;</span><br />
}<br />
<br />
.slider div.slides {<br />
&nbsp; html:<br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slide&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;&lt;%= link %&gt;</span></span>&quot;&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;&lt;%= img %&gt;</span></span>&quot; /&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;caption&quot;</span>&gt;&lt;%<span style="color: #66cc66;">=</span> <span style="color: #000066;">title</span> %&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">span</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
}<br />
<br />
.slider {<br />
&nbsp; priority: -10<br />
&nbsp; html: <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;pager&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
}<br />
<br />
.slider div.pager {<br />
&nbsp; priority: 10<br />
&nbsp; html: <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;prevSlide&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;javascript:;&quot;</span>&gt;</span>prev<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
}<br />
<br />
.slider div.pager {<br />
&nbsp; priority: -10<br />
&nbsp; html: <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;nextSlide&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;javascript:;&quot;</span>&gt;</span>next<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
}<br />
<br />
.slider div.pager {<br />
&nbsp; html: <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;pages&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">span</span>&gt;</span><br />
}<br />
<br />
.slider div.pager {<br />
&nbsp; html: <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">span</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;pages&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% <span style="color: #000066;">for</span> <span style="color: #66cc66;">&#40;</span>var i<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">0</span>; i&lt;slides.length; ++i<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span> %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;page&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;javascript:;&quot;</span>&gt;&lt;%<span style="color: #66cc66;">=</span> i+<span style="color: #cc66cc;">1</span> %&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% <span style="color: #66cc66;">&#125;</span> %&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">span</span>&gt;</span><br />
}</div></div>
<p>combined with some parameters, it will result</p>
<div class="codecolorer-container html4strict default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;"><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slider&quot;</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slides&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slide&quot;</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;..&quot;</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">img</span> <span style="color: #000066;">src</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;..&quot;</span><span style="color: #66cc66;">/</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">span</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;caption&quot;</span>&gt;</span>...<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">span</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slide&quot;</span>&gt;</span>...<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slide&quot;</span>&gt;</span>...<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;canvas <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;slides&quot;</span>&gt;&lt;<span style="color: #66cc66;">/</span>canvas&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;pager&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;javascript:;&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;prevSlide&quot;</span>&gt;</span>prev<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;pages&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;javascript:;&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;page&quot;</span>&gt;</span>1<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;javascript:;&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;page&quot;</span>&gt;</span>2<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;javascript:;&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;page&quot;</span>&gt;</span>3<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;javascript:;&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;nextSlide&quot;</span>&gt;</span>next<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></div>
<p>Of-course we could also do this programmatically with DOM. But see the benefit of such a descriptive way to define things?</p>
<p>You should keep in mind that <strong>the order of rules definition does not matter</strong>. In that&#8217;s sense, it is <strong>a mixable, extensible, modular and loosely-coupled template system</strong>.</p>
<h3>More about this <abbr title="Proof Of Concept">POC</abbr></h3>
<p>Unlike CSS, <strong>two same rules aren&#8217;t merged but are appended</strong>.</p>
<p>The <em><strong>priority</strong></em> governs the order of append. The higher the value is, the sooner it is appended to the containers selected by the CSS selector.</p>
<p>As you can see, there is a <strong>micro-templating</strong> inside each rule. For this example, it looks like the John Resig &#8216;s Micro Templating.</p>
<p>Note also that a rule must be aware of its <strong>parameters</strong> to work properly. But this only concerns the implementation: You have to find a way to give a dynamic reference of these parameters when you add a rule.</p>
<h3>Concrete implementation</h3>
<p>The code above was a conceptual proof of concept, but I implement a subset of these features in Javascript and made &#8220;SelectorTemplating.js&#8221; available here : <a href="https://gist.github.com/1731611">https://gist.github.com/1731611</a></p>
<p>This is how it can be used for (almost) the same example. You will see different style of usage:</p>
<div class="codecolorer-container javascript default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:435px;height:350px;"><div class="javascript codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #003366; font-weight: bold;">var</span> node <span style="color: #339933;">=</span> document.<span style="color: #660066;">getElementById</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;slider&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">var</span> t <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> SelectorTemplating<span style="color: #009900;">&#40;</span>node<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">var</span> tmpl<span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// defined somewhere, the John Resig 's Micro Templating.</span><br />
<br />
<span style="color: #006600; font-style: italic;">// root module</span><br />
<span style="color: #003366; font-weight: bold;">function</span> root <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">'&lt;div class=&quot;slider&quot;&gt;&lt;/div&gt;'</span> <span style="color: #009900;">&#125;</span><br />
t.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> root<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #006600; font-style: italic;">// slides module</span><br />
<span style="color: #003366; font-weight: bold;">var</span> slidesTmpl <span style="color: #339933;">=</span> tmpl<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;div class=&quot;slides&quot;&gt; &lt;% if(obj.slides) { for(var i=0; i&lt;slides.length; ++i) { var s = slides[i]; %&gt; &lt;div class=&quot;slide&quot;&gt; &lt;a href=&quot;&lt;%= s.link %&gt;&quot;&gt; &lt;img src=&quot;&lt;%= s.img %&gt;&quot; /&gt; &lt;span class=&quot;caption&quot;&gt;&lt;%= s.title %&gt;&lt;/span&gt; &lt;/a&gt; &lt;/div&gt; &lt;% }} %&gt; &lt;/div&gt;'</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #003366; font-weight: bold;">var</span> slides <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span> ... <span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// mutable</span><br />
t.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.slider&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> slidesTmpl<span style="color: #009900;">&#40;</span>slides<span style="color: #339933;">:</span> slides<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #006600; font-style: italic;">// canvas module</span><br />
t.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.slider div.slides&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">'&lt;canvas class=&quot;slides&quot;&gt;&lt;/canvas&gt;'</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<br />
<span style="color: #006600; font-style: italic;">// pager module</span><br />
<span style="color: #003366; font-weight: bold;">var</span> pagesTmpl <span style="color: #339933;">=</span> tmpl<span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'&lt;div class=&quot;pager&quot;&gt; &lt;span class=&quot;pages&quot;&gt; &lt;% if(obj.slides) { for(var i=0; i&lt;slides.length; ++i) { %&gt; &lt;a href=&quot;javascript:;&quot; class=&quot;page&quot;&gt;&lt;%= i+1 %&gt;&lt;/a&gt; &lt;% }} %&gt; &lt;/span&gt; &lt;/div&gt;'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #003366; font-weight: bold;">var</span> slides <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>...<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// synchronised with the slides module</span><br />
<span style="color: #003366; font-weight: bold;">var</span> prevButton<span style="color: #339933;">,</span> nextButton<span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// DOM element init when templated</span><br />
<span style="color: #003366; font-weight: bold;">var</span> pages <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><br />
&nbsp; <span style="color: #000066; font-weight: bold;">return</span> pagesTmpl<span style="color: #009900;">&#40;</span>slides<span style="color: #339933;">:</span> slides<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
t.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.sliderjs&quot;</span><span style="color: #339933;">,</span> pages<span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span><br />
t.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.sliderjs .options&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">'&lt;a class=&quot;prevSlide&quot; href=&quot;javascript:;&quot;&gt;prev&lt;/a&gt;'</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>n<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> prevButton <span style="color: #339933;">=</span> n<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">10</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// prepend first in options</span><br />
t.<span style="color: #660066;">add</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;.sliderjs .options&quot;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> <span style="color: #000066; font-weight: bold;">return</span> <span style="color: #3366CC;">'&lt;a class=&quot;nextSlide&quot; href=&quot;javascript:;&quot;&gt;next&lt;/a&gt;'</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span> <span style="color: #009900;">&#40;</span>n<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span> nextButton <span style="color: #339933;">=</span> n<span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #CC0000;">10</span> <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #006600; font-style: italic;">// append at the end of options</span><br />
<br />
<span style="color: #006600; font-style: italic;">// when all modules are init :</span><br />
t.<span style="color: #660066;">init</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></div></div>
<pre>
t.add (selector, templateFunction, callback, priority)
 * selector is the selector function. if null, append to root.
 * a template function is an identifier in the template.
 * the callback is called at the end of the templating with 2 arguments : the appended nodes and the global container.
</pre>
<h4>Algorithm of the template process</h4>
<pre>
container := the container element
rules := an array containing all rules.
sort rules by priority.
(1) take one rule from rules
  - elements := []
  - if the selector is @root, elements := [container]
  - otherwise, elements := all elements which matches the selector
  - if the elements is empty, back to (1) by taking the next rule.
  - (2) if not, templatize the html and append it into all of these elements. remove the rule from rules. back to (1) by starting from the first rules. 

the loop (1) must end when :
  - there is no rules anymore
  - you have covered all the rules array without finding a match (without passing by (2) for this loop). In that case, it means some rules are not used.
</pre>
<p>There is a known limitation of the algorithm I intend to fix soon:<br />
Once we found matching elements for a rule, we append the template in these elements once, and we remove the rule. It&#8217;s a simple way to avoid recursion. But this approach doesn&#8217;t work if a selector can potentially matches elements defined in different rules. <em>I know how to fix this but it&#8217;s not yet implemented.</em></p>
<h2>What&#8217;s next?</h2>
<p>We are working hard for the next version (v2) of <a href="http://sliderjs.org/">SliderJS</a> by trying to make a revolutionary IDE platform for SliderJS. It requires a modulification of every components of SliderJS, we try to keep things simple (no external library required, the core system is only 4k sized). You will have more information soon!</p>
<p>This templating system should benefits of this work.</p>
<p>Keep in touch!</p>
 <p><a href="http://blog.greweb.fr/?flattrss_redirect&amp;id=987&amp;md5=41a80597dea5f92e824bf48ee150473d" title="Flattr" target="_blank"><img src="http://blog.greweb.fr/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.greweb.fr/2012/02/css-selector-based-templating-example-with-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<atom:link rel="payment" href="https://flattr.com/submit/auto?user_id=greweb&amp;popout=1&amp;url=http%3A%2F%2Fblog.greweb.fr%2F2012%2F02%2Fcss-selector-based-templating-example-with-javascript%2F&amp;language=sq_AL&amp;category=text&amp;title=CSS-selector-based+templating+system+for+scalable+JavaScript+applications&amp;description=In+this+article%2C+we+will+focus+on+the+power+of+CSS+as+a+descriptive+language%2C+current+template+system+approach+and+their+problems+with+modularity+and+extensibility%2C+and+try+to+mix...&amp;tags=css%2Cjavascript%2Cscalable%2Ctemplating%2Cblog" type="text/html" />
	</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using apc

Served from: blog.greweb.fr @ 2012-05-18 13:45:07 -->
