Permalink
Browse files

More more more. Another article, two more demos. :)

  • Loading branch information...
1 parent 7272301 commit 15261b8cd9218f33a604115478a3a28c33590038 @ialexi ialexi committed Apr 17, 2010
View
2 Buildfile
@@ -4,5 +4,5 @@
# ===========================================================================
# Add initial buildfile information here
-config :all, :required => [:sproutcore, "sproutcore/animation"], :theme=>:pig, :url_prefix => "/static/hedwig/",
+config :all, :required => [:sproutcore, "sproutcore/animation", "sproutcore/forms"], :theme=>:pig, :url_prefix => "/static/hedwig/",
:html5_manifest=> true
View
2 apps/hedwig/resources/guide/touch.json
@@ -1 +1 @@
-{"title":"Touch Application Guide","sections":[{"title":"Introduction","articles":[{"content":"<h1>A Brief Touch</h1>\n\n<p>It is very possible to build <em>awesome</em> touch-enabled applications in SproutCore.</p>\n\n<p>But, what makes an awesome touch-enabled application? Sure, it must accept touches,\nbut with SproutCore's (constantly growing) touch support, this is now pretty easy:\nmany existing interfaces, if built with newer SproutCore varieties, will function fine (or mostly fine),\non both larger-screened touch devices (such as iPad) and the traditional desktop environment.</p>\n\n<p>But there are many differences between desktop and touch platforms:</p>\n\n<ul>\n<li><strong>Precision.</strong> Touches are less precise than clicks. To compensate, controls should be larger.</li>\n<li><strong>Performance.</strong> Touch-based devices tend to be slow (for now). To get around this just takes \nsome elbow grease: there are many techniques to speed things up... many of which SproutCore will\nhandle for you.</li>\n<li><strong>Animation.</strong> Lack of animation looks okay on desktop (even if animation is cool)... but on\ntouch devices, non-animated interfaces look strange: touch is so much more realistic than mouse,\nbut sudden changes without transitions are not realistic at all.</li>\n<li><strong>Coolness.</strong> Touch-based interfaces are cool. That is all.</li>\n</ul>\n\n<p>In this guide, we go over each of these&emdash;except for the last, which is rather vague; you'll have to figure out\nyour own meaning of \"coolness\".</p>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"A Brief Touch","any":"metadata","goes":"Here","damn":"gruber","this":"is still eye-readable","and":"He is wrong about touch apps."},{"content":"<h1>Touch Events</h1>\n\n<p>SproutCore's touch events have a few great features:</p>\n\n<ul>\n<li>Multiple views can receive touches simultaneously.</li>\n<li>A single view can receive multiple touches.</li>\n<li>A view can capture touches before allowing them to pass through to children.</li>\n<li>Child views can release touches back to parent views that originally captured them.</li>\n</ul>\n\n<p>We won't get into the last two in this article&emdash;they're quite sophisticated!</p>\n\n<h1>Simple Single-Touch Handling</h1>\n\n<p>You may be familiar with this SC.View method signature if you are familiar with SproutCore:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>)\n</code></pre>\n\n<p>With <code class='syntax js'><span class=\"variable\">mouseDown</span></code>, you can decide whether or not to accept the mouse event by returning either\n<code class='syntax js'><span class=\"class\">YES</span></code> or <code class='syntax js'><span class=\"class\">NO</span></code>.</p>\n\n<p>Touch events are similar, but work a bit differently:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>)\n</code></pre>\n\n<p>Instead of being passed a raw event, <code class='syntax js'><span class=\"variable\">touchStart</span></code> is passed an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code> object.\nIf you return YES from touchStart, your view will \"own\" the touch\u2014in SproutCore terms, your\nview will be the <em>touch responder</em>. For more information about what this entails, see\nthe \"Internals\" article. Your view will own the touch until the touch ends.</p>\n\n<p><code class='syntax js'><span class=\"variable\">touchStart</span></code> will be called once for every touch that touches the view.</p>\n\n<p><strong>Note:</strong> By default, views only receive <code class='syntax js'><span class=\"variable\">touchStart</span></code> and touchEnd for a single touch. This is\na feature intended to make it easier to handle such cases, very similar to Cocoa Touch's <code class='syntax js'><span class=\"variable\">acceptsMultitouch</span></code>\nproperty\u2014actually, SC.View uses the same property name! See the \"Multitouch\" article.</p>\n\n<h2>Anatomy of an SC.Touch</h2>\n\n<p>SC.Touch represents the touch from the time the user puts their finger on the screen until the time they lift it.</p>\n\n<p>The touch object acts like an event object in many ways. It has many other useful things, as well:</p>\n\n<ul>\n<li><code class='syntax js'><span class=\"variable\">pageX</span></code> and <code class='syntax js'><span class=\"variable\">pageY</span></code> for the touch</li>\n<li><code class='syntax js'><span class=\"variable\">event</span></code>: if in an event cycle, this contains the event. Otherwise, it is <code class='syntax js'><span class=\"variable\">undefined</span></code>. \nYou will probably never need to access this.</li>\n<li><code class='syntax js'><span class=\"variable\">preventDefault</span></code>: if the touch is connected with an event, this calls <code class='syntax js'><span class=\"variable\">preventDefault</span>()</code> on the event.</li>\n<li><code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"variable\">view</span>)</code>: when supplied a view, will find all touches that the view is the\ntouch responder for. It is a CoreSet; to get an array, call <code class='syntax js'>.<span class=\"variable\">toArray</span></code> on the result.</li>\n<li><code class='syntax js'><span class=\"variable\">averagedTouchesForView</span>(<span class=\"variable\">view</span>)</code>: When supplied a view, averages all the touches on that view,\nreturning both an average position and an average distance from that position.</li>\n</ul>\n\n<p><strong>Note:</strong> If you call <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code> from <code class='syntax js'><span class=\"variable\">touchStart</span></code>, the touch supplied will not be in the set\nreturned by <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>: you don't own the touch until you return YES.</p>\n\n<h2>touchEnd</h2>\n\n<p>Knowing when the touch starts is not very useful. At the very least, you will likely want to know when the touch\nends as well.</p>\n\n<p>It is quite simple:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>)\n</code></pre>\n\n<p>It works exactly like <code class='syntax js'><span class=\"variable\">touchStart</span></code>. The touch will no longer be in the set of touches for the view,\nso if you call <code class='syntax js'><span class=\"variable\">touch</span>.<span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>, you'll only receive any other active touches. If your\nview does not accept multitouch, then the set is guaranteed to have no touches in it\u2014you only receive\n<code class='syntax js'><span class=\"variable\">touchEnd</span></code> for the last touch that ends.</p>\n\n<h2>Tracking Touches</h2>\n\n<p>Tracking touch movement is simple:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>)\n</code></pre>\n\n<p>The <code class='syntax js'><span class=\"variable\">touches</span></code> argument is the set of touches on the view\u2014the same set you get by calling <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>.\nThis will have <em>all</em> touches, regardless of whether or not your view accepts multitouch.</p>\n\n<p>If your view does <em>not</em> accept multitouch, then it is even simpler:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">x</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">pageX</span>;\n<span class=\"variable\">y</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">pageY</span>;\n</code></pre>\n\n<h2>Tip: Cross-Platform-iness</h2>\n\n<p>Did you realize that, assuming you don't use the set of view touches or other touch-specific API,\nyou can do this:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n},\n\n<span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n},\n\n<span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n}\n</code></pre>\n\n<p>Of course, you can also redirect touch events to mouse events, but that is not as fun.</p>\n\n<h2>Putting it All Together</h2>\n\n<p>Here is a very simple demo that uses the methods described above to allow the user to move two views\naround the screen:</p>\n\n<p><a href='touch-demo.js' class='demo'>touch-demo.js</a></p>","errors":[],"demos":{"touch-demo.js":{"ex":"var Dot = SC.View.extend({\n touchStart: function(touch) {\n var f = this.get(\"frame\");\n this._touch = {\n start: { x: touch.pageX, y: touch.pageY },\n ourStart: { x: f.x, y: f.y, width: f.width, height: f.height }\n };\n return YES; // or we won't get touchesDragged\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n this.set(\"layout\", { \n left: t.ourStart.x + evt.pageX - t.start.x,\n top: t.ourStart.y + evt.pageY - t.start.y,\n width: t.ourStart.width,\n height: t.ourStart.height\n });\n },\n \n touchEnd: function() {\n // actually, we don't need to do anything here...\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"dot1 dot2\".w(),\n dot1: Dot.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 100, height: 100 }\n }),\n dot2: Dot.design({\n backgroundColor: \"blue\",\n layout: { right: 10, bottom: 10, width: 100, height: 100 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">Dot</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">f</span> = <span class=\"this\">this</span>.<span class=\"variable\">get</span>(<span class=\"string\">&quot;frame&quot;</span>);\n <span class=\"this\">this</span>.<span class=\"variable\">_touch</span> = {\n <span class=\"variable\">start</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">touch</span>.<span class=\"variable\">pageX</span>, <span class=\"variable\">y</span>: <span class=\"variable\">touch</span>.<span class=\"variable\">pageY</span> },\n <span class=\"variable\">ourStart</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">f</span>.<span class=\"variable\">x</span>, <span class=\"variable\">y</span>: <span class=\"variable\">f</span>.<span class=\"variable\">y</span>, <span class=\"variable\">width</span>: <span class=\"variable\">f</span>.<span class=\"variable\">width</span>, <span class=\"variable\">height</span>: <span class=\"variable\">f</span>.<span class=\"variable\">height</span> }\n };\n <span class=\"keyword\">return</span> <span class=\"class\">YES</span>; <span class=\"comment\">// or we won't get touchesDragged</span>\n },\n \n <span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">t</span> = <span class=\"this\">this</span>.<span class=\"variable\">_touch</span>;\n <span class=\"this\">this</span>.<span class=\"variable\">set</span>(<span class=\"string\">&quot;layout&quot;</span>, { \n <span class=\"variable\">left</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">x</span> + <span class=\"variable\">evt</span>.<span class=\"variable\">pageX</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">x</span>,\n <span class=\"variable\">top</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">y</span> + <span class=\"variable\">evt</span>.<span class=\"variable\">pageY</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">y</span>,\n <span class=\"variable\">width</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">width</span>,\n <span class=\"variable\">height</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">height</span>\n });\n },\n \n <span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>() {\n <span class=\"comment\">// actually, we don't need to do anything here...</span>\n },\n \n <span class=\"comment\">// and now, redirect mouse events :)</span>\n <span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n }\n});\n<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;dot1 dot2&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">dot1</span>: <span class=\"class\">Dot</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;red&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">left</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">top</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">100</span> }\n }),\n <span class=\"variable\">dot2</span>: <span class=\"class\">Dot</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;blue&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">right</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">bottom</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">100</span> }\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var Dot = SC.View.extend({\n touchStart: function(touch) {\n var f = this.get(\"frame\");\n this._touch = {\n start: { x: touch.pageX, y: touch.pageY },\n ourStart: { x: f.x, y: f.y, width: f.width, height: f.height }\n };\n return YES; // or we won't get touchesDragged\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n this.set(\"layout\", { \n left: t.ourStart.x + evt.pageX - t.start.x,\n top: t.ourStart.y + evt.pageY - t.start.y,\n width: t.ourStart.width,\n height: t.ourStart.height\n });\n },\n \n touchEnd: function() {\n // actually, we don't need to do anything here...\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"dot1 dot2\".w(),\n dot1: Dot.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 100, height: 100 }\n }),\n dot2: Dot.design({\n backgroundColor: \"blue\",\n layout: { right: 10, bottom: 10, width: 100, height: 100 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Touch Events"},{"content":"<h1>Multitouch</h1>\n\n<p>Handling single touches is pretty easy&emdash;not that much different from handling\nmouse events. But what about multiple touches?</p>\n\n<h2>Accepting Multiple Touches</h2>\n\n<p>First, you have to tell your view that you do, indeed want to receive multiple\ntouches. By default, views only receive single touches. This is because is easier \nto think in a single-touch model, and most controls only need to track a single touch.</p>\n\n<p>To accept multiple touches, just set the view's <code class='syntax js'><span class=\"variable\">acceptsMultitouch</span></code> property to\n<code class='syntax js'><span class=\"class\">YES</span></code>.</p>\n\n<pre><code class='syntax js'><span class=\"variable\">view</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">acceptsMultitouch</span>: <span class=\"class\">YES</span>\n});\n</code></pre>\n\n<h2>Processing the Individual Touches</h2>\n\n<p>Even without the supplied helper function, processing individual touches is relatively\nsimple:</p>\n\n<ul>\n<li>You get a separate <code class='syntax js'><span class=\"variable\">touchStart</span></code> for each individual touch.</li>\n<li>You get a separate <code class='syntax js'><span class=\"variable\">touchEnd</span></code> for each individual touch.</li>\n<li>You get one <code class='syntax js'><span class=\"variable\">touchesDragged</span></code> each event cycle for all of your touches put together.</li>\n</ul>\n\n<p>So, detecting individual touches starting and ending is simple. Detecting those touches\nmoving is not quite as simple, but still relatively easy.</p>\n\n<p>Remember how <code class='syntax js'><span class=\"variable\">touchesDragged</span></code> works:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>)\n</code></pre>\n\n<p><code class='syntax js'><span class=\"variable\">touches</span></code> is an SC.CoreSet of SC.Touch objects. What can you do with a CoreSet? \nYou can do a couple of things:</p>\n\n<ul>\n<li>Turn it into an array and do whatever.</li>\n<li>Call .forEach to iterate.</li>\n</ul>\n\n<p>But you don't have to use the touches set at all. The <code class='syntax js'><span class=\"variable\">evt</span></code> has some useful properties and methods,\ntoo:</p>\n\n<ul>\n<li>pageX/pageY: the position of the first touch.</li>\n<li>averagedTouchesForView: a method which returns the averaged touch position\nand the average distance of the touches from that position.</li>\n</ul>\n\n<p><code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">ScrollView</span></code>, for instance, makes heavy use of <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code>, and never\ndirectly touches the <code class='syntax js'><span class=\"variable\">touches</span></code> set.</p>\n\n<h2>Averaging Touches</h2>\n\n<p>It is often <em>very</em> useful to average the touches. </p>\n\n<p><code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code> returns an object with four properties:</p>\n\n<ul>\n<li><strong><code class='syntax js'><span class=\"variable\">x</span></code></strong>: The average X position of the touch.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">y</span></code></strong>: The average Y position of the touch.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">d</span></code></strong>: average distance of the all touches from the average x/y position.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">touchCount</span></code></strong> The number of touches averaged.</li>\n</ul>\n\n<p>You can call <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code> on two separate objects: an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Event</span></code> object,\nor an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code> object.</p>\n\n<p>The two work identically but for one important difference: when you call it on <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code>,\nyou <em>have the option</em> of telling the touch to add itself to the averaged set. Doing so makes no sense\nin most cases: the touch would just be counted twice! But what about <code class='syntax js'><span class=\"variable\">touchStart</span></code>?</p>\n\n<p>Recall that during <code class='syntax js'><span class=\"variable\">touchStart</span></code>, the view does not yet own the touch. So, <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code>\nwould not, by default count it.</p>\n\n<pre><code class='syntax js'><span class=\"comment\">// on an event:</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n\n<span class=\"comment\">// on a touch</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n\n<span class=\"comment\">// on a touch, counting the touch itself</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>, <span class=\"class\">YES</span>);\n</code></pre>\n\n<h2>Thinking it Over</h2>\n\n<p>How might you use all of these to produce a good result?</p>\n\n<p>Let's take a simple example: moving and resizing something:</p>\n\n<p><a href='multitouch.js' class='demo'>multitouch.js</a></p>","errors":[],"demos":{"multitouch.js":{"ex":"var Box = SC.View.extend({\n _scale: 1,\n _translateX: 0,\n _translateY: 0,\n acceptsMultitouch: YES,\n touchStart: function(touch) {\n this.recomputeTouchStatus(touch, YES);\n return YES;\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n var avg = evt.averagedTouchesForView(this);\n \n // translation is easy:\n this._translateX = t.ourStart.x + avg.x - t.start.x;\n this._translateY = t.ourStart.y + avg.y - t.start.y;\n \n // mathematically speaking, scale *= the end distance / the start distance\n if (t.start.d > 1) { // but prevent divide-by-0\n this._scale = t.ourStart.scale * (avg.d / t.start.d);\n }\n \n // reposition\n this._reposition();\n },\n \n touchEnd: function(touch) {\n this.recomputeTouchStatus(touch, NO);\n },\n \n /**\n With this, we recompute our touch status--updating the start positioning and scale.\n */\n recomputeTouchStatus: function(touch, considerTouch) {\n var avg = touch.averagedTouchesForView(this, considerTouch);\n this._touch = {\n start: { x: avg.x, y: avg.y, d: avg.d },\n ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }\n };\n },\n \n /**\n Repositions the view.\n */\n _reposition: function() {\n this.get(\"layer\").style.webkitTransform = \n \"translate3d(\" + this._translateX + \"px,\" + this._translateY + \"px, 0px) \" +\n \"scale3d(\" + this._scale + \",\" + this._scale + \",1)\";\n console.error(this._translateX + \" \" + this._translateY + \" \" + this._scale);\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"box\".w(),\n box: Box.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 200, height: 200 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">Box</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">_scale</span>: <span class=\"number integer\">1</span>,\n <span class=\"variable\">_translateX</span>: <span class=\"number integer\">0</span>,\n <span class=\"variable\">_translateY</span>: <span class=\"number integer\">0</span>,\n <span class=\"variable\">acceptsMultitouch</span>: <span class=\"class\">YES</span>,\n <span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">recomputeTouchStatus</span>(<span class=\"variable\">touch</span>, <span class=\"class\">YES</span>);\n <span class=\"keyword\">return</span> <span class=\"class\">YES</span>;\n },\n \n <span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">t</span> = <span class=\"this\">this</span>.<span class=\"variable\">_touch</span>;\n <span class=\"keyword\">var</span> <span class=\"variable\">avg</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n \n <span class=\"comment\">// translation is easy:</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">x</span> + <span class=\"variable\">avg</span>.<span class=\"variable\">x</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">x</span>;\n <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">y</span> + <span class=\"variable\">avg</span>.<span class=\"variable\">y</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">y</span>;\n \n <span class=\"comment\">// mathematically speaking, scale *= the end distance / the start distance</span>\n <span class=\"keyword\">if</span> (<span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">d</span> &gt; <span class=\"number integer\">1</span>) { <span class=\"comment\">// but prevent divide-by-0</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">scale</span> * (<span class=\"variable\">avg</span>.<span class=\"variable\">d</span> / <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">d</span>);\n }\n \n <span class=\"comment\">// reposition</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_reposition</span>();\n },\n \n <span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">recomputeTouchStatus</span>(<span class=\"variable\">touch</span>, <span class=\"class\">NO</span>);\n },\n \n <span class=\"multiline comment\">/**\n With this, we recompute our touch status--updating the start positioning and scale.\n */</span>\n <span class=\"variable\">recomputeTouchStatus</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>, <span class=\"variable\">considerTouch</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">avg</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>, <span class=\"variable\">considerTouch</span>);\n <span class=\"this\">this</span>.<span class=\"variable\">_touch</span> = {\n <span class=\"variable\">start</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">x</span>, <span class=\"variable\">y</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">y</span>, <span class=\"variable\">d</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">d</span> },\n <span class=\"variable\">ourStart</span>: { <span class=\"variable\">x</span>: <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span>, <span class=\"variable\">y</span>: <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span>, <span class=\"variable\">scale</span>: <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> }\n };\n },\n \n <span class=\"multiline comment\">/**\n Repositions the view.\n */</span>\n <span class=\"variable\">_reposition</span>: <span class=\"keyword\">function</span>() {\n <span class=\"this\">this</span>.<span class=\"variable\">get</span>(<span class=\"string\">&quot;layer&quot;</span>).<span class=\"variable\">style</span>.<span class=\"variable\">webkitTransform</span> = \n <span class=\"string\">&quot;translate3d(&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> + <span class=\"string\">&quot;px,&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> + <span class=\"string\">&quot;px, 0px) &quot;</span> +\n <span class=\"string\">&quot;scale3d(&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> + <span class=\"string\">&quot;,&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> + <span class=\"string\">&quot;,1)&quot;</span>;\n <span class=\"variable\">console</span>.<span class=\"variable\">error</span>(<span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> + <span class=\"string\">&quot; &quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> + <span class=\"string\">&quot; &quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span>);\n },\n \n <span class=\"comment\">// and now, redirect mouse events :)</span>\n <span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n }\n});\n<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;box&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">box</span>: <span class=\"class\">Box</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;red&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">left</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">top</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">200</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">200</span> }\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var Box = SC.View.extend({\n _scale: 1,\n _translateX: 0,\n _translateY: 0,\n acceptsMultitouch: YES,\n touchStart: function(touch) {\n this.recomputeTouchStatus(touch, YES);\n return YES;\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n var avg = evt.averagedTouchesForView(this);\n \n // translation is easy:\n this._translateX = t.ourStart.x + avg.x - t.start.x;\n this._translateY = t.ourStart.y + avg.y - t.start.y;\n \n // mathematically speaking, scale *= the end distance / the start distance\n if (t.start.d > 1) { // but prevent divide-by-0\n this._scale = t.ourStart.scale * (avg.d / t.start.d);\n }\n \n // reposition\n this._reposition();\n },\n \n touchEnd: function(touch) {\n this.recomputeTouchStatus(touch, NO);\n },\n \n /**\n With this, we recompute our touch status--updating the start positioning and scale.\n */\n recomputeTouchStatus: function(touch, considerTouch) {\n var avg = touch.averagedTouchesForView(this, considerTouch);\n this._touch = {\n start: { x: avg.x, y: avg.y, d: avg.d },\n ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }\n };\n },\n \n /**\n Repositions the view.\n */\n _reposition: function() {\n this.get(\"layer\").style.webkitTransform = \n \"translate3d(\" + this._translateX + \"px,\" + this._translateY + \"px, 0px) \" +\n \"scale3d(\" + this._scale + \",\" + this._scale + \",1)\";\n console.error(this._translateX + \" \" + this._translateY + \" \" + this._scale);\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"box\".w(),\n box: Box.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 200, height: 200 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Multitouch"}]},{"title":"Built-In Support","articles":[{"content":"<h1>ButtonView Touch Support</h1>","errors":[],"demos":{},"articleDirectory":"articles/controls/button/","outputDirectory":"build/","title":"ButtonView Touch Support"},{"content":"<h1>ScrollView Touch Support</h1>","errors":[],"demos":{},"articleDirectory":"articles/controls/scroll/","outputDirectory":"build/","title":"ScrollView Touch Support"}]},{"title":"Advanced Concepts","articles":[{"content":"<h1>Capturing</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Capturing"},{"content":"<h1>Releasing</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Releasing"}]}],"file":"build/guides/touch"}
+{"title":"Touch Application Guide","sections":[{"title":"Introduction","articles":[{"content":"<h1>A Brief Touch</h1>\n\n<p>It is very possible to build <em>awesome</em> touch-enabled applications in SproutCore.</p>\n\n<p>But, what makes an awesome touch-enabled application? Sure, it must accept touches,\nbut with SproutCore's (constantly growing) touch support, this is now pretty easy:\nmany existing interfaces, if built with newer SproutCore varieties, will function fine (or mostly fine),\non both larger-screened touch devices (such as iPad) and the traditional desktop environment.</p>\n\n<p>But there are many differences between desktop and touch platforms:</p>\n\n<ul>\n<li><strong>Precision.</strong> Touches are less precise than clicks. To compensate, controls should be larger.</li>\n<li><strong>Performance.</strong> Touch-based devices tend to be slow (for now). To get around this just takes \nsome elbow grease: there are many techniques to speed things up... many of which SproutCore will\nhandle for you.</li>\n<li><strong>Animation.</strong> Lack of animation looks okay on desktop (even if animation is cool)... but on\ntouch devices, non-animated interfaces look strange: touch is so much more realistic than mouse,\nbut sudden changes without transitions are not realistic at all.</li>\n<li><strong>Coolness.</strong> Touch-based interfaces are cool. That is all.</li>\n</ul>\n\n<p>In this guide, we go over each of these&emdash;except for the last, which is rather vague; you'll have to figure out\nyour own meaning of \"coolness\".</p>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"A Brief Touch","any":"metadata","goes":"Here","damn":"gruber","this":"is still eye-readable","and":"He is wrong about touch apps."},{"content":"<h1>Touch Events</h1>\n\n<p>SproutCore's touch events have a few great features:</p>\n\n<ul>\n<li>Multiple views can receive touches simultaneously.</li>\n<li>A single view can receive multiple touches.</li>\n<li>A view can capture touches before allowing them to pass through to children.</li>\n<li>Child views can release touches back to parent views that originally captured them.</li>\n</ul>\n\n<p>We won't get into the last two in this article&emdash;they're quite sophisticated!</p>\n\n<h1>Simple Single-Touch Handling</h1>\n\n<p>You may be familiar with this SC.View method signature if you are familiar with SproutCore:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>)\n</code></pre>\n\n<p>With <code class='syntax js'><span class=\"variable\">mouseDown</span></code>, you can decide whether or not to accept the mouse event by returning either\n<code class='syntax js'><span class=\"class\">YES</span></code> or <code class='syntax js'><span class=\"class\">NO</span></code>.</p>\n\n<p>Touch events are similar, but work a bit differently:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>)\n</code></pre>\n\n<p>Instead of being passed a raw event, <code class='syntax js'><span class=\"variable\">touchStart</span></code> is passed an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code> object.\nIf you return YES from touchStart, your view will \"own\" the touch\u2014in SproutCore terms, your\nview will be the <em>touch responder</em>. For more information about what this entails, see\nthe \"Internals\" article. Your view will own the touch until the touch ends.</p>\n\n<p><code class='syntax js'><span class=\"variable\">touchStart</span></code> will be called once for every touch that touches the view.</p>\n\n<p><strong>Note:</strong> By default, views only receive <code class='syntax js'><span class=\"variable\">touchStart</span></code> and touchEnd for a single touch. This is\na feature intended to make it easier to handle such cases, very similar to Cocoa Touch's <code class='syntax js'><span class=\"variable\">acceptsMultitouch</span></code>\nproperty\u2014actually, SC.View uses the same property name! See the \"Multitouch\" article.</p>\n\n<h2>Anatomy of an SC.Touch</h2>\n\n<p>SC.Touch represents the touch from the time the user puts their finger on the screen until the time they lift it.</p>\n\n<p>The touch object acts like an event object in many ways. It has many other useful things, as well:</p>\n\n<ul>\n<li><code class='syntax js'><span class=\"variable\">pageX</span></code> and <code class='syntax js'><span class=\"variable\">pageY</span></code> for the touch</li>\n<li><code class='syntax js'><span class=\"variable\">event</span></code>: if in an event cycle, this contains the event. Otherwise, it is <code class='syntax js'><span class=\"variable\">undefined</span></code>. \nYou will probably never need to access this.</li>\n<li><code class='syntax js'><span class=\"variable\">preventDefault</span></code>: if the touch is connected with an event, this calls <code class='syntax js'><span class=\"variable\">preventDefault</span>()</code> on the event.</li>\n<li><code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"variable\">view</span>)</code>: when supplied a view, will find all touches that the view is the\ntouch responder for. It is a CoreSet; to get an array, call <code class='syntax js'>.<span class=\"variable\">toArray</span></code> on the result.</li>\n<li><code class='syntax js'><span class=\"variable\">averagedTouchesForView</span>(<span class=\"variable\">view</span>)</code>: When supplied a view, averages all the touches on that view,\nreturning both an average position and an average distance from that position.</li>\n</ul>\n\n<p><strong>Note:</strong> If you call <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code> from <code class='syntax js'><span class=\"variable\">touchStart</span></code>, the touch supplied will not be in the set\nreturned by <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>: you don't own the touch until you return YES.</p>\n\n<h2>touchEnd</h2>\n\n<p>Knowing when the touch starts is not very useful. At the very least, you will likely want to know when the touch\nends as well.</p>\n\n<p>It is quite simple:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>)\n</code></pre>\n\n<p>It works exactly like <code class='syntax js'><span class=\"variable\">touchStart</span></code>. The touch will no longer be in the set of touches for the view,\nso if you call <code class='syntax js'><span class=\"variable\">touch</span>.<span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>, you'll only receive any other active touches. If your\nview does not accept multitouch, then the set is guaranteed to have no touches in it\u2014you only receive\n<code class='syntax js'><span class=\"variable\">touchEnd</span></code> for the last touch that ends.</p>\n\n<h2>Tracking Touches</h2>\n\n<p>Tracking touch movement is simple:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>)\n</code></pre>\n\n<p>The <code class='syntax js'><span class=\"variable\">touches</span></code> argument is the set of touches on the view\u2014the same set you get by calling <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>.\nThis will have <em>all</em> touches, regardless of whether or not your view accepts multitouch.</p>\n\n<p>If your view does <em>not</em> accept multitouch, then it is even simpler:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">x</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">pageX</span>;\n<span class=\"variable\">y</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">pageY</span>;\n</code></pre>\n\n<h2>Tip: Cross-Platform-iness</h2>\n\n<p>Did you realize that, assuming you don't use the set of view touches or other touch-specific API,\nyou can do this:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n},\n\n<span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n},\n\n<span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n}\n</code></pre>\n\n<p>Of course, you can also redirect touch events to mouse events, but that is not as fun.</p>\n\n<h2>Putting it All Together</h2>\n\n<p>Here is a very simple demo that uses the methods described above to allow the user to move two views\naround the screen:</p>\n\n<p><a href='touch-demo.js' class='demo'>touch-demo.js</a></p>","errors":[],"demos":{"touch-demo.js":{"ex":"var Dot = SC.View.extend({\n touchStart: function(touch) {\n var f = this.get(\"frame\");\n this._touch = {\n start: { x: touch.pageX, y: touch.pageY },\n ourStart: { x: f.x, y: f.y, width: f.width, height: f.height }\n };\n return YES; // or we won't get touchesDragged\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n this.set(\"layout\", { \n left: t.ourStart.x + evt.pageX - t.start.x,\n top: t.ourStart.y + evt.pageY - t.start.y,\n width: t.ourStart.width,\n height: t.ourStart.height\n });\n },\n \n touchEnd: function() {\n // actually, we don't need to do anything here...\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"dot1 dot2\".w(),\n dot1: Dot.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 100, height: 100 }\n }),\n dot2: Dot.design({\n backgroundColor: \"blue\",\n layout: { right: 10, bottom: 10, width: 100, height: 100 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">Dot</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">f</span> = <span class=\"this\">this</span>.<span class=\"variable\">get</span>(<span class=\"string\">&quot;frame&quot;</span>);\n <span class=\"this\">this</span>.<span class=\"variable\">_touch</span> = {\n <span class=\"variable\">start</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">touch</span>.<span class=\"variable\">pageX</span>, <span class=\"variable\">y</span>: <span class=\"variable\">touch</span>.<span class=\"variable\">pageY</span> },\n <span class=\"variable\">ourStart</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">f</span>.<span class=\"variable\">x</span>, <span class=\"variable\">y</span>: <span class=\"variable\">f</span>.<span class=\"variable\">y</span>, <span class=\"variable\">width</span>: <span class=\"variable\">f</span>.<span class=\"variable\">width</span>, <span class=\"variable\">height</span>: <span class=\"variable\">f</span>.<span class=\"variable\">height</span> }\n };\n <span class=\"keyword\">return</span> <span class=\"class\">YES</span>; <span class=\"comment\">// or we won't get touchesDragged</span>\n },\n \n <span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">t</span> = <span class=\"this\">this</span>.<span class=\"variable\">_touch</span>;\n <span class=\"this\">this</span>.<span class=\"variable\">set</span>(<span class=\"string\">&quot;layout&quot;</span>, { \n <span class=\"variable\">left</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">x</span> + <span class=\"variable\">evt</span>.<span class=\"variable\">pageX</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">x</span>,\n <span class=\"variable\">top</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">y</span> + <span class=\"variable\">evt</span>.<span class=\"variable\">pageY</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">y</span>,\n <span class=\"variable\">width</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">width</span>,\n <span class=\"variable\">height</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">height</span>\n });\n },\n \n <span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>() {\n <span class=\"comment\">// actually, we don't need to do anything here...</span>\n },\n \n <span class=\"comment\">// and now, redirect mouse events :)</span>\n <span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n }\n});\n<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;dot1 dot2&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">dot1</span>: <span class=\"class\">Dot</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;red&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">left</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">top</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">100</span> }\n }),\n <span class=\"variable\">dot2</span>: <span class=\"class\">Dot</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;blue&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">right</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">bottom</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">100</span> }\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var Dot = SC.View.extend({\n touchStart: function(touch) {\n var f = this.get(\"frame\");\n this._touch = {\n start: { x: touch.pageX, y: touch.pageY },\n ourStart: { x: f.x, y: f.y, width: f.width, height: f.height }\n };\n return YES; // or we won't get touchesDragged\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n this.set(\"layout\", { \n left: t.ourStart.x + evt.pageX - t.start.x,\n top: t.ourStart.y + evt.pageY - t.start.y,\n width: t.ourStart.width,\n height: t.ourStart.height\n });\n },\n \n touchEnd: function() {\n // actually, we don't need to do anything here...\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"dot1 dot2\".w(),\n dot1: Dot.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 100, height: 100 }\n }),\n dot2: Dot.design({\n backgroundColor: \"blue\",\n layout: { right: 10, bottom: 10, width: 100, height: 100 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Touch Events"},{"content":"<h1>Multitouch</h1>\n\n<p>Handling single touches is pretty easy&emdash;not that much different from handling\nmouse events. But what about multiple touches?</p>\n\n<h2>Accepting Multiple Touches</h2>\n\n<p>First, you have to tell your view that you do, indeed want to receive multiple\ntouches. By default, views only receive single touches. This is because is easier \nto think in a single-touch model, and most controls only need to track a single touch.</p>\n\n<p>To accept multiple touches, just set the view's <code class='syntax js'><span class=\"variable\">acceptsMultitouch</span></code> property to\n<code class='syntax js'><span class=\"class\">YES</span></code>.</p>\n\n<pre><code class='syntax js'><span class=\"variable\">view</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">acceptsMultitouch</span>: <span class=\"class\">YES</span>\n});\n</code></pre>\n\n<h2>Processing the Individual Touches</h2>\n\n<p>Even without the supplied helper function, processing individual touches is relatively\nsimple:</p>\n\n<ul>\n<li>You get a separate <code class='syntax js'><span class=\"variable\">touchStart</span></code> for each individual touch.</li>\n<li>You get a separate <code class='syntax js'><span class=\"variable\">touchEnd</span></code> for each individual touch.</li>\n<li>You get one <code class='syntax js'><span class=\"variable\">touchesDragged</span></code> each event cycle for all of your touches put together.</li>\n</ul>\n\n<p>So, detecting individual touches starting and ending is simple. Detecting those touches\nmoving is not quite as simple, but still relatively easy.</p>\n\n<p>Remember how <code class='syntax js'><span class=\"variable\">touchesDragged</span></code> works:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>)\n</code></pre>\n\n<p><code class='syntax js'><span class=\"variable\">touches</span></code> is an SC.CoreSet of SC.Touch objects. What can you do with a CoreSet? \nYou can do a couple of things:</p>\n\n<ul>\n<li>Turn it into an array and do whatever.</li>\n<li>Call .forEach to iterate.</li>\n</ul>\n\n<p>But you don't have to use the touches set at all. The <code class='syntax js'><span class=\"variable\">evt</span></code> has some useful properties and methods,\ntoo:</p>\n\n<ul>\n<li>pageX/pageY: the position of the first touch.</li>\n<li>averagedTouchesForView: a method which returns the averaged touch position\nand the average distance of the touches from that position.</li>\n</ul>\n\n<p><code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">ScrollView</span></code>, for instance, makes heavy use of <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code>, and never\ndirectly touches the <code class='syntax js'><span class=\"variable\">touches</span></code> set.</p>\n\n<h2>Averaging Touches</h2>\n\n<p>It is often <em>very</em> useful to average the touches. </p>\n\n<p><code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code> returns an object with four properties:</p>\n\n<ul>\n<li><strong><code class='syntax js'><span class=\"variable\">x</span></code></strong>: The average X position of the touch.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">y</span></code></strong>: The average Y position of the touch.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">d</span></code></strong>: average distance of the all touches from the average x/y position.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">touchCount</span></code></strong> The number of touches averaged.</li>\n</ul>\n\n<p>You can call <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code> on two separate objects: an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Event</span></code> object,\nor an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code> object.</p>\n\n<p>The two work identically but for one important difference: when you call it on <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code>,\nyou <em>have the option</em> of telling the touch to add itself to the averaged set. Doing so makes no sense\nin most cases: the touch would just be counted twice! But what about <code class='syntax js'><span class=\"variable\">touchStart</span></code>?</p>\n\n<p>Recall that during <code class='syntax js'><span class=\"variable\">touchStart</span></code>, the view does not yet own the touch. So, <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code>\nwould not, by default count it.</p>\n\n<pre><code class='syntax js'><span class=\"comment\">// on an event:</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n\n<span class=\"comment\">// on a touch</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n\n<span class=\"comment\">// on a touch, counting the touch itself</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>, <span class=\"class\">YES</span>);\n</code></pre>\n\n<h2>Thinking it Over</h2>\n\n<p>How might you use all of these to produce a good result?</p>\n\n<p>Let's take a simple example: moving and resizing something:</p>\n\n<p><a href='multitouch.js' class='demo'>multitouch.js</a></p>","errors":[],"demos":{"multitouch.js":{"ex":"var Box = SC.View.extend({\n _scale: 1,\n _translateX: 0,\n _translateY: 0,\n acceptsMultitouch: YES,\n touchStart: function(touch) {\n this.recomputeTouchStatus(touch, YES);\n return YES;\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n var avg = evt.averagedTouchesForView(this);\n \n // translation is easy:\n this._translateX = t.ourStart.x + avg.x - t.start.x;\n this._translateY = t.ourStart.y + avg.y - t.start.y;\n \n // mathematically speaking, scale *= the end distance / the start distance\n if (t.start.d > 1) { // but prevent divide-by-0\n this._scale = t.ourStart.scale * (avg.d / t.start.d);\n }\n \n // reposition\n this._reposition();\n },\n \n touchEnd: function(touch) {\n this.recomputeTouchStatus(touch, NO);\n },\n \n /**\n With this, we recompute our touch status--updating the start positioning and scale.\n */\n recomputeTouchStatus: function(touch, considerTouch) {\n var avg = touch.averagedTouchesForView(this, considerTouch);\n this._touch = {\n start: { x: avg.x, y: avg.y, d: avg.d },\n ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }\n };\n },\n \n /**\n Repositions the view.\n */\n _reposition: function() {\n this.get(\"layer\").style.webkitTransform = \n \"translate3d(\" + this._translateX + \"px,\" + this._translateY + \"px, 0px) \" +\n \"scale3d(\" + this._scale + \",\" + this._scale + \",1)\";\n console.error(this._translateX + \" \" + this._translateY + \" \" + this._scale);\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"box\".w(),\n box: Box.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 200, height: 200 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">Box</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">_scale</span>: <span class=\"number integer\">1</span>,\n <span class=\"variable\">_translateX</span>: <span class=\"number integer\">0</span>,\n <span class=\"variable\">_translateY</span>: <span class=\"number integer\">0</span>,\n <span class=\"variable\">acceptsMultitouch</span>: <span class=\"class\">YES</span>,\n <span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">recomputeTouchStatus</span>(<span class=\"variable\">touch</span>, <span class=\"class\">YES</span>);\n <span class=\"keyword\">return</span> <span class=\"class\">YES</span>;\n },\n \n <span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">t</span> = <span class=\"this\">this</span>.<span class=\"variable\">_touch</span>;\n <span class=\"keyword\">var</span> <span class=\"variable\">avg</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n \n <span class=\"comment\">// translation is easy:</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">x</span> + <span class=\"variable\">avg</span>.<span class=\"variable\">x</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">x</span>;\n <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">y</span> + <span class=\"variable\">avg</span>.<span class=\"variable\">y</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">y</span>;\n \n <span class=\"comment\">// mathematically speaking, scale *= the end distance / the start distance</span>\n <span class=\"keyword\">if</span> (<span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">d</span> &gt; <span class=\"number integer\">1</span>) { <span class=\"comment\">// but prevent divide-by-0</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">scale</span> * (<span class=\"variable\">avg</span>.<span class=\"variable\">d</span> / <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">d</span>);\n }\n \n <span class=\"comment\">// reposition</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_reposition</span>();\n },\n \n <span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">recomputeTouchStatus</span>(<span class=\"variable\">touch</span>, <span class=\"class\">NO</span>);\n },\n \n <span class=\"multiline comment\">/**\n With this, we recompute our touch status--updating the start positioning and scale.\n */</span>\n <span class=\"variable\">recomputeTouchStatus</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>, <span class=\"variable\">considerTouch</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">avg</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>, <span class=\"variable\">considerTouch</span>);\n <span class=\"this\">this</span>.<span class=\"variable\">_touch</span> = {\n <span class=\"variable\">start</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">x</span>, <span class=\"variable\">y</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">y</span>, <span class=\"variable\">d</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">d</span> },\n <span class=\"variable\">ourStart</span>: { <span class=\"variable\">x</span>: <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span>, <span class=\"variable\">y</span>: <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span>, <span class=\"variable\">scale</span>: <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> }\n };\n },\n \n <span class=\"multiline comment\">/**\n Repositions the view.\n */</span>\n <span class=\"variable\">_reposition</span>: <span class=\"keyword\">function</span>() {\n <span class=\"this\">this</span>.<span class=\"variable\">get</span>(<span class=\"string\">&quot;layer&quot;</span>).<span class=\"variable\">style</span>.<span class=\"variable\">webkitTransform</span> = \n <span class=\"string\">&quot;translate3d(&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> + <span class=\"string\">&quot;px,&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> + <span class=\"string\">&quot;px, 0px) &quot;</span> +\n <span class=\"string\">&quot;scale3d(&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> + <span class=\"string\">&quot;,&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> + <span class=\"string\">&quot;,1)&quot;</span>;\n <span class=\"variable\">console</span>.<span class=\"variable\">error</span>(<span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> + <span class=\"string\">&quot; &quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> + <span class=\"string\">&quot; &quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span>);\n },\n \n <span class=\"comment\">// and now, redirect mouse events :)</span>\n <span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n }\n});\n<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;box&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">box</span>: <span class=\"class\">Box</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;red&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">left</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">top</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">200</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">200</span> }\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var Box = SC.View.extend({\n _scale: 1,\n _translateX: 0,\n _translateY: 0,\n acceptsMultitouch: YES,\n touchStart: function(touch) {\n this.recomputeTouchStatus(touch, YES);\n return YES;\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n var avg = evt.averagedTouchesForView(this);\n \n // translation is easy:\n this._translateX = t.ourStart.x + avg.x - t.start.x;\n this._translateY = t.ourStart.y + avg.y - t.start.y;\n \n // mathematically speaking, scale *= the end distance / the start distance\n if (t.start.d > 1) { // but prevent divide-by-0\n this._scale = t.ourStart.scale * (avg.d / t.start.d);\n }\n \n // reposition\n this._reposition();\n },\n \n touchEnd: function(touch) {\n this.recomputeTouchStatus(touch, NO);\n },\n \n /**\n With this, we recompute our touch status--updating the start positioning and scale.\n */\n recomputeTouchStatus: function(touch, considerTouch) {\n var avg = touch.averagedTouchesForView(this, considerTouch);\n this._touch = {\n start: { x: avg.x, y: avg.y, d: avg.d },\n ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }\n };\n },\n \n /**\n Repositions the view.\n */\n _reposition: function() {\n this.get(\"layer\").style.webkitTransform = \n \"translate3d(\" + this._translateX + \"px,\" + this._translateY + \"px, 0px) \" +\n \"scale3d(\" + this._scale + \",\" + this._scale + \",1)\";\n console.error(this._translateX + \" \" + this._translateY + \" \" + this._scale);\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"box\".w(),\n box: Box.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 200, height: 200 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Multitouch"}]},{"title":"Built-In Support","articles":[{"content":"<h1>ButtonView Touch Support</h1>\n\n<p>ButtonView currently supports only a single touch (any other touches will be ignored). \nThis is fine: why would you want to consider two touches in a button press?</p>\n\n<p>However, it does not simply relay the touches to <code class='syntax js'><span class=\"variable\">mouseDown</span></code> and <code class='syntax js'><span class=\"variable\">mouseUp</span></code>.</p>\n\n<p>Instead, it calculates the distance of the main touch (<code class='syntax js'><span class=\"variable\">evt</span></code>'s <code class='syntax js'><span class=\"variable\">pageX</span></code> and <code class='syntax js'><span class=\"variable\">pageY</span></code>)\nfrom the button itself. This makes it easier to for a user to press a button while, for instance,\nmoving their finger.</p>\n\n<p>This is all done for you automatically. Here's a simple demo:\n<a href='touch-button.js' class='demo'>touch-button.js</a></p>\n\n<h2>Ace 2.0</h2>\n\n<p>Ace 2.0 supports several button sizes. In addition, it is capable of <em>automatically picking</em>\na size based on the size of your control. And best of all, it <em>centers</em> the button image\nvertically in the space you allocate. This allows you to, for instance, make a button 44px\ntall, but have the image only be 30px.</p>\n\n<p>You may use these options for <code class='syntax js'><span class=\"variable\">controlSize</span></code>:</p>\n\n<ul>\n<li>SC.SMALL_CONTROL_SIZE. 18px.</li>\n<li>SC.REGULAR_CONTROL_SIZE. 24px.</li>\n<li>SC.HUGE_CONTROL_SIZE. 30px.</li>\n<li>SC.JUMBO_CONTROL_SIZE. 44px.</li>\n<li>SC.AUTO_CONTROL_SIZE. Automatically figures a control size (largest that will fit), but\nthrows a warning if you don't have \"height\" set and it has to calculate the size.</li>\n<li>SC.CALCULATED_CONTROL_SIZE. Like AUTO_CONTROL_SIZE, but calculates it.</li>\n</ul>\n\n<p><a href='button-size.js' class='demo'>button-size.js</a></p>","errors":[],"demos":{"touch-button.js":{"ex":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"button\".w(),\n button: SC.ButtonView.design({\n layout: { centerX: 0, centerY: 0, width: 200, height: 44 },\n title: \"Tap Here :)\",\n controlSize: SC.AUTO_CONTROL_SIZE\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;button&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">button</span>: <span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">centerX</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">centerY</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">200</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">44</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;Tap Here :)&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">AUTO_CONTROL_SIZE</span>\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"button\".w(),\n button: SC.ButtonView.design({\n layout: { centerX: 0, centerY: 0, width: 200, height: 44 },\n title: \"Tap Here :)\",\n controlSize: SC.AUTO_CONTROL_SIZE\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"},"button-size.js":{"ex":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"form\".w(),\n \n form: SC.FormView.design({\n layout: {centerX: 0, centerY: 0, width: 400, height: 300 },\n childViews: \"small regular huge jumbo\".w(),\n small: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 18 },\n title: \"I'm TINY!\",\n controlSize: SC.SMALL_CONTROL_SIZE\n })),\n \n regular: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 24 },\n title: \"I'm Normal!\",\n controlSize: SC.REGULAR_CONTROL_SIZE\n })),\n \n huge: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 30 },\n title: \"I'm huge.\",\n controlSize: SC.HUGE_CONTROL_SIZE\n })),\n \n jumbo: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 150, height: 44 },\n title: \"i'm jumbo.\",\n controlSize: SC.JUMBO_CONTROL_SIZE\n }))\n \n \n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;form&quot;</span>.<span class=\"variable\">w</span>(),\n \n <span class=\"variable\">form</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: {<span class=\"variable\">centerX</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">centerY</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">400</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">300</span> },\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;small regular huge jumbo&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">small</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">18</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm TINY!&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">SMALL_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">regular</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">24</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm Normal!&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">REGULAR_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">huge</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">30</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm huge.&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">HUGE_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">jumbo</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">150</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">44</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;i'm jumbo.&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">JUMBO_CONTROL_SIZE</span>\n }))\n \n \n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"form\".w(),\n \n form: SC.FormView.design({\n layout: {centerX: 0, centerY: 0, width: 400, height: 300 },\n childViews: \"small regular huge jumbo\".w(),\n small: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 18 },\n title: \"I'm TINY!\",\n controlSize: SC.SMALL_CONTROL_SIZE\n })),\n \n regular: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 24 },\n title: \"I'm Normal!\",\n controlSize: SC.REGULAR_CONTROL_SIZE\n })),\n \n huge: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 30 },\n title: \"I'm huge.\",\n controlSize: SC.HUGE_CONTROL_SIZE\n })),\n \n jumbo: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 150, height: 44 },\n title: \"i'm jumbo.\",\n controlSize: SC.JUMBO_CONTROL_SIZE\n }))\n \n \n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/controls/button/","outputDirectory":"build/","title":"ButtonView Touch Support"},{"content":"<h1>ScrollView Touch Support</h1>","errors":[],"demos":{},"articleDirectory":"articles/controls/scroll/","outputDirectory":"build/","title":"ScrollView Touch Support"}]},{"title":"Advanced Concepts","articles":[{"content":"<h1>Capturing</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Capturing"},{"content":"<h1>Releasing</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Releasing"}]}],"file":"build/guides/touch"}
View
39 docs/build/articles/controls/button/button-size.js
@@ -0,0 +1,39 @@
+var MyExampleView = SC.View.extend({
+ backgroundColor: "white",
+ childViews: "form".w(),
+
+ form: SC.FormView.design({
+ layout: {centerX: 0, centerY: 0, width: 400, height: 300 },
+ childViews: "small regular huge jumbo".w(),
+ small: SC.FormView.row(SC.ButtonView.design({
+ layout: { width: 100, height: 18 },
+ title: "I'm TINY!",
+ controlSize: SC.SMALL_CONTROL_SIZE
+ })),
+
+ regular: SC.FormView.row(SC.ButtonView.design({
+ layout: { width: 100, height: 24 },
+ title: "I'm Normal!",
+ controlSize: SC.REGULAR_CONTROL_SIZE
+ })),
+
+ huge: SC.FormView.row(SC.ButtonView.design({
+ layout: { width: 100, height: 30 },
+ title: "I'm huge.",
+ controlSize: SC.HUGE_CONTROL_SIZE
+ })),
+
+ jumbo: SC.FormView.row(SC.ButtonView.design({
+ layout: { width: 150, height: 44 },
+ title: "i'm jumbo.",
+ controlSize: SC.JUMBO_CONTROL_SIZE
+ }))
+
+
+ })
+});
+
+// bootstrap code :)
+exports.getDemoView = function() {
+ return MyExampleView;
+};
View
14 docs/build/articles/controls/button/touch-button.js
@@ -0,0 +1,14 @@
+var MyExampleView = SC.View.extend({
+ backgroundColor: "white",
+ childViews: "button".w(),
+ button: SC.ButtonView.design({
+ layout: { centerX: 0, centerY: 0, width: 200, height: 44 },
+ title: "Tap Here :)",
+ controlSize: SC.AUTO_CONTROL_SIZE
+ })
+});
+
+// bootstrap code :)
+exports.getDemoView = function() {
+ return MyExampleView;
+};
View
33 docs/build/articles/controls/button/touch.html
@@ -89,4 +89,37 @@
</head><body><div class="header"><a href="../../../index.html" class="img"><img src="../../../resources/logo.png" /></a><a href="../../../index.html" class="here">Documentation
</a><a href="../../../reference/index.html" class="item">SproutCore Reference
</a></div><div class="content"><h1>ButtonView Touch Support</h1>
+
+<p>ButtonView currently supports only a single touch (any other touches will be ignored).
+This is fine: why would you want to consider two touches in a button press?</p>
+
+<p>However, it does not simply relay the touches to <code class='syntax js'><span class="variable">mouseDown</span></code> and <code class='syntax js'><span class="variable">mouseUp</span></code>.</p>
+
+<p>Instead, it calculates the distance of the main touch (<code class='syntax js'><span class="variable">evt</span></code>'s <code class='syntax js'><span class="variable">pageX</span></code> and <code class='syntax js'><span class="variable">pageY</span></code>)
+from the button itself. This makes it easier to for a user to press a button while, for instance,
+moving their finger.</p>
+
+<p>This is all done for you automatically. Here's a simple demo:
+<a href='touch-button.js' class='demo'>touch-button.js</a></p>
+
+<h2>Ace 2.0</h2>
+
+<p>Ace 2.0 supports several button sizes. In addition, it is capable of <em>automatically picking</em>
+a size based on the size of your control. And best of all, it <em>centers</em> the button image
+vertically in the space you allocate. This allows you to, for instance, make a button 44px
+tall, but have the image only be 30px.</p>
+
+<p>You may use these options for <code class='syntax js'><span class="variable">controlSize</span></code>:</p>
+
+<ul>
+<li>SC.SMALL_CONTROL_SIZE. 18px.</li>
+<li>SC.REGULAR_CONTROL_SIZE. 24px.</li>
+<li>SC.HUGE_CONTROL_SIZE. 30px.</li>
+<li>SC.JUMBO_CONTROL_SIZE. 44px.</li>
+<li>SC.AUTO_CONTROL_SIZE. Automatically figures a control size (largest that will fit), but
+throws a warning if you don't have "height" set and it has to calculate the size.</li>
+<li>SC.CALCULATED_CONTROL_SIZE. Like AUTO_CONTROL_SIZE, but calculates it.</li>
+</ul>
+
+<p><a href='button-size.js' class='demo'>button-size.js</a></p>
</div><div class="footer"></div></body></html>
View
2 docs/build/articles/controls/button/touch.json
@@ -1 +1 @@
-{"content":"<h1>ButtonView Touch Support</h1>","errors":[],"demos":{},"articleDirectory":"articles/controls/button/","outputDirectory":"build/","title":"ButtonView Touch Support"}
+{"content":"<h1>ButtonView Touch Support</h1>\n\n<p>ButtonView currently supports only a single touch (any other touches will be ignored). \nThis is fine: why would you want to consider two touches in a button press?</p>\n\n<p>However, it does not simply relay the touches to <code class='syntax js'><span class=\"variable\">mouseDown</span></code> and <code class='syntax js'><span class=\"variable\">mouseUp</span></code>.</p>\n\n<p>Instead, it calculates the distance of the main touch (<code class='syntax js'><span class=\"variable\">evt</span></code>'s <code class='syntax js'><span class=\"variable\">pageX</span></code> and <code class='syntax js'><span class=\"variable\">pageY</span></code>)\nfrom the button itself. This makes it easier to for a user to press a button while, for instance,\nmoving their finger.</p>\n\n<p>This is all done for you automatically. Here's a simple demo:\n<a href='touch-button.js' class='demo'>touch-button.js</a></p>\n\n<h2>Ace 2.0</h2>\n\n<p>Ace 2.0 supports several button sizes. In addition, it is capable of <em>automatically picking</em>\na size based on the size of your control. And best of all, it <em>centers</em> the button image\nvertically in the space you allocate. This allows you to, for instance, make a button 44px\ntall, but have the image only be 30px.</p>\n\n<p>You may use these options for <code class='syntax js'><span class=\"variable\">controlSize</span></code>:</p>\n\n<ul>\n<li>SC.SMALL_CONTROL_SIZE. 18px.</li>\n<li>SC.REGULAR_CONTROL_SIZE. 24px.</li>\n<li>SC.HUGE_CONTROL_SIZE. 30px.</li>\n<li>SC.JUMBO_CONTROL_SIZE. 44px.</li>\n<li>SC.AUTO_CONTROL_SIZE. Automatically figures a control size (largest that will fit), but\nthrows a warning if you don't have \"height\" set and it has to calculate the size.</li>\n<li>SC.CALCULATED_CONTROL_SIZE. Like AUTO_CONTROL_SIZE, but calculates it.</li>\n</ul>\n\n<p><a href='button-size.js' class='demo'>button-size.js</a></p>","errors":[],"demos":{"touch-button.js":{"ex":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"button\".w(),\n button: SC.ButtonView.design({\n layout: { centerX: 0, centerY: 0, width: 200, height: 44 },\n title: \"Tap Here :)\",\n controlSize: SC.AUTO_CONTROL_SIZE\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;button&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">button</span>: <span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">centerX</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">centerY</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">200</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">44</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;Tap Here :)&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">AUTO_CONTROL_SIZE</span>\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"button\".w(),\n button: SC.ButtonView.design({\n layout: { centerX: 0, centerY: 0, width: 200, height: 44 },\n title: \"Tap Here :)\",\n controlSize: SC.AUTO_CONTROL_SIZE\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"},"button-size.js":{"ex":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"form\".w(),\n \n form: SC.FormView.design({\n layout: {centerX: 0, centerY: 0, width: 400, height: 300 },\n childViews: \"small regular huge jumbo\".w(),\n small: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 18 },\n title: \"I'm TINY!\",\n controlSize: SC.SMALL_CONTROL_SIZE\n })),\n \n regular: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 24 },\n title: \"I'm Normal!\",\n controlSize: SC.REGULAR_CONTROL_SIZE\n })),\n \n huge: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 30 },\n title: \"I'm huge.\",\n controlSize: SC.HUGE_CONTROL_SIZE\n })),\n \n jumbo: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 150, height: 44 },\n title: \"i'm jumbo.\",\n controlSize: SC.JUMBO_CONTROL_SIZE\n }))\n \n \n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;form&quot;</span>.<span class=\"variable\">w</span>(),\n \n <span class=\"variable\">form</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: {<span class=\"variable\">centerX</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">centerY</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">400</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">300</span> },\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;small regular huge jumbo&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">small</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">18</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm TINY!&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">SMALL_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">regular</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">24</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm Normal!&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">REGULAR_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">huge</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">30</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm huge.&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">HUGE_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">jumbo</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">150</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">44</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;i'm jumbo.&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">JUMBO_CONTROL_SIZE</span>\n }))\n \n \n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"form\".w(),\n \n form: SC.FormView.design({\n layout: {centerX: 0, centerY: 0, width: 400, height: 300 },\n childViews: \"small regular huge jumbo\".w(),\n small: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 18 },\n title: \"I'm TINY!\",\n controlSize: SC.SMALL_CONTROL_SIZE\n })),\n \n regular: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 24 },\n title: \"I'm Normal!\",\n controlSize: SC.REGULAR_CONTROL_SIZE\n })),\n \n huge: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 30 },\n title: \"I'm huge.\",\n controlSize: SC.HUGE_CONTROL_SIZE\n })),\n \n jumbo: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 150, height: 44 },\n title: \"i'm jumbo.\",\n controlSize: SC.JUMBO_CONTROL_SIZE\n }))\n \n \n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/controls/button/","outputDirectory":"build/","title":"ButtonView Touch Support"}
View
32 docs/build/articles/controls/button/touch.md
@@ -1,2 +1,32 @@
ButtonView Touch Support
-========================
+========================
+ButtonView currently supports only a single touch (any other touches will be ignored).
+This is fine: why would you want to consider two touches in a button press?
+
+However, it does not simply relay the touches to `#js:mouseDown` and `#js:mouseUp`.
+
+Instead, it calculates the distance of the main touch (`#js:evt`'s `#js:pageX` and `#js:pageY`)
+from the button itself. This makes it easier to for a user to press a button while, for instance,
+moving their finger.
+
+This is all done for you automatically. Here's a simple demo:
+{{demo:sc|touch-button.js}}
+
+Ace 2.0
+--------
+Ace 2.0 supports several button sizes. In addition, it is capable of _automatically picking_
+a size based on the size of your control. And best of all, it _centers_ the button image
+vertically in the space you allocate. This allows you to, for instance, make a button 44px
+tall, but have the image only be 30px.
+
+You may use these options for `#js:controlSize`:
+
+- SC.SMALL\_CONTROL\_SIZE. 18px.
+- SC.REGULAR\_CONTROL\_SIZE. 24px.
+- SC.HUGE\_CONTROL\_SIZE. 30px.
+- SC.JUMBO\_CONTROL\_SIZE. 44px.
+- SC.AUTO\_CONTROL\_SIZE. Automatically figures a control size (largest that will fit), but
+ throws a warning if you don't have "height" set and it has to calculate the size.
+- SC.CALCULATED\_CONTROL\_SIZE. Like AUTO\_CONTROL\_SIZE, but calculates it.
+
+{{demo:sc|button-size.js}}
View
2 docs/build/guides/touch.json
@@ -1 +1 @@
-{"title":"Touch Application Guide","sections":[{"title":"Introduction","articles":[{"content":"<h1>A Brief Touch</h1>\n\n<p>It is very possible to build <em>awesome</em> touch-enabled applications in SproutCore.</p>\n\n<p>But, what makes an awesome touch-enabled application? Sure, it must accept touches,\nbut with SproutCore's (constantly growing) touch support, this is now pretty easy:\nmany existing interfaces, if built with newer SproutCore varieties, will function fine (or mostly fine),\non both larger-screened touch devices (such as iPad) and the traditional desktop environment.</p>\n\n<p>But there are many differences between desktop and touch platforms:</p>\n\n<ul>\n<li><strong>Precision.</strong> Touches are less precise than clicks. To compensate, controls should be larger.</li>\n<li><strong>Performance.</strong> Touch-based devices tend to be slow (for now). To get around this just takes \nsome elbow grease: there are many techniques to speed things up... many of which SproutCore will\nhandle for you.</li>\n<li><strong>Animation.</strong> Lack of animation looks okay on desktop (even if animation is cool)... but on\ntouch devices, non-animated interfaces look strange: touch is so much more realistic than mouse,\nbut sudden changes without transitions are not realistic at all.</li>\n<li><strong>Coolness.</strong> Touch-based interfaces are cool. That is all.</li>\n</ul>\n\n<p>In this guide, we go over each of these&emdash;except for the last, which is rather vague; you'll have to figure out\nyour own meaning of \"coolness\".</p>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"A Brief Touch","any":"metadata","goes":"Here","damn":"gruber","this":"is still eye-readable","and":"He is wrong about touch apps."},{"content":"<h1>Touch Events</h1>\n\n<p>SproutCore's touch events have a few great features:</p>\n\n<ul>\n<li>Multiple views can receive touches simultaneously.</li>\n<li>A single view can receive multiple touches.</li>\n<li>A view can capture touches before allowing them to pass through to children.</li>\n<li>Child views can release touches back to parent views that originally captured them.</li>\n</ul>\n\n<p>We won't get into the last two in this article&emdash;they're quite sophisticated!</p>\n\n<h1>Simple Single-Touch Handling</h1>\n\n<p>You may be familiar with this SC.View method signature if you are familiar with SproutCore:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>)\n</code></pre>\n\n<p>With <code class='syntax js'><span class=\"variable\">mouseDown</span></code>, you can decide whether or not to accept the mouse event by returning either\n<code class='syntax js'><span class=\"class\">YES</span></code> or <code class='syntax js'><span class=\"class\">NO</span></code>.</p>\n\n<p>Touch events are similar, but work a bit differently:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>)\n</code></pre>\n\n<p>Instead of being passed a raw event, <code class='syntax js'><span class=\"variable\">touchStart</span></code> is passed an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code> object.\nIf you return YES from touchStart, your view will \"own\" the touch\u2014in SproutCore terms, your\nview will be the <em>touch responder</em>. For more information about what this entails, see\nthe \"Internals\" article. Your view will own the touch until the touch ends.</p>\n\n<p><code class='syntax js'><span class=\"variable\">touchStart</span></code> will be called once for every touch that touches the view.</p>\n\n<p><strong>Note:</strong> By default, views only receive <code class='syntax js'><span class=\"variable\">touchStart</span></code> and touchEnd for a single touch. This is\na feature intended to make it easier to handle such cases, very similar to Cocoa Touch's <code class='syntax js'><span class=\"variable\">acceptsMultitouch</span></code>\nproperty\u2014actually, SC.View uses the same property name! See the \"Multitouch\" article.</p>\n\n<h2>Anatomy of an SC.Touch</h2>\n\n<p>SC.Touch represents the touch from the time the user puts their finger on the screen until the time they lift it.</p>\n\n<p>The touch object acts like an event object in many ways. It has many other useful things, as well:</p>\n\n<ul>\n<li><code class='syntax js'><span class=\"variable\">pageX</span></code> and <code class='syntax js'><span class=\"variable\">pageY</span></code> for the touch</li>\n<li><code class='syntax js'><span class=\"variable\">event</span></code>: if in an event cycle, this contains the event. Otherwise, it is <code class='syntax js'><span class=\"variable\">undefined</span></code>. \nYou will probably never need to access this.</li>\n<li><code class='syntax js'><span class=\"variable\">preventDefault</span></code>: if the touch is connected with an event, this calls <code class='syntax js'><span class=\"variable\">preventDefault</span>()</code> on the event.</li>\n<li><code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"variable\">view</span>)</code>: when supplied a view, will find all touches that the view is the\ntouch responder for. It is a CoreSet; to get an array, call <code class='syntax js'>.<span class=\"variable\">toArray</span></code> on the result.</li>\n<li><code class='syntax js'><span class=\"variable\">averagedTouchesForView</span>(<span class=\"variable\">view</span>)</code>: When supplied a view, averages all the touches on that view,\nreturning both an average position and an average distance from that position.</li>\n</ul>\n\n<p><strong>Note:</strong> If you call <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code> from <code class='syntax js'><span class=\"variable\">touchStart</span></code>, the touch supplied will not be in the set\nreturned by <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>: you don't own the touch until you return YES.</p>\n\n<h2>touchEnd</h2>\n\n<p>Knowing when the touch starts is not very useful. At the very least, you will likely want to know when the touch\nends as well.</p>\n\n<p>It is quite simple:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>)\n</code></pre>\n\n<p>It works exactly like <code class='syntax js'><span class=\"variable\">touchStart</span></code>. The touch will no longer be in the set of touches for the view,\nso if you call <code class='syntax js'><span class=\"variable\">touch</span>.<span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>, you'll only receive any other active touches. If your\nview does not accept multitouch, then the set is guaranteed to have no touches in it\u2014you only receive\n<code class='syntax js'><span class=\"variable\">touchEnd</span></code> for the last touch that ends.</p>\n\n<h2>Tracking Touches</h2>\n\n<p>Tracking touch movement is simple:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>)\n</code></pre>\n\n<p>The <code class='syntax js'><span class=\"variable\">touches</span></code> argument is the set of touches on the view\u2014the same set you get by calling <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>.\nThis will have <em>all</em> touches, regardless of whether or not your view accepts multitouch.</p>\n\n<p>If your view does <em>not</em> accept multitouch, then it is even simpler:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">x</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">pageX</span>;\n<span class=\"variable\">y</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">pageY</span>;\n</code></pre>\n\n<h2>Tip: Cross-Platform-iness</h2>\n\n<p>Did you realize that, assuming you don't use the set of view touches or other touch-specific API,\nyou can do this:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n},\n\n<span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n},\n\n<span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n}\n</code></pre>\n\n<p>Of course, you can also redirect touch events to mouse events, but that is not as fun.</p>\n\n<h2>Putting it All Together</h2>\n\n<p>Here is a very simple demo that uses the methods described above to allow the user to move two views\naround the screen:</p>\n\n<p><a href='touch-demo.js' class='demo'>touch-demo.js</a></p>","errors":[],"demos":{"touch-demo.js":{"ex":"var Dot = SC.View.extend({\n touchStart: function(touch) {\n var f = this.get(\"frame\");\n this._touch = {\n start: { x: touch.pageX, y: touch.pageY },\n ourStart: { x: f.x, y: f.y, width: f.width, height: f.height }\n };\n return YES; // or we won't get touchesDragged\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n this.set(\"layout\", { \n left: t.ourStart.x + evt.pageX - t.start.x,\n top: t.ourStart.y + evt.pageY - t.start.y,\n width: t.ourStart.width,\n height: t.ourStart.height\n });\n },\n \n touchEnd: function() {\n // actually, we don't need to do anything here...\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"dot1 dot2\".w(),\n dot1: Dot.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 100, height: 100 }\n }),\n dot2: Dot.design({\n backgroundColor: \"blue\",\n layout: { right: 10, bottom: 10, width: 100, height: 100 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">Dot</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">f</span> = <span class=\"this\">this</span>.<span class=\"variable\">get</span>(<span class=\"string\">&quot;frame&quot;</span>);\n <span class=\"this\">this</span>.<span class=\"variable\">_touch</span> = {\n <span class=\"variable\">start</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">touch</span>.<span class=\"variable\">pageX</span>, <span class=\"variable\">y</span>: <span class=\"variable\">touch</span>.<span class=\"variable\">pageY</span> },\n <span class=\"variable\">ourStart</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">f</span>.<span class=\"variable\">x</span>, <span class=\"variable\">y</span>: <span class=\"variable\">f</span>.<span class=\"variable\">y</span>, <span class=\"variable\">width</span>: <span class=\"variable\">f</span>.<span class=\"variable\">width</span>, <span class=\"variable\">height</span>: <span class=\"variable\">f</span>.<span class=\"variable\">height</span> }\n };\n <span class=\"keyword\">return</span> <span class=\"class\">YES</span>; <span class=\"comment\">// or we won't get touchesDragged</span>\n },\n \n <span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">t</span> = <span class=\"this\">this</span>.<span class=\"variable\">_touch</span>;\n <span class=\"this\">this</span>.<span class=\"variable\">set</span>(<span class=\"string\">&quot;layout&quot;</span>, { \n <span class=\"variable\">left</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">x</span> + <span class=\"variable\">evt</span>.<span class=\"variable\">pageX</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">x</span>,\n <span class=\"variable\">top</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">y</span> + <span class=\"variable\">evt</span>.<span class=\"variable\">pageY</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">y</span>,\n <span class=\"variable\">width</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">width</span>,\n <span class=\"variable\">height</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">height</span>\n });\n },\n \n <span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>() {\n <span class=\"comment\">// actually, we don't need to do anything here...</span>\n },\n \n <span class=\"comment\">// and now, redirect mouse events :)</span>\n <span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n }\n});\n<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;dot1 dot2&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">dot1</span>: <span class=\"class\">Dot</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;red&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">left</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">top</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">100</span> }\n }),\n <span class=\"variable\">dot2</span>: <span class=\"class\">Dot</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;blue&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">right</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">bottom</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">100</span> }\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var Dot = SC.View.extend({\n touchStart: function(touch) {\n var f = this.get(\"frame\");\n this._touch = {\n start: { x: touch.pageX, y: touch.pageY },\n ourStart: { x: f.x, y: f.y, width: f.width, height: f.height }\n };\n return YES; // or we won't get touchesDragged\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n this.set(\"layout\", { \n left: t.ourStart.x + evt.pageX - t.start.x,\n top: t.ourStart.y + evt.pageY - t.start.y,\n width: t.ourStart.width,\n height: t.ourStart.height\n });\n },\n \n touchEnd: function() {\n // actually, we don't need to do anything here...\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"dot1 dot2\".w(),\n dot1: Dot.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 100, height: 100 }\n }),\n dot2: Dot.design({\n backgroundColor: \"blue\",\n layout: { right: 10, bottom: 10, width: 100, height: 100 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Touch Events"},{"content":"<h1>Multitouch</h1>\n\n<p>Handling single touches is pretty easy&emdash;not that much different from handling\nmouse events. But what about multiple touches?</p>\n\n<h2>Accepting Multiple Touches</h2>\n\n<p>First, you have to tell your view that you do, indeed want to receive multiple\ntouches. By default, views only receive single touches. This is because is easier \nto think in a single-touch model, and most controls only need to track a single touch.</p>\n\n<p>To accept multiple touches, just set the view's <code class='syntax js'><span class=\"variable\">acceptsMultitouch</span></code> property to\n<code class='syntax js'><span class=\"class\">YES</span></code>.</p>\n\n<pre><code class='syntax js'><span class=\"variable\">view</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">acceptsMultitouch</span>: <span class=\"class\">YES</span>\n});\n</code></pre>\n\n<h2>Processing the Individual Touches</h2>\n\n<p>Even without the supplied helper function, processing individual touches is relatively\nsimple:</p>\n\n<ul>\n<li>You get a separate <code class='syntax js'><span class=\"variable\">touchStart</span></code> for each individual touch.</li>\n<li>You get a separate <code class='syntax js'><span class=\"variable\">touchEnd</span></code> for each individual touch.</li>\n<li>You get one <code class='syntax js'><span class=\"variable\">touchesDragged</span></code> each event cycle for all of your touches put together.</li>\n</ul>\n\n<p>So, detecting individual touches starting and ending is simple. Detecting those touches\nmoving is not quite as simple, but still relatively easy.</p>\n\n<p>Remember how <code class='syntax js'><span class=\"variable\">touchesDragged</span></code> works:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>)\n</code></pre>\n\n<p><code class='syntax js'><span class=\"variable\">touches</span></code> is an SC.CoreSet of SC.Touch objects. What can you do with a CoreSet? \nYou can do a couple of things:</p>\n\n<ul>\n<li>Turn it into an array and do whatever.</li>\n<li>Call .forEach to iterate.</li>\n</ul>\n\n<p>But you don't have to use the touches set at all. The <code class='syntax js'><span class=\"variable\">evt</span></code> has some useful properties and methods,\ntoo:</p>\n\n<ul>\n<li>pageX/pageY: the position of the first touch.</li>\n<li>averagedTouchesForView: a method which returns the averaged touch position\nand the average distance of the touches from that position.</li>\n</ul>\n\n<p><code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">ScrollView</span></code>, for instance, makes heavy use of <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code>, and never\ndirectly touches the <code class='syntax js'><span class=\"variable\">touches</span></code> set.</p>\n\n<h2>Averaging Touches</h2>\n\n<p>It is often <em>very</em> useful to average the touches. </p>\n\n<p><code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code> returns an object with four properties:</p>\n\n<ul>\n<li><strong><code class='syntax js'><span class=\"variable\">x</span></code></strong>: The average X position of the touch.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">y</span></code></strong>: The average Y position of the touch.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">d</span></code></strong>: average distance of the all touches from the average x/y position.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">touchCount</span></code></strong> The number of touches averaged.</li>\n</ul>\n\n<p>You can call <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code> on two separate objects: an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Event</span></code> object,\nor an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code> object.</p>\n\n<p>The two work identically but for one important difference: when you call it on <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code>,\nyou <em>have the option</em> of telling the touch to add itself to the averaged set. Doing so makes no sense\nin most cases: the touch would just be counted twice! But what about <code class='syntax js'><span class=\"variable\">touchStart</span></code>?</p>\n\n<p>Recall that during <code class='syntax js'><span class=\"variable\">touchStart</span></code>, the view does not yet own the touch. So, <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code>\nwould not, by default count it.</p>\n\n<pre><code class='syntax js'><span class=\"comment\">// on an event:</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n\n<span class=\"comment\">// on a touch</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n\n<span class=\"comment\">// on a touch, counting the touch itself</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>, <span class=\"class\">YES</span>);\n</code></pre>\n\n<h2>Thinking it Over</h2>\n\n<p>How might you use all of these to produce a good result?</p>\n\n<p>Let's take a simple example: moving and resizing something:</p>\n\n<p><a href='multitouch.js' class='demo'>multitouch.js</a></p>","errors":[],"demos":{"multitouch.js":{"ex":"var Box = SC.View.extend({\n _scale: 1,\n _translateX: 0,\n _translateY: 0,\n acceptsMultitouch: YES,\n touchStart: function(touch) {\n this.recomputeTouchStatus(touch, YES);\n return YES;\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n var avg = evt.averagedTouchesForView(this);\n \n // translation is easy:\n this._translateX = t.ourStart.x + avg.x - t.start.x;\n this._translateY = t.ourStart.y + avg.y - t.start.y;\n \n // mathematically speaking, scale *= the end distance / the start distance\n if (t.start.d > 1) { // but prevent divide-by-0\n this._scale = t.ourStart.scale * (avg.d / t.start.d);\n }\n \n // reposition\n this._reposition();\n },\n \n touchEnd: function(touch) {\n this.recomputeTouchStatus(touch, NO);\n },\n \n /**\n With this, we recompute our touch status--updating the start positioning and scale.\n */\n recomputeTouchStatus: function(touch, considerTouch) {\n var avg = touch.averagedTouchesForView(this, considerTouch);\n this._touch = {\n start: { x: avg.x, y: avg.y, d: avg.d },\n ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }\n };\n },\n \n /**\n Repositions the view.\n */\n _reposition: function() {\n this.get(\"layer\").style.webkitTransform = \n \"translate3d(\" + this._translateX + \"px,\" + this._translateY + \"px, 0px) \" +\n \"scale3d(\" + this._scale + \",\" + this._scale + \",1)\";\n console.error(this._translateX + \" \" + this._translateY + \" \" + this._scale);\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"box\".w(),\n box: Box.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 200, height: 200 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">Box</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">_scale</span>: <span class=\"number integer\">1</span>,\n <span class=\"variable\">_translateX</span>: <span class=\"number integer\">0</span>,\n <span class=\"variable\">_translateY</span>: <span class=\"number integer\">0</span>,\n <span class=\"variable\">acceptsMultitouch</span>: <span class=\"class\">YES</span>,\n <span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">recomputeTouchStatus</span>(<span class=\"variable\">touch</span>, <span class=\"class\">YES</span>);\n <span class=\"keyword\">return</span> <span class=\"class\">YES</span>;\n },\n \n <span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">t</span> = <span class=\"this\">this</span>.<span class=\"variable\">_touch</span>;\n <span class=\"keyword\">var</span> <span class=\"variable\">avg</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n \n <span class=\"comment\">// translation is easy:</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">x</span> + <span class=\"variable\">avg</span>.<span class=\"variable\">x</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">x</span>;\n <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">y</span> + <span class=\"variable\">avg</span>.<span class=\"variable\">y</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">y</span>;\n \n <span class=\"comment\">// mathematically speaking, scale *= the end distance / the start distance</span>\n <span class=\"keyword\">if</span> (<span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">d</span> &gt; <span class=\"number integer\">1</span>) { <span class=\"comment\">// but prevent divide-by-0</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">scale</span> * (<span class=\"variable\">avg</span>.<span class=\"variable\">d</span> / <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">d</span>);\n }\n \n <span class=\"comment\">// reposition</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_reposition</span>();\n },\n \n <span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">recomputeTouchStatus</span>(<span class=\"variable\">touch</span>, <span class=\"class\">NO</span>);\n },\n \n <span class=\"multiline comment\">/**\n With this, we recompute our touch status--updating the start positioning and scale.\n */</span>\n <span class=\"variable\">recomputeTouchStatus</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>, <span class=\"variable\">considerTouch</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">avg</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>, <span class=\"variable\">considerTouch</span>);\n <span class=\"this\">this</span>.<span class=\"variable\">_touch</span> = {\n <span class=\"variable\">start</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">x</span>, <span class=\"variable\">y</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">y</span>, <span class=\"variable\">d</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">d</span> },\n <span class=\"variable\">ourStart</span>: { <span class=\"variable\">x</span>: <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span>, <span class=\"variable\">y</span>: <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span>, <span class=\"variable\">scale</span>: <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> }\n };\n },\n \n <span class=\"multiline comment\">/**\n Repositions the view.\n */</span>\n <span class=\"variable\">_reposition</span>: <span class=\"keyword\">function</span>() {\n <span class=\"this\">this</span>.<span class=\"variable\">get</span>(<span class=\"string\">&quot;layer&quot;</span>).<span class=\"variable\">style</span>.<span class=\"variable\">webkitTransform</span> = \n <span class=\"string\">&quot;translate3d(&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> + <span class=\"string\">&quot;px,&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> + <span class=\"string\">&quot;px, 0px) &quot;</span> +\n <span class=\"string\">&quot;scale3d(&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> + <span class=\"string\">&quot;,&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> + <span class=\"string\">&quot;,1)&quot;</span>;\n <span class=\"variable\">console</span>.<span class=\"variable\">error</span>(<span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> + <span class=\"string\">&quot; &quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> + <span class=\"string\">&quot; &quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span>);\n },\n \n <span class=\"comment\">// and now, redirect mouse events :)</span>\n <span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n }\n});\n<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;box&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">box</span>: <span class=\"class\">Box</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;red&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">left</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">top</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">200</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">200</span> }\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var Box = SC.View.extend({\n _scale: 1,\n _translateX: 0,\n _translateY: 0,\n acceptsMultitouch: YES,\n touchStart: function(touch) {\n this.recomputeTouchStatus(touch, YES);\n return YES;\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n var avg = evt.averagedTouchesForView(this);\n \n // translation is easy:\n this._translateX = t.ourStart.x + avg.x - t.start.x;\n this._translateY = t.ourStart.y + avg.y - t.start.y;\n \n // mathematically speaking, scale *= the end distance / the start distance\n if (t.start.d > 1) { // but prevent divide-by-0\n this._scale = t.ourStart.scale * (avg.d / t.start.d);\n }\n \n // reposition\n this._reposition();\n },\n \n touchEnd: function(touch) {\n this.recomputeTouchStatus(touch, NO);\n },\n \n /**\n With this, we recompute our touch status--updating the start positioning and scale.\n */\n recomputeTouchStatus: function(touch, considerTouch) {\n var avg = touch.averagedTouchesForView(this, considerTouch);\n this._touch = {\n start: { x: avg.x, y: avg.y, d: avg.d },\n ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }\n };\n },\n \n /**\n Repositions the view.\n */\n _reposition: function() {\n this.get(\"layer\").style.webkitTransform = \n \"translate3d(\" + this._translateX + \"px,\" + this._translateY + \"px, 0px) \" +\n \"scale3d(\" + this._scale + \",\" + this._scale + \",1)\";\n console.error(this._translateX + \" \" + this._translateY + \" \" + this._scale);\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"box\".w(),\n box: Box.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 200, height: 200 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Multitouch"}]},{"title":"Built-In Support","articles":[{"content":"<h1>ButtonView Touch Support</h1>","errors":[],"demos":{},"articleDirectory":"articles/controls/button/","outputDirectory":"build/","title":"ButtonView Touch Support"},{"content":"<h1>ScrollView Touch Support</h1>","errors":[],"demos":{},"articleDirectory":"articles/controls/scroll/","outputDirectory":"build/","title":"ScrollView Touch Support"}]},{"title":"Advanced Concepts","articles":[{"content":"<h1>Capturing</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Capturing"},{"content":"<h1>Releasing</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Releasing"}]}],"file":"build/guides/touch"}
+{"title":"Touch Application Guide","sections":[{"title":"Introduction","articles":[{"content":"<h1>A Brief Touch</h1>\n\n<p>It is very possible to build <em>awesome</em> touch-enabled applications in SproutCore.</p>\n\n<p>But, what makes an awesome touch-enabled application? Sure, it must accept touches,\nbut with SproutCore's (constantly growing) touch support, this is now pretty easy:\nmany existing interfaces, if built with newer SproutCore varieties, will function fine (or mostly fine),\non both larger-screened touch devices (such as iPad) and the traditional desktop environment.</p>\n\n<p>But there are many differences between desktop and touch platforms:</p>\n\n<ul>\n<li><strong>Precision.</strong> Touches are less precise than clicks. To compensate, controls should be larger.</li>\n<li><strong>Performance.</strong> Touch-based devices tend to be slow (for now). To get around this just takes \nsome elbow grease: there are many techniques to speed things up... many of which SproutCore will\nhandle for you.</li>\n<li><strong>Animation.</strong> Lack of animation looks okay on desktop (even if animation is cool)... but on\ntouch devices, non-animated interfaces look strange: touch is so much more realistic than mouse,\nbut sudden changes without transitions are not realistic at all.</li>\n<li><strong>Coolness.</strong> Touch-based interfaces are cool. That is all.</li>\n</ul>\n\n<p>In this guide, we go over each of these&emdash;except for the last, which is rather vague; you'll have to figure out\nyour own meaning of \"coolness\".</p>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"A Brief Touch","any":"metadata","goes":"Here","damn":"gruber","this":"is still eye-readable","and":"He is wrong about touch apps."},{"content":"<h1>Touch Events</h1>\n\n<p>SproutCore's touch events have a few great features:</p>\n\n<ul>\n<li>Multiple views can receive touches simultaneously.</li>\n<li>A single view can receive multiple touches.</li>\n<li>A view can capture touches before allowing them to pass through to children.</li>\n<li>Child views can release touches back to parent views that originally captured them.</li>\n</ul>\n\n<p>We won't get into the last two in this article&emdash;they're quite sophisticated!</p>\n\n<h1>Simple Single-Touch Handling</h1>\n\n<p>You may be familiar with this SC.View method signature if you are familiar with SproutCore:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>)\n</code></pre>\n\n<p>With <code class='syntax js'><span class=\"variable\">mouseDown</span></code>, you can decide whether or not to accept the mouse event by returning either\n<code class='syntax js'><span class=\"class\">YES</span></code> or <code class='syntax js'><span class=\"class\">NO</span></code>.</p>\n\n<p>Touch events are similar, but work a bit differently:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>)\n</code></pre>\n\n<p>Instead of being passed a raw event, <code class='syntax js'><span class=\"variable\">touchStart</span></code> is passed an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code> object.\nIf you return YES from touchStart, your view will \"own\" the touch\u2014in SproutCore terms, your\nview will be the <em>touch responder</em>. For more information about what this entails, see\nthe \"Internals\" article. Your view will own the touch until the touch ends.</p>\n\n<p><code class='syntax js'><span class=\"variable\">touchStart</span></code> will be called once for every touch that touches the view.</p>\n\n<p><strong>Note:</strong> By default, views only receive <code class='syntax js'><span class=\"variable\">touchStart</span></code> and touchEnd for a single touch. This is\na feature intended to make it easier to handle such cases, very similar to Cocoa Touch's <code class='syntax js'><span class=\"variable\">acceptsMultitouch</span></code>\nproperty\u2014actually, SC.View uses the same property name! See the \"Multitouch\" article.</p>\n\n<h2>Anatomy of an SC.Touch</h2>\n\n<p>SC.Touch represents the touch from the time the user puts their finger on the screen until the time they lift it.</p>\n\n<p>The touch object acts like an event object in many ways. It has many other useful things, as well:</p>\n\n<ul>\n<li><code class='syntax js'><span class=\"variable\">pageX</span></code> and <code class='syntax js'><span class=\"variable\">pageY</span></code> for the touch</li>\n<li><code class='syntax js'><span class=\"variable\">event</span></code>: if in an event cycle, this contains the event. Otherwise, it is <code class='syntax js'><span class=\"variable\">undefined</span></code>. \nYou will probably never need to access this.</li>\n<li><code class='syntax js'><span class=\"variable\">preventDefault</span></code>: if the touch is connected with an event, this calls <code class='syntax js'><span class=\"variable\">preventDefault</span>()</code> on the event.</li>\n<li><code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"variable\">view</span>)</code>: when supplied a view, will find all touches that the view is the\ntouch responder for. It is a CoreSet; to get an array, call <code class='syntax js'>.<span class=\"variable\">toArray</span></code> on the result.</li>\n<li><code class='syntax js'><span class=\"variable\">averagedTouchesForView</span>(<span class=\"variable\">view</span>)</code>: When supplied a view, averages all the touches on that view,\nreturning both an average position and an average distance from that position.</li>\n</ul>\n\n<p><strong>Note:</strong> If you call <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code> from <code class='syntax js'><span class=\"variable\">touchStart</span></code>, the touch supplied will not be in the set\nreturned by <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>: you don't own the touch until you return YES.</p>\n\n<h2>touchEnd</h2>\n\n<p>Knowing when the touch starts is not very useful. At the very least, you will likely want to know when the touch\nends as well.</p>\n\n<p>It is quite simple:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>)\n</code></pre>\n\n<p>It works exactly like <code class='syntax js'><span class=\"variable\">touchStart</span></code>. The touch will no longer be in the set of touches for the view,\nso if you call <code class='syntax js'><span class=\"variable\">touch</span>.<span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>, you'll only receive any other active touches. If your\nview does not accept multitouch, then the set is guaranteed to have no touches in it\u2014you only receive\n<code class='syntax js'><span class=\"variable\">touchEnd</span></code> for the last touch that ends.</p>\n\n<h2>Tracking Touches</h2>\n\n<p>Tracking touch movement is simple:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>)\n</code></pre>\n\n<p>The <code class='syntax js'><span class=\"variable\">touches</span></code> argument is the set of touches on the view\u2014the same set you get by calling <code class='syntax js'><span class=\"variable\">touchesForView</span>(<span class=\"this\">this</span>)</code>.\nThis will have <em>all</em> touches, regardless of whether or not your view accepts multitouch.</p>\n\n<p>If your view does <em>not</em> accept multitouch, then it is even simpler:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">x</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">pageX</span>;\n<span class=\"variable\">y</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">pageY</span>;\n</code></pre>\n\n<h2>Tip: Cross-Platform-iness</h2>\n\n<p>Did you realize that, assuming you don't use the set of view touches or other touch-specific API,\nyou can do this:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n},\n\n<span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n},\n\n<span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n}\n</code></pre>\n\n<p>Of course, you can also redirect touch events to mouse events, but that is not as fun.</p>\n\n<h2>Putting it All Together</h2>\n\n<p>Here is a very simple demo that uses the methods described above to allow the user to move two views\naround the screen:</p>\n\n<p><a href='touch-demo.js' class='demo'>touch-demo.js</a></p>","errors":[],"demos":{"touch-demo.js":{"ex":"var Dot = SC.View.extend({\n touchStart: function(touch) {\n var f = this.get(\"frame\");\n this._touch = {\n start: { x: touch.pageX, y: touch.pageY },\n ourStart: { x: f.x, y: f.y, width: f.width, height: f.height }\n };\n return YES; // or we won't get touchesDragged\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n this.set(\"layout\", { \n left: t.ourStart.x + evt.pageX - t.start.x,\n top: t.ourStart.y + evt.pageY - t.start.y,\n width: t.ourStart.width,\n height: t.ourStart.height\n });\n },\n \n touchEnd: function() {\n // actually, we don't need to do anything here...\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"dot1 dot2\".w(),\n dot1: Dot.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 100, height: 100 }\n }),\n dot2: Dot.design({\n backgroundColor: \"blue\",\n layout: { right: 10, bottom: 10, width: 100, height: 100 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">Dot</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">f</span> = <span class=\"this\">this</span>.<span class=\"variable\">get</span>(<span class=\"string\">&quot;frame&quot;</span>);\n <span class=\"this\">this</span>.<span class=\"variable\">_touch</span> = {\n <span class=\"variable\">start</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">touch</span>.<span class=\"variable\">pageX</span>, <span class=\"variable\">y</span>: <span class=\"variable\">touch</span>.<span class=\"variable\">pageY</span> },\n <span class=\"variable\">ourStart</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">f</span>.<span class=\"variable\">x</span>, <span class=\"variable\">y</span>: <span class=\"variable\">f</span>.<span class=\"variable\">y</span>, <span class=\"variable\">width</span>: <span class=\"variable\">f</span>.<span class=\"variable\">width</span>, <span class=\"variable\">height</span>: <span class=\"variable\">f</span>.<span class=\"variable\">height</span> }\n };\n <span class=\"keyword\">return</span> <span class=\"class\">YES</span>; <span class=\"comment\">// or we won't get touchesDragged</span>\n },\n \n <span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">t</span> = <span class=\"this\">this</span>.<span class=\"variable\">_touch</span>;\n <span class=\"this\">this</span>.<span class=\"variable\">set</span>(<span class=\"string\">&quot;layout&quot;</span>, { \n <span class=\"variable\">left</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">x</span> + <span class=\"variable\">evt</span>.<span class=\"variable\">pageX</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">x</span>,\n <span class=\"variable\">top</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">y</span> + <span class=\"variable\">evt</span>.<span class=\"variable\">pageY</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">y</span>,\n <span class=\"variable\">width</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">width</span>,\n <span class=\"variable\">height</span>: <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">height</span>\n });\n },\n \n <span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>() {\n <span class=\"comment\">// actually, we don't need to do anything here...</span>\n },\n \n <span class=\"comment\">// and now, redirect mouse events :)</span>\n <span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n }\n});\n<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;dot1 dot2&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">dot1</span>: <span class=\"class\">Dot</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;red&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">left</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">top</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">100</span> }\n }),\n <span class=\"variable\">dot2</span>: <span class=\"class\">Dot</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;blue&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">right</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">bottom</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">100</span> }\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var Dot = SC.View.extend({\n touchStart: function(touch) {\n var f = this.get(\"frame\");\n this._touch = {\n start: { x: touch.pageX, y: touch.pageY },\n ourStart: { x: f.x, y: f.y, width: f.width, height: f.height }\n };\n return YES; // or we won't get touchesDragged\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n this.set(\"layout\", { \n left: t.ourStart.x + evt.pageX - t.start.x,\n top: t.ourStart.y + evt.pageY - t.start.y,\n width: t.ourStart.width,\n height: t.ourStart.height\n });\n },\n \n touchEnd: function() {\n // actually, we don't need to do anything here...\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"dot1 dot2\".w(),\n dot1: Dot.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 100, height: 100 }\n }),\n dot2: Dot.design({\n backgroundColor: \"blue\",\n layout: { right: 10, bottom: 10, width: 100, height: 100 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Touch Events"},{"content":"<h1>Multitouch</h1>\n\n<p>Handling single touches is pretty easy&emdash;not that much different from handling\nmouse events. But what about multiple touches?</p>\n\n<h2>Accepting Multiple Touches</h2>\n\n<p>First, you have to tell your view that you do, indeed want to receive multiple\ntouches. By default, views only receive single touches. This is because is easier \nto think in a single-touch model, and most controls only need to track a single touch.</p>\n\n<p>To accept multiple touches, just set the view's <code class='syntax js'><span class=\"variable\">acceptsMultitouch</span></code> property to\n<code class='syntax js'><span class=\"class\">YES</span></code>.</p>\n\n<pre><code class='syntax js'><span class=\"variable\">view</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">acceptsMultitouch</span>: <span class=\"class\">YES</span>\n});\n</code></pre>\n\n<h2>Processing the Individual Touches</h2>\n\n<p>Even without the supplied helper function, processing individual touches is relatively\nsimple:</p>\n\n<ul>\n<li>You get a separate <code class='syntax js'><span class=\"variable\">touchStart</span></code> for each individual touch.</li>\n<li>You get a separate <code class='syntax js'><span class=\"variable\">touchEnd</span></code> for each individual touch.</li>\n<li>You get one <code class='syntax js'><span class=\"variable\">touchesDragged</span></code> each event cycle for all of your touches put together.</li>\n</ul>\n\n<p>So, detecting individual touches starting and ending is simple. Detecting those touches\nmoving is not quite as simple, but still relatively easy.</p>\n\n<p>Remember how <code class='syntax js'><span class=\"variable\">touchesDragged</span></code> works:</p>\n\n<pre><code class='syntax js'><span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>)\n</code></pre>\n\n<p><code class='syntax js'><span class=\"variable\">touches</span></code> is an SC.CoreSet of SC.Touch objects. What can you do with a CoreSet? \nYou can do a couple of things:</p>\n\n<ul>\n<li>Turn it into an array and do whatever.</li>\n<li>Call .forEach to iterate.</li>\n</ul>\n\n<p>But you don't have to use the touches set at all. The <code class='syntax js'><span class=\"variable\">evt</span></code> has some useful properties and methods,\ntoo:</p>\n\n<ul>\n<li>pageX/pageY: the position of the first touch.</li>\n<li>averagedTouchesForView: a method which returns the averaged touch position\nand the average distance of the touches from that position.</li>\n</ul>\n\n<p><code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">ScrollView</span></code>, for instance, makes heavy use of <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code>, and never\ndirectly touches the <code class='syntax js'><span class=\"variable\">touches</span></code> set.</p>\n\n<h2>Averaging Touches</h2>\n\n<p>It is often <em>very</em> useful to average the touches. </p>\n\n<p><code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code> returns an object with four properties:</p>\n\n<ul>\n<li><strong><code class='syntax js'><span class=\"variable\">x</span></code></strong>: The average X position of the touch.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">y</span></code></strong>: The average Y position of the touch.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">d</span></code></strong>: average distance of the all touches from the average x/y position.</li>\n<li><strong><code class='syntax js'><span class=\"variable\">touchCount</span></code></strong> The number of touches averaged.</li>\n</ul>\n\n<p>You can call <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code> on two separate objects: an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Event</span></code> object,\nor an <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code> object.</p>\n\n<p>The two work identically but for one important difference: when you call it on <code class='syntax js'><span class=\"class\">SC</span>.<span class=\"class\">Touch</span></code>,\nyou <em>have the option</em> of telling the touch to add itself to the averaged set. Doing so makes no sense\nin most cases: the touch would just be counted twice! But what about <code class='syntax js'><span class=\"variable\">touchStart</span></code>?</p>\n\n<p>Recall that during <code class='syntax js'><span class=\"variable\">touchStart</span></code>, the view does not yet own the touch. So, <code class='syntax js'><span class=\"variable\">averagedTouchesForView</span></code>\nwould not, by default count it.</p>\n\n<pre><code class='syntax js'><span class=\"comment\">// on an event:</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n\n<span class=\"comment\">// on a touch</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n\n<span class=\"comment\">// on a touch, counting the touch itself</span>\n<span class=\"keyword\">var</span> <span class=\"variable\">a</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>, <span class=\"class\">YES</span>);\n</code></pre>\n\n<h2>Thinking it Over</h2>\n\n<p>How might you use all of these to produce a good result?</p>\n\n<p>Let's take a simple example: moving and resizing something:</p>\n\n<p><a href='multitouch.js' class='demo'>multitouch.js</a></p>","errors":[],"demos":{"multitouch.js":{"ex":"var Box = SC.View.extend({\n _scale: 1,\n _translateX: 0,\n _translateY: 0,\n acceptsMultitouch: YES,\n touchStart: function(touch) {\n this.recomputeTouchStatus(touch, YES);\n return YES;\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n var avg = evt.averagedTouchesForView(this);\n \n // translation is easy:\n this._translateX = t.ourStart.x + avg.x - t.start.x;\n this._translateY = t.ourStart.y + avg.y - t.start.y;\n \n // mathematically speaking, scale *= the end distance / the start distance\n if (t.start.d > 1) { // but prevent divide-by-0\n this._scale = t.ourStart.scale * (avg.d / t.start.d);\n }\n \n // reposition\n this._reposition();\n },\n \n touchEnd: function(touch) {\n this.recomputeTouchStatus(touch, NO);\n },\n \n /**\n With this, we recompute our touch status--updating the start positioning and scale.\n */\n recomputeTouchStatus: function(touch, considerTouch) {\n var avg = touch.averagedTouchesForView(this, considerTouch);\n this._touch = {\n start: { x: avg.x, y: avg.y, d: avg.d },\n ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }\n };\n },\n \n /**\n Repositions the view.\n */\n _reposition: function() {\n this.get(\"layer\").style.webkitTransform = \n \"translate3d(\" + this._translateX + \"px,\" + this._translateY + \"px, 0px) \" +\n \"scale3d(\" + this._scale + \",\" + this._scale + \",1)\";\n console.error(this._translateX + \" \" + this._translateY + \" \" + this._scale);\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"box\".w(),\n box: Box.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 200, height: 200 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">Box</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">_scale</span>: <span class=\"number integer\">1</span>,\n <span class=\"variable\">_translateX</span>: <span class=\"number integer\">0</span>,\n <span class=\"variable\">_translateY</span>: <span class=\"number integer\">0</span>,\n <span class=\"variable\">acceptsMultitouch</span>: <span class=\"class\">YES</span>,\n <span class=\"variable\">touchStart</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">recomputeTouchStatus</span>(<span class=\"variable\">touch</span>, <span class=\"class\">YES</span>);\n <span class=\"keyword\">return</span> <span class=\"class\">YES</span>;\n },\n \n <span class=\"variable\">touchesDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>, <span class=\"variable\">touches</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">t</span> = <span class=\"this\">this</span>.<span class=\"variable\">_touch</span>;\n <span class=\"keyword\">var</span> <span class=\"variable\">avg</span> = <span class=\"variable\">evt</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>);\n \n <span class=\"comment\">// translation is easy:</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">x</span> + <span class=\"variable\">avg</span>.<span class=\"variable\">x</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">x</span>;\n <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">y</span> + <span class=\"variable\">avg</span>.<span class=\"variable\">y</span> - <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">y</span>;\n \n <span class=\"comment\">// mathematically speaking, scale *= the end distance / the start distance</span>\n <span class=\"keyword\">if</span> (<span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">d</span> &gt; <span class=\"number integer\">1</span>) { <span class=\"comment\">// but prevent divide-by-0</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> = <span class=\"variable\">t</span>.<span class=\"variable\">ourStart</span>.<span class=\"variable\">scale</span> * (<span class=\"variable\">avg</span>.<span class=\"variable\">d</span> / <span class=\"variable\">t</span>.<span class=\"variable\">start</span>.<span class=\"variable\">d</span>);\n }\n \n <span class=\"comment\">// reposition</span>\n <span class=\"this\">this</span>.<span class=\"variable\">_reposition</span>();\n },\n \n <span class=\"variable\">touchEnd</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">recomputeTouchStatus</span>(<span class=\"variable\">touch</span>, <span class=\"class\">NO</span>);\n },\n \n <span class=\"multiline comment\">/**\n With this, we recompute our touch status--updating the start positioning and scale.\n */</span>\n <span class=\"variable\">recomputeTouchStatus</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">touch</span>, <span class=\"variable\">considerTouch</span>) {\n <span class=\"keyword\">var</span> <span class=\"variable\">avg</span> = <span class=\"variable\">touch</span>.<span class=\"variable\">averagedTouchesForView</span>(<span class=\"this\">this</span>, <span class=\"variable\">considerTouch</span>);\n <span class=\"this\">this</span>.<span class=\"variable\">_touch</span> = {\n <span class=\"variable\">start</span>: { <span class=\"variable\">x</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">x</span>, <span class=\"variable\">y</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">y</span>, <span class=\"variable\">d</span>: <span class=\"variable\">avg</span>.<span class=\"variable\">d</span> },\n <span class=\"variable\">ourStart</span>: { <span class=\"variable\">x</span>: <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span>, <span class=\"variable\">y</span>: <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span>, <span class=\"variable\">scale</span>: <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> }\n };\n },\n \n <span class=\"multiline comment\">/**\n Repositions the view.\n */</span>\n <span class=\"variable\">_reposition</span>: <span class=\"keyword\">function</span>() {\n <span class=\"this\">this</span>.<span class=\"variable\">get</span>(<span class=\"string\">&quot;layer&quot;</span>).<span class=\"variable\">style</span>.<span class=\"variable\">webkitTransform</span> = \n <span class=\"string\">&quot;translate3d(&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> + <span class=\"string\">&quot;px,&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> + <span class=\"string\">&quot;px, 0px) &quot;</span> +\n <span class=\"string\">&quot;scale3d(&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> + <span class=\"string\">&quot;,&quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span> + <span class=\"string\">&quot;,1)&quot;</span>;\n <span class=\"variable\">console</span>.<span class=\"variable\">error</span>(<span class=\"this\">this</span>.<span class=\"variable\">_translateX</span> + <span class=\"string\">&quot; &quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_translateY</span> + <span class=\"string\">&quot; &quot;</span> + <span class=\"this\">this</span>.<span class=\"variable\">_scale</span>);\n },\n \n <span class=\"comment\">// and now, redirect mouse events :)</span>\n <span class=\"variable\">mouseDown</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchStart</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseDragged</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchesDragged</span>(<span class=\"variable\">evt</span>);\n },\n \n <span class=\"variable\">mouseUp</span>: <span class=\"keyword\">function</span>(<span class=\"variable\">evt</span>) {\n <span class=\"this\">this</span>.<span class=\"variable\">touchEnd</span>(<span class=\"variable\">evt</span>);\n }\n});\n<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;box&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">box</span>: <span class=\"class\">Box</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;red&quot;</span>,\n <span class=\"variable\">layout</span>: { <span class=\"variable\">left</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">top</span>: <span class=\"number integer\">10</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">200</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">200</span> }\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var Box = SC.View.extend({\n _scale: 1,\n _translateX: 0,\n _translateY: 0,\n acceptsMultitouch: YES,\n touchStart: function(touch) {\n this.recomputeTouchStatus(touch, YES);\n return YES;\n },\n \n touchesDragged: function(evt, touches) {\n var t = this._touch;\n var avg = evt.averagedTouchesForView(this);\n \n // translation is easy:\n this._translateX = t.ourStart.x + avg.x - t.start.x;\n this._translateY = t.ourStart.y + avg.y - t.start.y;\n \n // mathematically speaking, scale *= the end distance / the start distance\n if (t.start.d > 1) { // but prevent divide-by-0\n this._scale = t.ourStart.scale * (avg.d / t.start.d);\n }\n \n // reposition\n this._reposition();\n },\n \n touchEnd: function(touch) {\n this.recomputeTouchStatus(touch, NO);\n },\n \n /**\n With this, we recompute our touch status--updating the start positioning and scale.\n */\n recomputeTouchStatus: function(touch, considerTouch) {\n var avg = touch.averagedTouchesForView(this, considerTouch);\n this._touch = {\n start: { x: avg.x, y: avg.y, d: avg.d },\n ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }\n };\n },\n \n /**\n Repositions the view.\n */\n _reposition: function() {\n this.get(\"layer\").style.webkitTransform = \n \"translate3d(\" + this._translateX + \"px,\" + this._translateY + \"px, 0px) \" +\n \"scale3d(\" + this._scale + \",\" + this._scale + \",1)\";\n console.error(this._translateX + \" \" + this._translateY + \" \" + this._scale);\n },\n \n // and now, redirect mouse events :)\n mouseDown: function(evt) {\n this.touchStart(evt);\n },\n \n mouseDragged: function(evt) {\n this.touchesDragged(evt);\n },\n \n mouseUp: function(evt) {\n this.touchEnd(evt);\n }\n});\nvar MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"box\".w(),\n box: Box.design({\n backgroundColor: \"red\",\n layout: { left: 10, top: 10, width: 200, height: 200 }\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Multitouch"}]},{"title":"Built-In Support","articles":[{"content":"<h1>ButtonView Touch Support</h1>\n\n<p>ButtonView currently supports only a single touch (any other touches will be ignored). \nThis is fine: why would you want to consider two touches in a button press?</p>\n\n<p>However, it does not simply relay the touches to <code class='syntax js'><span class=\"variable\">mouseDown</span></code> and <code class='syntax js'><span class=\"variable\">mouseUp</span></code>.</p>\n\n<p>Instead, it calculates the distance of the main touch (<code class='syntax js'><span class=\"variable\">evt</span></code>'s <code class='syntax js'><span class=\"variable\">pageX</span></code> and <code class='syntax js'><span class=\"variable\">pageY</span></code>)\nfrom the button itself. This makes it easier to for a user to press a button while, for instance,\nmoving their finger.</p>\n\n<p>This is all done for you automatically. Here's a simple demo:\n<a href='touch-button.js' class='demo'>touch-button.js</a></p>\n\n<h2>Ace 2.0</h2>\n\n<p>Ace 2.0 supports several button sizes. In addition, it is capable of <em>automatically picking</em>\na size based on the size of your control. And best of all, it <em>centers</em> the button image\nvertically in the space you allocate. This allows you to, for instance, make a button 44px\ntall, but have the image only be 30px.</p>\n\n<p>You may use these options for <code class='syntax js'><span class=\"variable\">controlSize</span></code>:</p>\n\n<ul>\n<li>SC.SMALL_CONTROL_SIZE. 18px.</li>\n<li>SC.REGULAR_CONTROL_SIZE. 24px.</li>\n<li>SC.HUGE_CONTROL_SIZE. 30px.</li>\n<li>SC.JUMBO_CONTROL_SIZE. 44px.</li>\n<li>SC.AUTO_CONTROL_SIZE. Automatically figures a control size (largest that will fit), but\nthrows a warning if you don't have \"height\" set and it has to calculate the size.</li>\n<li>SC.CALCULATED_CONTROL_SIZE. Like AUTO_CONTROL_SIZE, but calculates it.</li>\n</ul>\n\n<p><a href='button-size.js' class='demo'>button-size.js</a></p>","errors":[],"demos":{"touch-button.js":{"ex":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"button\".w(),\n button: SC.ButtonView.design({\n layout: { centerX: 0, centerY: 0, width: 200, height: 44 },\n title: \"Tap Here :)\",\n controlSize: SC.AUTO_CONTROL_SIZE\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;button&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">button</span>: <span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">centerX</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">centerY</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">200</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">44</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;Tap Here :)&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">AUTO_CONTROL_SIZE</span>\n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"button\".w(),\n button: SC.ButtonView.design({\n layout: { centerX: 0, centerY: 0, width: 200, height: 44 },\n title: \"Tap Here :)\",\n controlSize: SC.AUTO_CONTROL_SIZE\n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"},"button-size.js":{"ex":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"form\".w(),\n \n form: SC.FormView.design({\n layout: {centerX: 0, centerY: 0, width: 400, height: 300 },\n childViews: \"small regular huge jumbo\".w(),\n small: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 18 },\n title: \"I'm TINY!\",\n controlSize: SC.SMALL_CONTROL_SIZE\n })),\n \n regular: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 24 },\n title: \"I'm Normal!\",\n controlSize: SC.REGULAR_CONTROL_SIZE\n })),\n \n huge: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 30 },\n title: \"I'm huge.\",\n controlSize: SC.HUGE_CONTROL_SIZE\n })),\n \n jumbo: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 150, height: 44 },\n title: \"i'm jumbo.\",\n controlSize: SC.JUMBO_CONTROL_SIZE\n }))\n \n \n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n","highlighted":"<span class=\"keyword\">var</span> <span class=\"class\">MyExampleView</span> = <span class=\"class\">SC</span>.<span class=\"class\">View</span>.<span class=\"variable\">extend</span>({\n <span class=\"variable\">backgroundColor</span>: <span class=\"string\">&quot;white&quot;</span>,\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;form&quot;</span>.<span class=\"variable\">w</span>(),\n \n <span class=\"variable\">form</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: {<span class=\"variable\">centerX</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">centerY</span>: <span class=\"number integer\">0</span>, <span class=\"variable\">width</span>: <span class=\"number integer\">400</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">300</span> },\n <span class=\"variable\">childViews</span>: <span class=\"string\">&quot;small regular huge jumbo&quot;</span>.<span class=\"variable\">w</span>(),\n <span class=\"variable\">small</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">18</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm TINY!&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">SMALL_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">regular</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">24</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm Normal!&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">REGULAR_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">huge</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">100</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">30</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;I'm huge.&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">HUGE_CONTROL_SIZE</span>\n })),\n \n <span class=\"variable\">jumbo</span>: <span class=\"class\">SC</span>.<span class=\"class\">FormView</span>.<span class=\"variable\">row</span>(<span class=\"class\">SC</span>.<span class=\"class\">ButtonView</span>.<span class=\"variable\">design</span>({\n <span class=\"variable\">layout</span>: { <span class=\"variable\">width</span>: <span class=\"number integer\">150</span>, <span class=\"variable\">height</span>: <span class=\"number integer\">44</span> },\n <span class=\"variable\">title</span>: <span class=\"string\">&quot;i'm jumbo.&quot;</span>,\n <span class=\"variable\">controlSize</span>: <span class=\"class\">SC</span>.<span class=\"class\">JUMBO_CONTROL_SIZE</span>\n }))\n \n \n })\n});\n\n<span class=\"comment\">// bootstrap code :)</span>\n<span class=\"variable\">exports</span>.<span class=\"variable\">getDemoView</span> = <span class=\"keyword\">function</span>() {\n <span class=\"keyword\">return</span> <span class=\"class\">MyExampleView</span>;\n};\n","original":"var MyExampleView = SC.View.extend({\n backgroundColor: \"white\",\n childViews: \"form\".w(),\n \n form: SC.FormView.design({\n layout: {centerX: 0, centerY: 0, width: 400, height: 300 },\n childViews: \"small regular huge jumbo\".w(),\n small: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 18 },\n title: \"I'm TINY!\",\n controlSize: SC.SMALL_CONTROL_SIZE\n })),\n \n regular: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 24 },\n title: \"I'm Normal!\",\n controlSize: SC.REGULAR_CONTROL_SIZE\n })),\n \n huge: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 100, height: 30 },\n title: \"I'm huge.\",\n controlSize: SC.HUGE_CONTROL_SIZE\n })),\n \n jumbo: SC.FormView.row(SC.ButtonView.design({\n layout: { width: 150, height: 44 },\n title: \"i'm jumbo.\",\n controlSize: SC.JUMBO_CONTROL_SIZE\n }))\n \n \n })\n});\n\n// bootstrap code :)\nexports.getDemoView = function() {\n return MyExampleView;\n};\n"}},"articleDirectory":"articles/controls/button/","outputDirectory":"build/","title":"ButtonView Touch Support"},{"content":"<h1>ScrollView Touch Support</h1>","errors":[],"demos":{},"articleDirectory":"articles/controls/scroll/","outputDirectory":"build/","title":"ScrollView Touch Support"}]},{"title":"Advanced Concepts","articles":[{"content":"<h1>Capturing</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Capturing"},{"content":"<h1>Releasing</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Releasing"}]}],"file":"build/guides/touch"}
View
39 docs/src/articles/controls/button/button-size.js
@@ -0,0 +1,39 @@
+var MyExampleView = SC.View.extend({
+ backgroundColor: "white",
+ childViews: "form".w(),
+
+ form: SC.FormView.design({
+ layout: {centerX: 0, centerY: 0, width: 400, height: 300 },
+ childViews: "small regular huge jumbo".w(),
+ small: SC.FormView.row(SC.ButtonView.design({
+ layout: { width: 100, height: 18 },
+ title: "I'm TINY!",
+ controlSize: SC.SMALL_CONTROL_SIZE
+ })),
+
+ regular: SC.FormView.row(SC.ButtonView.design({
+ layout: { width: 100, height: 24 },
+ title: "I'm Normal!",
+ controlSize: SC.REGULAR_CONTROL_SIZE
+ })),
+
+ huge: SC.FormView.row(SC.ButtonView.design({
+ layout: { width: 100, height: 30 },
+ title: "I'm huge.",
+ controlSize: SC.HUGE_CONTROL_SIZE
+ })),
+
+ jumbo: SC.FormView.row(SC.ButtonView.design({
+ layout: { width: 150, height: 44 },
+ title: "i'm jumbo.",
+ controlSize: SC.JUMBO_CONTROL_SIZE
+ }))
+
+
+ })
+});
+
+// bootstrap code :)
+exports.getDemoView = function() {
+ return MyExampleView;
+};
View
14 docs/src/articles/controls/button/touch-button.js
@@ -0,0 +1,14 @@
+var MyExampleView = SC.View.extend({
+ backgroundColor: "white",
+ childViews: "button".w(),
+ button: SC.ButtonView.design({
+ layout: { centerX: 0, centerY: 0, width: 200, height: 44 },
+ title: "Tap Here :)",
+ controlSize: SC.AUTO_CONTROL_SIZE
+ })
+});
+
+// bootstrap code :)
+exports.getDemoView = function() {
+ return MyExampleView;
+};
View
32 docs/src/articles/controls/button/touch.md
@@ -1,2 +1,32 @@
ButtonView Touch Support
-========================
+========================
+ButtonView currently supports only a single touch (any other touches will be ignored).
+This is fine: why would you want to consider two touches in a button press?
+
+However, it does not simply relay the touches to `#js:mouseDown` and `#js:mouseUp`.
+
+Instead, it calculates the distance of the main touch (`#js:evt`'s `#js:pageX` and `#js:pageY`)
+from the button itself. This makes it easier to for a user to press a button while, for instance,
+moving their finger.
+
+This is all done for you automatically. Here's a simple demo:
+{{demo:sc|touch-button.js}}
+
+Ace 2.0
+--------
+Ace 2.0 supports several button sizes. In addition, it is capable of _automatically picking_
+a size based on the size of your control. And best of all, it _centers_ the button image
+vertically in the space you allocate. This allows you to, for instance, make a button 44px
+tall, but have the image only be 30px.
+
+You may use these options for `#js:controlSize`:
+
+- SC.SMALL\_CONTROL\_SIZE. 18px.
+- SC.REGULAR\_CONTROL\_SIZE. 24px.
+- SC.HUGE\_CONTROL\_SIZE. 30px.
+- SC.JUMBO\_CONTROL\_SIZE. 44px.
+- SC.AUTO\_CONTROL\_SIZE. Automatically figures a control size (largest that will fit), but
+ throws a warning if you don't have "height" set and it has to calculate the size.
+- SC.CALCULATED\_CONTROL\_SIZE. Like AUTO\_CONTROL\_SIZE, but calculates it.
+
+{{demo:sc|button-size.js}}

0 comments on commit 15261b8

Please sign in to comment.