Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

More docs, more efficiency, more better.

  • Loading branch information...
commit 7272301d9a193f2f004a7af22df130bbab687165 1 parent a21c640
@ialexi authored
Showing with 1,050 additions and 33 deletions.
  1. +3 −2 apps/hedwig/resources/guide/touch.guide
  2. +1 −1  apps/hedwig/resources/guide/touch.json
  3. +5 −4 apps/hedwig/views/article_view.js
  4. +21 −4 docs/build/articles/touch/a-brief-touch.html
  5. +1 −1  docs/build/articles/touch/a-brief-touch.json
  6. +21 −5 docs/build/articles/touch/a-brief-touch.md
  7. +189 −0 docs/build/articles/touch/multitouch.html
  8. +78 −0 docs/build/articles/touch/multitouch.js
  9. +1 −0  docs/build/articles/touch/multitouch.json
  10. +94 −0 docs/build/articles/touch/multitouch.md
  11. +17 −0 docs/build/articles/touch/touch-demo.js
  12. +115 −0 docs/build/articles/touch/touch-events.html
  13. +1 −1  docs/build/articles/touch/touch-events.json
  14. +113 −1 docs/build/articles/touch/touch-events.md
  15. +3 −2 docs/build/guides/touch.guide
  16. +1 −1  docs/build/guides/touch.json
  17. +21 −5 docs/src/articles/touch/a-brief-touch.md
  18. +78 −0 docs/src/articles/touch/multitouch.js
  19. +94 −0 docs/src/articles/touch/multitouch.md
  20. +17 −0 docs/src/articles/touch/touch-demo.js
  21. +113 −1 docs/src/articles/touch/touch-events.md
  22. +3 −2 docs/src/guides/touch.guide
  23. BIN  themes/pig/resources/images/2.png
  24. +31 −2 themes/pig/resources/theme.css
  25. +24 −0 themes/pig/src/content.css
  26. +4 −0 themes/pig/src/paper/paper.css
  27. BIN  themes/pig/src/tree/bg.jpg
  28. +1 −1  themes/pig/src/tree/tree.css
View
5 apps/hedwig/resources/guide/touch.guide
@@ -1,11 +1,12 @@
{
- "title": "Writing Touch Applications",
+ "title": "Touch Application Guide",
"sections": [
{
"title": "Introduction",
"articles": [
"articles/touch/a-brief-touch",
- "articles/touch/touch-events"
+ "articles/touch/touch-events",
+ "articles/touch/multitouch"
]
},
{
View
2  apps/hedwig/resources/guide/touch.json
@@ -1 +1 @@
-{"title":"Writing Touch Applications","sections":[{"title":"Introduction","articles":[{"content":"<h1>A Brief Touch on Touches</h1>\n\n<p>Some text goes here.</p>\n\n<p>Note that links like the below must appear on empty lines with no preceding whitespace.</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});\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=\"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});\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":"A Brief Touch on Touches","any":"metadata","goes":"Here","damn":"gruber","this":"is still eye-readable","and":"He is wrong about touch apps."},{"content":"<h1>Touch Events</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Touch Events"}]},{"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>","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"}
View
9 apps/hedwig/views/article_view.js
@@ -4,7 +4,7 @@ Hedwig.ArticleView = SC.View.extend(Hedwig.TouchHelper, {
mouseDown: function(evt) {
this._mouseStart = { x: evt.pageX, y: evt.pageY };
- return YES;
+ return NO;
},
mouseUp: function(evt) {
@@ -52,9 +52,9 @@ Hedwig.ArticleView = SC.View.extend(Hedwig.TouchHelper, {
borderStyle: SC.BORDER_NONE,
contentView: SC.StaticContentView.design({
contentBinding: "Hedwig.articleController.html",
- contentDidChange: function() {
+ didUpdateLayer: function() {
sc_super();
- this.invokeLater("processContent", 1);
+ this.processContent();
}.observes("content"),
processContent: function() {
@@ -65,7 +65,7 @@ Hedwig.ArticleView = SC.View.extend(Hedwig.TouchHelper, {
touchStart: function(touch) { return this.mouseDown(touch); },
mouseDown: function(evt) {
- evt.preventDefault();
+
var el = document.elementFromPoint(evt.pageX, evt.pageY), demoNode = null;
while (el) {
@@ -79,6 +79,7 @@ Hedwig.ArticleView = SC.View.extend(Hedwig.TouchHelper, {
if (demoNode) {
Hedwig.sendAction("openDemo", demoNode.getAttribute("href"));
+ evt.preventDefault();
return YES;
}
View
25 docs/build/articles/touch/a-brief-touch.html
@@ -88,11 +88,28 @@
</style>
</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>A Brief Touch on Touches</h1>
+</a></div><div class="content"><h1>A Brief Touch</h1>
-<p>Some text goes here.</p>
+<p>It is very possible to build <em>awesome</em> touch-enabled applications in SproutCore.</p>
-<p>Note that links like the below must appear on empty lines with no preceding whitespace.</p>
+<p>But, what makes an awesome touch-enabled application? Sure, it must accept touches,
+but with SproutCore's (constantly growing) touch support, this is now pretty easy:
+many existing interfaces, if built with newer SproutCore varieties, will function fine (or mostly fine),
+on both larger-screened touch devices (such as iPad) and the traditional desktop environment.</p>
-<p><a href='touch-demo.js' class='demo'>touch-demo.js</a></p>
+<p>But there are many differences between desktop and touch platforms:</p>
+
+<ul>
+<li><strong>Precision.</strong> Touches are less precise than clicks. To compensate, controls should be larger.</li>
+<li><strong>Performance.</strong> Touch-based devices tend to be slow (for now). To get around this just takes
+some elbow grease: there are many techniques to speed things up... many of which SproutCore will
+handle for you.</li>
+<li><strong>Animation.</strong> Lack of animation looks okay on desktop (even if animation is cool)... but on
+touch devices, non-animated interfaces look strange: touch is so much more realistic than mouse,
+but sudden changes without transitions are not realistic at all.</li>
+<li><strong>Coolness.</strong> Touch-based interfaces are cool. That is all.</li>
+</ul>
+
+<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
+your own meaning of "coolness".</p>
</div><div class="footer"></div></body></html>
View
2  docs/build/articles/touch/a-brief-touch.json
@@ -1 +1 @@
-{"content":"<h1>A Brief Touch on Touches</h1>\n\n<p>Some text goes here.</p>\n\n<p>Note that links like the below must appear on empty lines with no preceding whitespace.</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});\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=\"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});\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":"A Brief Touch on Touches","any":"metadata","goes":"Here","damn":"gruber","this":"is still eye-readable","and":"He is wrong about touch apps."}
+{"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."}
View
26 docs/build/articles/touch/a-brief-touch.md
@@ -6,10 +6,26 @@
"and": "He is wrong about touch apps."
}
-A Brief Touch on Touches
-========================
-Some text goes here.
+A Brief Touch
+=============
-Note that links like the below must appear on empty lines with no preceding whitespace.
+It is very possible to build _awesome_ touch-enabled applications in SproutCore.
-{{demo:sc|touch-demo.js}}
+But, what makes an awesome touch-enabled application? Sure, it must accept touches,
+but with SproutCore's (constantly growing) touch support, this is now pretty easy:
+many existing interfaces, if built with newer SproutCore varieties, will function fine (or mostly fine),
+on both larger-screened touch devices (such as iPad) and the traditional desktop environment.
+
+But there are many differences between desktop and touch platforms:
+
+- **Precision.** Touches are less precise than clicks. To compensate, controls should be larger.
+- **Performance.** Touch-based devices tend to be slow (for now). To get around this just takes
+ some elbow grease: there are many techniques to speed things up... many of which SproutCore will
+ handle for you.
+- **Animation.** Lack of animation looks okay on desktop (even if animation is cool)... but on
+ touch devices, non-animated interfaces look strange: touch is so much more realistic than mouse,
+ but sudden changes without transitions are not realistic at all.
+- **Coolness.** Touch-based interfaces are cool. That is all.
+
+In this guide, we go over each of these—except for the last, which is rather vague; you'll have to figure out
+your own meaning of "coolness".
View
189 docs/build/articles/touch/multitouch.html
@@ -0,0 +1,189 @@
+<html><head><title>Docs
+</title><meta http-equiv: 'Content-Type' content="text/html; charset=utf-8" />
+<style type="text/css">
+ body {
+ font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif;
+ margin: 0px;
+ margin-bottom:1em;
+ font-family: sans-serif;
+ font-size: 10px;
+ line-height:1.2;
+ }
+
+ .content { font-size: 14px; }
+
+ code {
+ font-family: Monaco, Inconsolata, Courier, fixed-width;
+ font-size: 12px;
+ }
+
+ pre code {
+ margin-right: 1em;
+ border: 1px solid #a0b0a0;
+ overflow-y: hidden;
+ overflow-x: auto;
+ background: #f5f9f5;
+ display:block;
+ padding: 1em;
+ }
+
+ a { text-decoration: none; color: rgb(50, 50, 155); }
+
+
+ .header {
+ background-color: rgb(38, 43, 50);
+ height: 60px;
+ padding-top:17px;
+ padding-bottom:17px;
+ padding-left:2em;
+ }
+
+ .header a.img {
+ float: left;
+ }
+
+ .header .here {
+ float:left;
+ margin-top:27px;
+ margin-left:5px;
+ color: rgb(200, 255, 200);
+ font-size: 25px;
+ }
+
+ .header span.here {
+ margin-top:34px;
+ font-size:15px;
+ color: white;
+ }
+
+ .header a.item {
+ float:right;
+ margin-top: 34px;
+ margin-right:10px;
+ color: white;
+ font-size:15px;
+ }
+
+ .header a.item:hover {
+ text-decoration: underline;
+ }
+
+ .content {
+ padding-top: 1em;
+ padding-left: 2em;
+ padding-right: 2em;
+ }
+
+ img { margin-left: auto; margin-right: auto; display: block; }
+
+
+ h1, h2, h3 { color: rgb(100, 155, 100); }
+
+ code .class { color: rgb(0, 0, 150); }
+ /*code .variable { color: rgb(10, 70, 10); }*/
+ code .comment { color: rgb(100, 150, 200); }
+ code .string { color: rgb(0, 100, 10); }
+ code .number { color: rgb(0, 0, 255); }
+ code .keyword, code .this { color: rgb(25, 110, 25); font-weight: bold; }
+</style>
+</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>Multitouch</h1>
+
+<p>Handling single touches is pretty easy&emdash;not that much different from handling
+mouse events. But what about multiple touches?</p>
+
+<h2>Accepting Multiple Touches</h2>
+
+<p>First, you have to tell your view that you do, indeed want to receive multiple
+touches. By default, views only receive single touches. This is because is easier
+to think in a single-touch model, and most controls only need to track a single touch.</p>
+
+<p>To accept multiple touches, just set the view's <code class='syntax js'><span class="variable">acceptsMultitouch</span></code> property to
+<code class='syntax js'><span class="class">YES</span></code>.</p>
+
+<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>({
+ <span class="variable">acceptsMultitouch</span>: <span class="class">YES</span>
+});
+</code></pre>
+
+<h2>Processing the Individual Touches</h2>
+
+<p>Even without the supplied helper function, processing individual touches is relatively
+simple:</p>
+
+<ul>
+<li>You get a separate <code class='syntax js'><span class="variable">touchStart</span></code> for each individual touch.</li>
+<li>You get a separate <code class='syntax js'><span class="variable">touchEnd</span></code> for each individual touch.</li>
+<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>
+</ul>
+
+<p>So, detecting individual touches starting and ending is simple. Detecting those touches
+moving is not quite as simple, but still relatively easy.</p>
+
+<p>Remember how <code class='syntax js'><span class="variable">touchesDragged</span></code> works:</p>
+
+<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>)
+</code></pre>
+
+<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?
+You can do a couple of things:</p>
+
+<ul>
+<li>Turn it into an array and do whatever.</li>
+<li>Call .forEach to iterate.</li>
+</ul>
+
+<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,
+too:</p>
+
+<ul>
+<li>pageX/pageY: the position of the first touch.</li>
+<li>averagedTouchesForView: a method which returns the averaged touch position
+and the average distance of the touches from that position.</li>
+</ul>
+
+<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
+directly touches the <code class='syntax js'><span class="variable">touches</span></code> set.</p>
+
+<h2>Averaging Touches</h2>
+
+<p>It is often <em>very</em> useful to average the touches. </p>
+
+<p><code class='syntax js'><span class="variable">averagedTouchesForView</span></code> returns an object with four properties:</p>
+
+<ul>
+<li><strong><code class='syntax js'><span class="variable">x</span></code></strong>: The average X position of the touch.</li>
+<li><strong><code class='syntax js'><span class="variable">y</span></code></strong>: The average Y position of the touch.</li>
+<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>
+<li><strong><code class='syntax js'><span class="variable">touchCount</span></code></strong> The number of touches averaged.</li>
+</ul>
+
+<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,
+or an <code class='syntax js'><span class="class">SC</span>.<span class="class">Touch</span></code> object.</p>
+
+<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>,
+you <em>have the option</em> of telling the touch to add itself to the averaged set. Doing so makes no sense
+in most cases: the touch would just be counted twice! But what about <code class='syntax js'><span class="variable">touchStart</span></code>?</p>
+
+<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>
+would not, by default count it.</p>
+
+<pre><code class='syntax js'><span class="comment">// on an event:</span>
+<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>);
+
+<span class="comment">// on a touch</span>
+<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="comment">// on a touch, counting the touch itself</span>
+<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>);
+</code></pre>
+
+<h2>Thinking it Over</h2>
+
+<p>How might you use all of these to produce a good result?</p>
+
+<p>Let's take a simple example: moving and resizing something:</p>
+
+<p><a href='multitouch.js' class='demo'>multitouch.js</a></p>
+</div><div class="footer"></div></body></html>
View
78 docs/build/articles/touch/multitouch.js
@@ -0,0 +1,78 @@
+var Box = SC.View.extend({
+ _scale: 1,
+ _translateX: 0,
+ _translateY: 0,
+ acceptsMultitouch: YES,
+ touchStart: function(touch) {
+ this.recomputeTouchStatus(touch, YES);
+ return YES;
+ },
+
+ touchesDragged: function(evt, touches) {
+ var t = this._touch;
+ var avg = evt.averagedTouchesForView(this);
+
+ // translation is easy:
+ this._translateX = t.ourStart.x + avg.x - t.start.x;
+ this._translateY = t.ourStart.y + avg.y - t.start.y;
+
+ // mathematically speaking, scale *= the end distance / the start distance
+ if (t.start.d > 1) { // but prevent divide-by-0
+ this._scale = t.ourStart.scale * (avg.d / t.start.d);
+ }
+
+ // reposition
+ this._reposition();
+ },
+
+ touchEnd: function(touch) {
+ this.recomputeTouchStatus(touch, NO);
+ },
+
+ /**
+ With this, we recompute our touch status--updating the start positioning and scale.
+ */
+ recomputeTouchStatus: function(touch, considerTouch) {
+ var avg = touch.averagedTouchesForView(this, considerTouch);
+ this._touch = {
+ start: { x: avg.x, y: avg.y, d: avg.d },
+ ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }
+ };
+ },
+
+ /**
+ Repositions the view.
+ */
+ _reposition: function() {
+ this.get("layer").style.webkitTransform =
+ "translate3d(" + this._translateX + "px," + this._translateY + "px, 0px) " +
+ "scale3d(" + this._scale + "," + this._scale + ",1)";
+ console.error(this._translateX + " " + this._translateY + " " + this._scale);
+ },
+
+ // and now, redirect mouse events :)
+ mouseDown: function(evt) {
+ this.touchStart(evt);
+ },
+
+ mouseDragged: function(evt) {
+ this.touchesDragged(evt);
+ },
+
+ mouseUp: function(evt) {
+ this.touchEnd(evt);
+ }
+});
+var MyExampleView = SC.View.extend({
+ backgroundColor: "white",
+ childViews: "box".w(),
+ box: Box.design({
+ backgroundColor: "red",
+ layout: { left: 10, top: 10, width: 200, height: 200 }
+ })
+});
+
+// bootstrap code :)
+exports.getDemoView = function() {
+ return MyExampleView;
+};
View
1  docs/build/articles/touch/multitouch.json
@@ -0,0 +1 @@
+{"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"}
View
94 docs/build/articles/touch/multitouch.md
@@ -0,0 +1,94 @@
+Multitouch
+===========
+Handling single touches is pretty easy—not that much different from handling
+mouse events. But what about multiple touches?
+
+Accepting Multiple Touches
+---------------------------
+First, you have to tell your view that you do, indeed want to receive multiple
+touches. By default, views only receive single touches. This is because is easier
+to think in a single-touch model, and most controls only need to track a single touch.
+
+To accept multiple touches, just set the view's `#js:acceptsMultitouch` property to
+`#js:YES`.
+
+ #js
+ view = SC.View.extend({
+ acceptsMultitouch: YES
+ });
+
+Processing the Individual Touches
+-----------------------------------
+Even without the supplied helper function, processing individual touches is relatively
+simple:
+
+- You get a separate `#js:touchStart` for each individual touch.
+- You get a separate `#js:touchEnd` for each individual touch.
+- You get one `#js:touchesDragged` each event cycle for all of your touches put together.
+
+So, detecting individual touches starting and ending is simple. Detecting those touches
+moving is not quite as simple, but still relatively easy.
+
+Remember how `#js:touchesDragged` works:
+
+ #js
+ touchesDragged: function(evt, touches)
+
+`#js:touches` is an SC.CoreSet of SC.Touch objects. What can you do with a CoreSet?
+You can do a couple of things:
+
+- Turn it into an array and do whatever.
+- Call .forEach to iterate.
+
+But you don't have to use the touches set at all. The `#js:evt` has some useful properties and methods,
+too:
+
+- pageX/pageY: the position of the first touch.
+- averagedTouchesForView: a method which returns the averaged touch position
+ and the average distance of the touches from that position.
+
+`#js:SC.ScrollView`, for instance, makes heavy use of `#js:averagedTouchesForView`, and never
+directly touches the `#js:touches` set.
+
+
+Averaging Touches
+------------------
+It is often _very_ useful to average the touches.
+
+`#js:averagedTouchesForView` returns an object with four properties:
+
+- **`#js:x`**: The average X position of the touch.
+- **`#js:y`**: The average Y position of the touch.
+- **`#js:d`**: average distance of the all touches from the average x/y position.
+- **`#js:touchCount`** The number of touches averaged.
+
+You can call `#js:averagedTouchesForView` on two separate objects: an `#js:SC.Event` object,
+or an `#js:SC.Touch` object.
+
+The two work identically but for one important difference: when you call it on `#js:SC.Touch`,
+you _have the option_ of telling the touch to add itself to the averaged set. Doing so makes no sense
+in most cases: the touch would just be counted twice! But what about `#js:touchStart`?
+
+Recall that during `#js:touchStart`, the view does not yet own the touch. So, `#js:averagedTouchesForView`
+would not, by default count it.
+
+ #js
+ // on an event:
+ var a = evt.averagedTouchesForView(this);
+
+ // on a touch
+ var a = touch.averagedTouchesForView(this);
+
+ // on a touch, counting the touch itself
+ var a = touch.averagedTouchesForView(this, YES);
+
+Thinking it Over
+------------------
+How might you use all of these to produce a good result?
+
+Let's take a simple example: moving and resizing something:
+
+{{demo:sc|multitouch.js}}
+
+
+
View
17 docs/build/articles/touch/touch-demo.js
@@ -16,6 +16,23 @@ var Dot = SC.View.extend({
width: t.ourStart.width,
height: t.ourStart.height
});
+ },
+
+ touchEnd: function() {
+ // actually, we don't need to do anything here...
+ },
+
+ // and now, redirect mouse events :)
+ mouseDown: function(evt) {
+ this.touchStart(evt);
+ },
+
+ mouseDragged: function(evt) {
+ this.touchesDragged(evt);
+ },
+
+ mouseUp: function(evt) {
+ this.touchEnd(evt);
}
});
var MyExampleView = SC.View.extend({
View
115 docs/build/articles/touch/touch-events.html
@@ -89,4 +89,119 @@
</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>Touch Events</h1>
+
+<p>SproutCore's touch events have a few great features:</p>
+
+<ul>
+<li>Multiple views can receive touches simultaneously.</li>
+<li>A single view can receive multiple touches.</li>
+<li>A view can capture touches before allowing them to pass through to children.</li>
+<li>Child views can release touches back to parent views that originally captured them.</li>
+</ul>
+
+<p>We won't get into the last two in this article&emdash;they're quite sophisticated!</p>
+
+<h1>Simple Single-Touch Handling</h1>
+
+<p>You may be familiar with this SC.View method signature if you are familiar with SproutCore:</p>
+
+<pre><code class='syntax js'><span class="variable">mouseDown</span>: <span class="keyword">function</span>(<span class="variable">evt</span>)
+</code></pre>
+
+<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
+<code class='syntax js'><span class="class">YES</span></code> or <code class='syntax js'><span class="class">NO</span></code>.</p>
+
+<p>Touch events are similar, but work a bit differently:</p>
+
+<pre><code class='syntax js'><span class="variable">touchStart</span>: <span class="keyword">function</span>(<span class="variable">touch</span>)
+</code></pre>
+
+<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.
+If you return YES from touchStart, your view will "own" the touch—in SproutCore terms, your
+view will be the <em>touch responder</em>. For more information about what this entails, see
+the "Internals" article. Your view will own the touch until the touch ends.</p>
+
+<p><code class='syntax js'><span class="variable">touchStart</span></code> will be called once for every touch that touches the view.</p>
+
+<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
+a 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>
+property—actually, SC.View uses the same property name! See the "Multitouch" article.</p>
+
+<h2>Anatomy of an SC.Touch</h2>
+
+<p>SC.Touch represents the touch from the time the user puts their finger on the screen until the time they lift it.</p>
+
+<p>The touch object acts like an event object in many ways. It has many other useful things, as well:</p>
+
+<ul>
+<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>
+<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>.
+You will probably never need to access this.</li>
+<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>
+<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
+touch 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>
+<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,
+returning both an average position and an average distance from that position.</li>
+</ul>
+
+<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
+returned 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>
+
+<h2>touchEnd</h2>
+
+<p>Knowing when the touch starts is not very useful. At the very least, you will likely want to know when the touch
+ends as well.</p>
+
+<p>It is quite simple:</p>
+
+<pre><code class='syntax js'><span class="variable">touchEnd</span>: <span class="keyword">function</span>(<span class="variable">touch</span>)
+</code></pre>
+
+<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,
+so 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
+view does not accept multitouch, then the set is guaranteed to have no touches in it—you only receive
+<code class='syntax js'><span class="variable">touchEnd</span></code> for the last touch that ends.</p>
+
+<h2>Tracking Touches</h2>
+
+<p>Tracking touch movement is simple:</p>
+
+<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>)
+</code></pre>
+
+<p>The <code class='syntax js'><span class="variable">touches</span></code> argument is the set of touches on the view—the same set you get by calling <code class='syntax js'><span class="variable">touchesForView</span>(<span class="this">this</span>)</code>.
+This will have <em>all</em> touches, regardless of whether or not your view accepts multitouch.</p>
+
+<p>If your view does <em>not</em> accept multitouch, then it is even simpler:</p>
+
+<pre><code class='syntax js'><span class="variable">x</span> = <span class="variable">evt</span>.<span class="variable">pageX</span>;
+<span class="variable">y</span> = <span class="variable">evt</span>.<span class="variable">pageY</span>;
+</code></pre>
+
+<h2>Tip: Cross-Platform-iness</h2>
+
+<p>Did you realize that, assuming you don't use the set of view touches or other touch-specific API,
+you can do this:</p>
+
+<pre><code class='syntax js'><span class="variable">mouseDown</span>: <span class="keyword">function</span>(<span class="variable">evt</span>) {
+ <span class="this">this</span>.<span class="variable">touchStart</span>(<span class="variable">evt</span>);
+},
+
+<span class="variable">mouseDragged</span>: <span class="keyword">function</span>(<span class="variable">evt</span>) {
+ <span class="this">this</span>.<span class="variable">touchesDragged</span>(<span class="variable">evt</span>);
+},
+
+<span class="variable">mouseUp</span>: <span class="keyword">function</span>(<span class="variable">evt</span>) {
+ <span class="this">this</span>.<span class="variable">touchEnd</span>(<span class="variable">evt</span>);
+}
+</code></pre>
+
+<p>Of course, you can also redirect touch events to mouse events, but that is not as fun.</p>
+
+<h2>Putting it All Together</h2>
+
+<p>Here is a very simple demo that uses the methods described above to allow the user to move two views
+around the screen:</p>
+
+<p><a href='touch-demo.js' class='demo'>touch-demo.js</a></p>
</div><div class="footer"></div></body></html>
View
2  docs/build/articles/touch/touch-events.json
@@ -1 +1 @@
-{"content":"<h1>Touch Events</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Touch Events"}
+{"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"}
View
114 docs/build/articles/touch/touch-events.md
@@ -1,2 +1,114 @@
Touch Events
-=============
+=============
+
+SproutCore's touch events have a few great features:
+
+- Multiple views can receive touches simultaneously.
+- A single view can receive multiple touches.
+- A view can capture touches before allowing them to pass through to children.
+- Child views can release touches back to parent views that originally captured them.
+
+We won't get into the last two in this article—they're quite sophisticated!
+
+Simple Single-Touch Handling
+=====================================================
+You may be familiar with this SC.View method signature if you are familiar with SproutCore:
+
+ #js
+ mouseDown: function(evt)
+
+With `#js:mouseDown`, you can decide whether or not to accept the mouse event by returning either
+`#js:YES` or `#js:NO`.
+
+Touch events are similar, but work a bit differently:
+
+ #js
+ touchStart: function(touch)
+
+Instead of being passed a raw event, `#js:touchStart` is passed an `#js:SC.Touch` object.
+If you return YES from touchStart, your view will "own" the touch—in SproutCore terms, your
+view will be the _touch responder_. For more information about what this entails, see
+the "Internals" article. Your view will own the touch until the touch ends.
+
+`#js:touchStart` will be called once for every touch that touches the view.
+
+**Note:** By default, views only receive `#js:touchStart` and touchEnd for a single touch. This is
+a feature intended to make it easier to handle such cases, very similar to Cocoa Touch's `#js:acceptsMultitouch`
+property—actually, SC.View uses the same property name! See the "Multitouch" article.
+
+Anatomy of an SC.Touch
+------------------------
+SC.Touch represents the touch from the time the user puts their finger on the screen until the time they lift it.
+
+The touch object acts like an event object in many ways. It has many other useful things, as well:
+
+- `#js:pageX` and `#js:pageY` for the touch
+- `#js:event`: if in an event cycle, this contains the event. Otherwise, it is `#js:undefined`.
+ You will probably never need to access this.
+- `#js:preventDefault`: if the touch is connected with an event, this calls `#js:preventDefault()` on the event.
+- `#js:touchesForView(view)`: when supplied a view, will find all touches that the view is the
+ touch responder for. It is a CoreSet; to get an array, call `#js:.toArray` on the result.
+- `#js:averagedTouchesForView(view)`: When supplied a view, averages all the touches on that view,
+ returning both an average position and an average distance from that position.
+
+**Note:** If you call `#js:touchesForView(this)` from `#js:touchStart`, the touch supplied will not be in the set
+returned by `#js:touchesForView(this)`: you don't own the touch until you return YES.
+
+touchEnd
+-----------------
+Knowing when the touch starts is not very useful. At the very least, you will likely want to know when the touch
+ends as well.
+
+It is quite simple:
+
+ #js
+ touchEnd: function(touch)
+
+It works exactly like `#js:touchStart`. The touch will no longer be in the set of touches for the view,
+so if you call `#js:touch.touchesForView(this)`, you'll only receive any other active touches. If your
+view does not accept multitouch, then the set is guaranteed to have no touches in it—you only receive
+`#js:touchEnd` for the last touch that ends.
+
+Tracking Touches
+------------------
+Tracking touch movement is simple:
+
+ #js
+ touchesDragged: function(evt, touches)
+
+The `#js:touches` argument is the set of touches on the view—the same set you get by calling `#js:touchesForView(this)`.
+This will have _all_ touches, regardless of whether or not your view accepts multitouch.
+
+If your view does _not_ accept multitouch, then it is even simpler:
+
+ #js
+ x = evt.pageX;
+ y = evt.pageY;
+
+Tip: Cross-Platform-iness
+--------------------------
+Did you realize that, assuming you don't use the set of view touches or other touch-specific API,
+you can do this:
+
+ #js
+ mouseDown: function(evt) {
+ this.touchStart(evt);
+ },
+
+ mouseDragged: function(evt) {
+ this.touchesDragged(evt);
+ },
+
+ mouseUp: function(evt) {
+ this.touchEnd(evt);
+ }
+
+Of course, you can also redirect touch events to mouse events, but that is not as fun.
+
+Putting it All Together
+------------------------
+Here is a very simple demo that uses the methods described above to allow the user to move two views
+around the screen:
+
+{{demo:sc|touch-demo.js}}
+
View
5 docs/build/guides/touch.guide
@@ -1,11 +1,12 @@
{
- "title": "Writing Touch Applications",
+ "title": "Touch Application Guide",
"sections": [
{
"title": "Introduction",
"articles": [
"articles/touch/a-brief-touch",
- "articles/touch/touch-events"
+ "articles/touch/touch-events",
+ "articles/touch/multitouch"
]
},
{
View
2  docs/build/guides/touch.json
@@ -1 +1 @@
-{"title":"Writing Touch Applications","sections":[{"title":"Introduction","articles":[{"content":"<h1>A Brief Touch on Touches</h1>\n\n<p>Some text goes here.</p>\n\n<p>Note that links like the below must appear on empty lines with no preceding whitespace.</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});\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=\"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});\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":"A Brief Touch on Touches","any":"metadata","goes":"Here","damn":"gruber","this":"is still eye-readable","and":"He is wrong about touch apps."},{"content":"<h1>Touch Events</h1>","errors":[],"demos":{},"articleDirectory":"articles/touch/","outputDirectory":"build/","title":"Touch Events"}]},{"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>","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"}
View
26 docs/src/articles/touch/a-brief-touch.md
@@ -6,10 +6,26 @@
"and": "He is wrong about touch apps."
}
-A Brief Touch on Touches
-========================
-Some text goes here.
+A Brief Touch
+=============
-Note that links like the below must appear on empty lines with no preceding whitespace.
+It is very possible to build _awesome_ touch-enabled applications in SproutCore.
-{{demo:sc|touch-demo.js}}
+But, what makes an awesome touch-enabled application? Sure, it must accept touches,
+but with SproutCore's (constantly growing) touch support, this is now pretty easy:
+many existing interfaces, if built with newer SproutCore varieties, will function fine (or mostly fine),
+on both larger-screened touch devices (such as iPad) and the traditional desktop environment.
+
+But there are many differences between desktop and touch platforms:
+
+- **Precision.** Touches are less precise than clicks. To compensate, controls should be larger.
+- **Performance.** Touch-based devices tend to be slow (for now). To get around this just takes
+ some elbow grease: there are many techniques to speed things up... many of which SproutCore will
+ handle for you.
+- **Animation.** Lack of animation looks okay on desktop (even if animation is cool)... but on
+ touch devices, non-animated interfaces look strange: touch is so much more realistic than mouse,
+ but sudden changes without transitions are not realistic at all.
+- **Coolness.** Touch-based interfaces are cool. That is all.
+
+In this guide, we go over each of these—except for the last, which is rather vague; you'll have to figure out
+your own meaning of "coolness".
View
78 docs/src/articles/touch/multitouch.js
@@ -0,0 +1,78 @@
+var Box = SC.View.extend({
+ _scale: 1,
+ _translateX: 0,
+ _translateY: 0,
+ acceptsMultitouch: YES,
+ touchStart: function(touch) {
+ this.recomputeTouchStatus(touch, YES);
+ return YES;
+ },
+
+ touchesDragged: function(evt, touches) {
+ var t = this._touch;
+ var avg = evt.averagedTouchesForView(this);
+
+ // translation is easy:
+ this._translateX = t.ourStart.x + avg.x - t.start.x;
+ this._translateY = t.ourStart.y + avg.y - t.start.y;
+
+ // mathematically speaking, scale *= the end distance / the start distance
+ if (t.start.d > 1) { // but prevent divide-by-0
+ this._scale = t.ourStart.scale * (avg.d / t.start.d);
+ }
+
+ // reposition
+ this._reposition();
+ },
+
+ touchEnd: function(touch) {
+ this.recomputeTouchStatus(touch, NO);
+ },
+
+ /**
+ With this, we recompute our touch status--updating the start positioning and scale.
+ */
+ recomputeTouchStatus: function(touch, considerTouch) {
+ var avg = touch.averagedTouchesForView(this, considerTouch);
+ this._touch = {
+ start: { x: avg.x, y: avg.y, d: avg.d },
+ ourStart: { x: this._translateX, y: this._translateY, scale: this._scale }
+ };
+ },
+
+ /**
+ Repositions the view.
+ */
+ _reposition: function() {
+ this.get("layer").style.webkitTransform =
+ "translate3d(" + this._translateX + "px," + this._translateY + "px, 0px) " +
+ "scale3d(" + this._scale + "," + this._scale + ",1)";
+ console.error(this._translateX + " " + this._translateY + " " + this._scale);
+ },
+
+ // and now, redirect mouse events :)
+ mouseDown: function(evt) {
+ this.touchStart(evt);
+ },
+
+ mouseDragged: function(evt) {
+ this.touchesDragged(evt);
+ },
+
+ mouseUp: function(evt) {
+ this.touchEnd(evt);
+ }
+});
+var MyExampleView = SC.View.extend({
+ backgroundColor: "white",
+ childViews: "box".w(),
+ box: Box.design({
+ backgroundColor: "red",
+ layout: { left: 10, top: 10, width: 200, height: 200 }
+ })
+});
+
+// bootstrap code :)
+exports.getDemoView = function() {
+ return MyExampleView;
+};
View
94 docs/src/articles/touch/multitouch.md
@@ -0,0 +1,94 @@
+Multitouch
+===========
+Handling single touches is pretty easy—not that much different from handling
+mouse events. But what about multiple touches?
+
+Accepting Multiple Touches
+---------------------------
+First, you have to tell your view that you do, indeed want to receive multiple
+touches. By default, views only receive single touches. This is because is easier
+to think in a single-touch model, and most controls only need to track a single touch.
+
+To accept multiple touches, just set the view's `#js:acceptsMultitouch` property to
+`#js:YES`.
+
+ #js
+ view = SC.View.extend({
+ acceptsMultitouch: YES
+ });
+
+Processing the Individual Touches
+-----------------------------------
+Even without the supplied helper function, processing individual touches is relatively
+simple:
+
+- You get a separate `#js:touchStart` for each individual touch.
+- You get a separate `#js:touchEnd` for each individual touch.
+- You get one `#js:touchesDragged` each event cycle for all of your touches put together.
+
+So, detecting individual touches starting and ending is simple. Detecting those touches
+moving is not quite as simple, but still relatively easy.
+
+Remember how `#js:touchesDragged` works:
+
+ #js
+ touchesDragged: function(evt, touches)
+
+`#js:touches` is an SC.CoreSet of SC.Touch objects. What can you do with a CoreSet?
+You can do a couple of things:
+
+- Turn it into an array and do whatever.
+- Call .forEach to iterate.
+
+But you don't have to use the touches set at all. The `#js:evt` has some useful properties and methods,
+too:
+
+- pageX/pageY: the position of the first touch.
+- averagedTouchesForView: a method which returns the averaged touch position
+ and the average distance of the touches from that position.
+
+`#js:SC.ScrollView`, for instance, makes heavy use of `#js:averagedTouchesForView`, and never
+directly touches the `#js:touches` set.
+
+
+Averaging Touches
+------------------
+It is often _very_ useful to average the touches.
+
+`#js:averagedTouchesForView` returns an object with four properties:
+
+- **`#js:x`**: The average X position of the touch.
+- **`#js:y`**: The average Y position of the touch.
+- **`#js:d`**: average distance of the all touches from the average x/y position.
+- **`#js:touchCount`** The number of touches averaged.
+
+You can call `#js:averagedTouchesForView` on two separate objects: an `#js:SC.Event` object,
+or an `#js:SC.Touch` object.
+
+The two work identically but for one important difference: when you call it on `#js:SC.Touch`,
+you _have the option_ of telling the touch to add itself to the averaged set. Doing so makes no sense
+in most cases: the touch would just be counted twice! But what about `#js:touchStart`?
+
+Recall that during `#js:touchStart`, the view does not yet own the touch. So, `#js:averagedTouchesForView`
+would not, by default count it.
+
+ #js
+ // on an event:
+ var a = evt.averagedTouchesForView(this);
+
+ // on a touch
+ var a = touch.averagedTouchesForView(this);
+
+ // on a touch, counting the touch itself
+ var a = touch.averagedTouchesForView(this, YES);
+
+Thinking it Over
+------------------
+How might you use all of these to produce a good result?
+
+Let's take a simple example: moving and resizing something:
+
+{{demo:sc|multitouch.js}}
+
+
+
View
17 docs/src/articles/touch/touch-demo.js
@@ -16,6 +16,23 @@ var Dot = SC.View.extend({
width: t.ourStart.width,
height: t.ourStart.height
});
+ },
+
+ touchEnd: function() {
+ // actually, we don't need to do anything here...
+ },
+
+ // and now, redirect mouse events :)
+ mouseDown: function(evt) {
+ this.touchStart(evt);
+ },
+
+ mouseDragged: function(evt) {
+ this.touchesDragged(evt);
+ },
+
+ mouseUp: function(evt) {
+ this.touchEnd(evt);
}
});
var MyExampleView = SC.View.extend({
View
114 docs/src/articles/touch/touch-events.md
@@ -1,2 +1,114 @@
Touch Events
-=============
+=============
+
+SproutCore's touch events have a few great features:
+
+- Multiple views can receive touches simultaneously.
+- A single view can receive multiple touches.
+- A view can capture touches before allowing them to pass through to children.
+- Child views can release touches back to parent views that originally captured them.
+
+We won't get into the last two in this article—they're quite sophisticated!
+
+Simple Single-Touch Handling
+=====================================================
+You may be familiar with this SC.View method signature if you are familiar with SproutCore:
+
+ #js
+ mouseDown: function(evt)
+
+With `#js:mouseDown`, you can decide whether or not to accept the mouse event by returning either
+`#js:YES` or `#js:NO`.
+
+Touch events are similar, but work a bit differently:
+
+ #js
+ touchStart: function(touch)
+
+Instead of being passed a raw event, `#js:touchStart` is passed an `#js:SC.Touch` object.
+If you return YES from touchStart, your view will "own" the touch—in SproutCore terms, your
+view will be the _touch responder_. For more information about what this entails, see
+the "Internals" article. Your view will own the touch until the touch ends.
+
+`#js:touchStart` will be called once for every touch that touches the view.
+
+**Note:** By default, views only receive `#js:touchStart` and touchEnd for a single touch. This is
+a feature intended to make it easier to handle such cases, very similar to Cocoa Touch's `#js:acceptsMultitouch`
+property—actually, SC.View uses the same property name! See the "Multitouch" article.
+
+Anatomy of an SC.Touch
+------------------------
+SC.Touch represents the touch from the time the user puts their finger on the screen until the time they lift it.
+
+The touch object acts like an event object in many ways. It has many other useful things, as well:
+
+- `#js:pageX` and `#js:pageY` for the touch
+- `#js:event`: if in an event cycle, this contains the event. Otherwise, it is `#js:undefined`.
+ You will probably never need to access this.
+- `#js:preventDefault`: if the touch is connected with an event, this calls `#js:preventDefault()` on the event.
+- `#js:touchesForView(view)`: when supplied a view, will find all touches that the view is the
+ touch responder for. It is a CoreSet; to get an array, call `#js:.toArray` on the result.
+- `#js:averagedTouchesForView(view)`: When supplied a view, averages all the touches on that view,
+ returning both an average position and an average distance from that position.
+
+**Note:** If you call `#js:touchesForView(this)` from `#js:touchStart`, the touch supplied will not be in the set
+returned by `#js:touchesForView(this)`: you don't own the touch until you return YES.
+
+touchEnd
+-----------------
+Knowing when the touch starts is not very useful. At the very least, you will likely want to know when the touch
+ends as well.
+
+It is quite simple:
+
+ #js
+ touchEnd: function(touch)
+
+It works exactly like `#js:touchStart`. The touch will no longer be in the set of touches for the view,
+so if you call `#js:touch.touchesForView(this)`, you'll only receive any other active touches. If your
+view does not accept multitouch, then the set is guaranteed to have no touches in it—you only receive
+`#js:touchEnd` for the last touch that ends.
+
+Tracking Touches
+------------------
+Tracking touch movement is simple:
+
+ #js
+ touchesDragged: function(evt, touches)
+
+The `#js:touches` argument is the set of touches on the view—the same set you get by calling `#js:touchesForView(this)`.
+This will have _all_ touches, regardless of whether or not your view accepts multitouch.
+
+If your view does _not_ accept multitouch, then it is even simpler:
+
+ #js
+ x = evt.pageX;
+ y = evt.pageY;
+
+Tip: Cross-Platform-iness
+--------------------------
+Did you realize that, assuming you don't use the set of view touches or other touch-specific API,
+you can do this:
+
+ #js
+ mouseDown: function(evt) {
+ this.touchStart(evt);
+ },
+
+ mouseDragged: function(evt) {
+ this.touchesDragged(evt);
+ },
+
+ mouseUp: function(evt) {
+ this.touchEnd(evt);
+ }
+
+Of course, you can also redirect touch events to mouse events, but that is not as fun.
+
+Putting it All Together
+------------------------
+Here is a very simple demo that uses the methods described above to allow the user to move two views
+around the screen:
+
+{{demo:sc|touch-demo.js}}
+
View
5 docs/src/guides/touch.guide
@@ -1,11 +1,12 @@
{
- "title": "Writing Touch Applications",
+ "title": "Touch Application Guide",
"sections": [
{
"title": "Introduction",
"articles": [
"articles/touch/a-brief-touch",
- "articles/touch/touch-events"
+ "articles/touch/touch-events",
+ "articles/touch/multitouch"
]
},
{
View
BIN  themes/pig/resources/images/2.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
33 themes/pig/resources/theme.css
@@ -1,4 +1,4 @@
-.sc-theme .sc-view.ace.light.pig.sc-scroll-view.desk { background: url('data:image/png;base64,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') repeat-y; }
+.sc-theme .sc-view.ace.light.pig.sc-scroll-view.desk { background: url('data:image/png;base64,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') repeat-y; }
.sc-theme .sc-view.ace.light.pig.sc-collection-view.sc-list-view.sc-source-list.desk {
z-index: 0;
background: none;
@@ -70,6 +70,7 @@
background: white;
-webkit-box-shadow: 0px 5px 25px white;
}
+.sc-theme .sc-view.ace.light.pig.paper.sc-scroller-view { z-index: 20; }
.sc-theme .sc-view.ace.light.pig.sc-toolbar-view { -webkit-box-shadow: none; }
.sc-theme .sc-view.ace.light.pig.sc-view.demo { background: none; }
.sc-theme .sc-view.ace.light.pig.sc-view.demo .middle { display: none; }
@@ -93,12 +94,40 @@
height: 150px;
border: 1px solid gray;
}
-.sc-theme .sc-view.ace.light.pig.sc-static-content-view { font-size: 1.2em; }
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view {
+ -webkit-user-select: text;
+ font-size: 1.2em;
+}
.sc-theme .sc-view.ace.light.pig.sc-static-content-view h1 { font-size: 1.5em; }
.sc-theme .sc-view.ace.light.pig.sc-static-content-view h1 { color: #5078aa; }
.sc-theme .sc-view.ace.light.pig.sc-static-content-view h2 { color: #5078aa; }
.sc-theme .sc-view.ace.light.pig.sc-static-content-view h3 { color: #5078aa; }
.sc-theme .sc-view.ace.light.pig.sc-static-content-view h4 { color: #5078aa; }
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view code {
+ font-family: Monaco, Inconsolata, Courier, fixed-width;
+ font-size: 12px;
+}
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view pre code {
+ margin-right: 1em;
+ border: 1px solid #a0b0a0;
+ overflow-y: hidden;
+ overflow-x: auto;
+ background: #f5f9f5;
+ display: block;
+ padding: 1em;
+}
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view code .class { color: #000096; }
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view code .comment { color: #6496c8; }
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view code .string { color: #00640a; }
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view code .number { color: #0000ff; }
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view code .keyword {
+ color: #196e19;
+ font-weight: bold;
+}
+.sc-theme .sc-view.ace.light.pig.sc-static-content-view code .this {
+ color: #196e19;
+ font-weight: bold;
+}
.sc-theme .sc-view.ace.light.pig.sc-scroll-view.source {
background-color: white;
-webkit-transform: translate3d(0px,0px,0px);
View
24 themes/pig/src/content.css
@@ -4,6 +4,7 @@
}
@view(sc-static-content-view) {
+ -webkit-user-select: text;
font-size: 1.2em;
h1 {
font-size: 1.5em;
@@ -13,4 +14,27 @@
h1, h2, h3, h4 {
color: rgb(80,120,170);
}
+
+ code {
+ font-family: Monaco, Inconsolata, Courier, fixed-width;
+ font-size: 12px;
+ }
+
+ pre code {
+ margin-right: 1em;
+ border: 1px solid #a0b0a0;
+ overflow-y: hidden;
+ overflow-x: auto;
+ background: #f5f9f5;
+ display:block;
+ padding: 1em;
+ }
+
+ code .class { color: rgb(0, 0, 150); }
+
+ /*code .variable { color: rgb(10, 70, 10); }*/
+ code .comment { color: rgb(100, 150, 200); }
+ code .string { color: rgb(0, 100, 10); }
+ code .number { color: rgb(0, 0, 255); }
+ code .keyword, code .this { color: rgb(25, 110, 25); font-weight: bold; }
}
View
4 themes/pig/src/paper/paper.css
@@ -12,4 +12,8 @@
-webkit-box-shadow: 0px 5px 25px white;
}
+@view(sc-scroller-view) {
+ z-index: 20; /* Sit above toolbar */
+}
+
@end
View
BIN  themes/pig/src/tree/bg.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
2  themes/pig/src/tree/tree.css
@@ -1,5 +1,5 @@
@view(sc-scroll-view).desk {
- background: sprite("bg.png" repeat-y);
+ background: sprite("bg.jpg" repeat-y);
}
@view(sc-collection-view.sc-list-view.sc-source-list).desk {
Please sign in to comment.
Something went wrong with that request. Please try again.