<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:series="http://organizeseries.com/"
> <channel><title>SitePoint &#187; Programming</title> <atom:link href="http://www.sitepoint.com/category/programming/feed/" rel="self" type="application/rss+xml" /><link>http://www.sitepoint.com</link> <description>Learn CSS &#124; HTML5 &#124; JavaScript &#124; Wordpress &#124; Tutorials-Web Development &#124; Reference &#124; Books and More</description> <lastBuildDate>Mon, 13 May 2013 13:12:07 +0000</lastBuildDate> <language>en-US</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.5.1</generator> <item><title>CSS Architectures: Refactor Your CSS</title><link>http://www.sitepoint.com/css-architectures-refactor-your-css/</link> <comments>http://www.sitepoint.com/css-architectures-refactor-your-css/#comments</comments> <pubDate>Fri, 03 May 2013 12:44:33 +0000</pubDate> <dc:creator>Denise Jacobs</dc:creator> <category><![CDATA[CSS]]></category> <category><![CDATA[CSS3]]></category> <category><![CDATA[Programming]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65996</guid> <description><![CDATA[Denise Jacobs continues her series, this time offering a methodical way of debloatifying redundant CSS code: refactoring.]]></description> <content:encoded><![CDATA[<p></p><p>The top scalable and modular approaches I covered <a
href="http://www.sitepoint.com/css-architectures-scalable-and-modular-approaches/">in the previous article</a> in my CSS Architectures series all have pieces of brilliance that can help you change the way you think about and structure your CSS. They also overlap in many areas, which indicates which aspects of the process of improving your CSS are truly critical. Although you could follow any single approach while constructing a new site to great success, the fact of the matter is that what most of us are doing is trying to make sense of existing CSS run amok.</p><p>So, while the approaches I described are great on their own, what we really need is a way to combine the superpowers from them all to combat the evil of crazy code – a sort of “<a
href="http://www.youtube.com/watch?v=ANCjrzSJOsU">Justice</a> <a
href="http://www.youtube.com/watch?v=FLOwCWDlVTg">League</a>” of scalable and modular techniques. Furthermore, just as Rome wasn’t built in a day, it’s a fool’s errand to try to correct in one fell swoop thousands of lines of code that lack rhyme or reason. Thus, it’s a good idea to pass over the code in focused waves through a phased approach.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><h2>Giving CSS Refactoring a Good Name</h2><p>Last year, I had a project for a client where I was retained to do exactly that. After studying DRY CSS, OOCSS, SMACSS, and CSSG, I endeavored to distill them into their essential practices. In a moment of insight, I realized that all these approaches boiled down to the well-known adage “measure twice, cut once.” Of course! They all encourage looking at patterns, creating portable styles and modules that can be reused and not adding superfluous and redundant selectors or styles.</p><p>Additionally, my client had a lot of code and wanted to have flexibility in terms of the amount of changes that could be made to the CSS.  So, I developed a cohesive, phased plan of attack to reduce the number of lines in my client’s CSS. By the end, all of the practices and techniques for all four scalable CSS frameworks were incorporated, and the process I developed is very effective at reducing lines of CSS.</p><p>Once I created the process, I had to figure out what to name it. Taking “measure twice, cut once” as my base, I added CSS to it and this is what I got:</p><p>measure twice, cut once css → mtco css → meta coa css → MetaCoax!</p><p>So, in this article, I’ll share with you my MetaCoax CSS <a
href="http://aka.ms/CodeRefactoring">refactoring</a> process, designed to “de-bloatify” thousands of lines of redundant CSS—improving the readability, simplicity and extensibility of the CSS while keeping the visible design and functionality of the site the same. (<a
href="http://www.slideshare.net/denisejacobs/scalable-and-modular-css-ftw">Check out the slides</a> from my recent presentation on de-bloatifying CSS.)</p><p>To get yourself ready to refactor CSS, here are some suggestions. First, be conversant with specificity and the cascade – it will make a huge difference. I hope that in the first two articles in this series (<a
href="http://msdn.microsoft.com/en-us/magazine/jj983725.aspx">Part 1</a>, <a
href="http://msdn.microsoft.com/en-us/magazine/dn194516.aspx">Part 2</a>), I’ve driven home that making selectors and rules overly specific limits their reusability. When using descendent selectors especially, specificity can easily and quickly spiral out of control, and that’s precisely what we’re working to avoid. Second, remember inheritance rules: certain properties are inherited by child elements; thus, how these properties cascade down the DOM should always be kept in mind.</p><h2>The MetaCoax Process</h2><p>The MetaCoax process is a four-phased approach. Each phase builds on the previous one, and they all incorporate practices that decrease the amount of code, increase scalability and maintainability and, as an added bonus, lay the foundations for a <a
href="http://futurefriend.ly/">future-friendly</a> site. We’ll look at a detailed breakdown of each phase and the practices and techniques each encompasses. In this article, I’ll cover phases 1 and 2. Details about phases 3 and 4 will appear in the final article in the series.</p><p><b>Note:</b> An excellent tool to use while you’re going through the MetaCoax refactoring process is Nicole Sullivan’s <a
href="http://csslint.net/">CSS Lint</a>, which identifies additional places in the CSS to clean up and gives you ideas on how to do so.</p><h3>Phase 1: Shorten Selectors and Leverage and Layer Rulesets</h3><p>The first phase is focused on a minimum amount of work to improve a site’s CSS. These changes involve modifying the CSS but don’t touch the current HTML for a site’s pages. The goal is to make the stylesheet a little more lightweight and also easier to maintain and update with a small amount of time and effort. The method involves optimizing selectors while reducing redundancy with smarter reuse of rulesets. Even if you apply only the practices from this phase to your CSS, you’ll see an improvement in maintainability.</p><p>Here&#8217;s what we’re going to do:</p><ul><li>Shorten selectors chains<ul><li>Kill qualifiers</li><li>Drop descendants</li><li>Make the selector chain three or less</li></ul></li><li>Leverage and layer declarations<ul><li>Leverage the cascade by relying on inheritance</li><li>Review, revise and reduce !important properties</li><li>DRY (“don’t repeat yourself”) your rulesets</li></ul></li></ul><h3>Shorten Selector Chains</h3><p>To best optimize selectors, the goal is to use a shallow instead of a deep selector chain, making the chain as short as possible. This practice makes the code easier to work with, and the styles become more portable. Other advantages are reducing the chances of selector breakage, reducing location dependency, decreasing specificity and avoiding specificity wars by preventing overuse of !important declarations.</p><p>You have several ways in which you can shorten the selector chain, incorporating practices from all of the scalable architectures I outlined and further applying the “reduce, reuse, recycle” ethos. All of the practices are guaranteed to make the CSS code more forgiving. And isn’t that essentially the goal of updating our stylesheets?</p><h4>Drop Descendent Selectors</h4><p>The descendent selector (a b) is one of the most “expensive” combinatory selectors to use to target an element. Other expensive CSS selectors include the universal selector (*) and the child selector (a &gt; b). What makes them expensive? They are very general, and thus force the browser to look through more page elements to make a match. The longer the selector chain and the more checks required, the longer the browser takes to render the styles on the screen. When matching a descendent selector, the browser must find every instance of the key selector (which is the one on the far right) on the page, and then go up the ancestor tree to make the match.</p><p>While this might not be a problem for a stylesheet of a few hundred lines, it becomes more of an issue when the size of a document nears 10,000 lines or more. Even more important, in adopting a future-friendly and<a
href="http://aka.ms/MobileFirst"> mobile first</a> approach, long selector chains create a situation where small, less capable devices are forced to load and process unnecessarily large CSS documents.</p><p>Overdependence on descendent selectors is a vestige of the days of coding for Internet Explorer 6, as Internet Explorer 6 did not render the other CSS 2.1 combinator selectors at all. Because <a
href="http://aka.ms/ie6countdown">Internet Explorer 6 usage</a> is now almost nonexistent in the United States and other major markets, it’s completely safe to start employing selectors that are compatible with Internet Explorer 7 and Internet Explorer 8 and let go of the heavy use of descendent selectors once and for all. <b>Table 1</b> shows the selectors you can use with Internet Explorer 7. All versions of Internet Explorer since then support all the selectors shown here.</p><div
align="center"><table
width="287" border="1" cellspacing="0" cellpadding="0"><tbody><tr><td
valign="bottom" nowrap="nowrap" width="213"><b>Selector</b></td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center"><b>Internet Explorer 7</b></p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">Universal *</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">y</p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">Child: e &gt; f</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">y</p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">Attribute: e[attribute]</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">y</p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">:first-child</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">y</p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">:hover</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">y</p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">:active</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">y</p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">Sibling/Adjacent: e + f</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">n</p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">:before</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">n</p></td></tr><tr><td
valign="bottom" nowrap="nowrap" width="213">:after</td><td
valign="bottom" nowrap="nowrap" width="74"><p
align="center">n</p></td></tr></tbody></table></div><p><b>Table 1. CSS 2.1 Selectors Safe for Internet Explorer 7</b>.</p><p><b>Note:</b> Check the charts at <a
href="http://caniuse.com/">http://caniuse.com/</a> and <a
href="http://www.findmebyip.com/litmus/">http://www.findmebyip.com/litmus/</a> to determine the browser support of other CSS selectors.</p><p>Instead of the descendent selector, use the child selector. The child selector selects elements that are direct descendants of the parent element—that is, direct children in the first generation—as opposed to a grandchild or great-grandchild, which is what the descendent selector includes. <b>Figure 1</b> illustrates this selection process.</p><p><img
class="alignnone size-full wp-image-65997" alt="A Descendent Selector vs. a Child Selector" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/05/figure12.png" width="422" height="288" /></p><p><b>Figure 1.</b> <b>A Descendent Selector vs. a Child Selector</b></p><p>Although the child selector is still an “expensive” selector, it is more specific. This means that the browser won’t search as far down the inheritance chain to match the key selector. Thus, such a selector targets the element you need much better.</p><p>If you must use a descendent selector, eliminate all superfluous elements in it. For example:</p><p><code>.widget li a</code></p><p>would become</p><p><code>.widget a</code></p><p>The style will be applied whether the li is there or not.</p><h4>Kill Qualified Selectors</h4><p>Qualifying both #IDs and .classes with elements causes the browser to slow unnecessarily to search for the additional elements on the page to make a match with the selector. It is never necessary to qualify an ID. An ID has one of the highest specificity weights in CSS because it is unique to whatever page it is on, and it will always have a direct match on its own. Qualified selectors also cause the specificity of the selectors to be ridiculously high, necessitating the use of even more specific selectors and the use of !important to trump these super-specific rulesets.</p><p>Selectors such as</p><p><code>div#widget-nav div#widget-nav-slider</code></p><p>can be simplified to</p><p><code>#widget-nav #widget-nav-slider</code></p><p>and further whittled down to</p><p><code>#widget-nav-slider</code></p><p>Each provides the same outcome.</p><p>Dropping an element class qualifier in selectors lessens the specificity of the selector, which better enables you to correctly use the cascade to override the style if necessary. For example,</p><p><code>li.chapter</code></p><p>would ideally be changed to</p><p><code>.chapter</code></p><p>Even better, because it is more specific to the case of the &lt;li&gt;, you could consider changing the class on your &lt;li&gt; tag, and scoping the CSS to</p><p><code>.li-chapter</code> or <code>.list-chapter</code></p><h4>Make It Three or Less</h4><p>When working on optimizing selectors, institute a “three or less” rule: a combinator selector should have no more than three steps to get to the key selector. For example, take this doozy of a selector:</p><p><code>div#blog-footer div#col2.column div.bestright p.besttitle {margin-bottom: 4px;}</code></p><p>To have three steps or less to get to the key selector, make a change like this:</p><p><code>#col2.column .besttitle {border: 1px solid #eee;}</code></p><h3>Leverage and Layer Declarations</h3><p>The next order of business is to focus on the style declarations themselves. When refactoring bloated CSS down to something more manageable, it’s easy to focus primarily on the selectors and believe that the styles will work themselves out. However, paying attention to what style declarations you’re creating (see <b>Figure 2</b>) and where they go makes a difference as well in moving toward sleek CSS.</p><p><img
class="alignnone size-full wp-image-65998" alt="Anatomy of a CSS Ruleset" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/05/figure2.png" width="372" height="139" /></p><p><b>Figure 2.</b> <b>Anatomy of a CSS Ruleset</b></p><h4>Leverage Inheritance</h4><p>Often, we think we know something really well when actually we don’t, and inheritance in CSS may just be one of those areas. You might remember that <a
href="http://www.w3.org/wiki/Inheritance_and_cascade">inheritance is a fundamental concept of CSS</a>, but you might not remember exactly which properties naturally inherit and which do not. <b>Table 2</b> shows the most commonly used properties that get inherited by descendent elements, unless the descendent elements are styled otherwise. (<a
href="http://www.w3.org/TR/CSS21/propidx.html">There are other more obscure properties that are inherited as well</a>.)</p><table
border="0" cellspacing="0" cellpadding="0"><tbody><tr><td
valign="top" width="187"><code>color</code> <code>font-family</code> <code>font-family </code> <code>font-size   </code> <code>font-style</code> <code>font-variant      </code> <code>font-weight       </code> <code>font</code> <code>letter-spacing</code> <code>line-height </code></td><td
valign="top" width="210"><code>list-style-image </code> <code>list-style-position     </code> <code>list-style-type   </code> <code>list-style</code> <code>text-align</code> <code>text-indent       </code> <code>text-transform</code> <code>visibility</code> <code>white-space</code> <code>word-spacing</code></td></tr></tbody></table><p><b>Table 2. Common Elements Inherited by Descendent Elements</b></p><p>These properties are important to keep in mind when you’re looking for redundant styles to consolidate or eliminate. When you’re updating the stylesheet, properties that can be inherited should be placed in the CSS so that they are best utilized and not repeated. With proper placement of these properties, later redundant style declarations could be eliminated completely.</p><h4>Review, Revise and Reduce !important Properties</h4><p>If your CSS boasts an impressive number of !important declarations, then it’s time to reduce it. You should really use !important declarations only in certain instances. Chris Coyier of <a
href="http://aka.ms/CSStricks">CSS Tricks</a> recommends using them with <a
href="http://css-tricks.com/when-using-important-is-the-right-choice/">utility classes or in user stylesheets</a>. If you use them otherwise, you may end up being branded as <a
href="https://twitter.com/stefsull/status/70631020352913408">selfish and lazy</a>, and who wants that?!</p><p>How to cut down on !important? First, keep the specificity of selectors low by following the suggestions I made earlier.  Second, remember that, ideally, new styles should not undo previous rulesets but add to them.</p><p>Here’s what I mean: if you find yourself writing new styles to undo an earlier style (and then using !important to try to trump the style in the event of a specificity war), then you need to rethink the older style, distill it down to its necessities, and then create new styles that augment the original style instead of working to undo what’s already there. This is what I think of as “layering” style rulesets. This can also be referred to as “extending” (or “subclassing”) a style, which is part of creating modules in phase 2.</p><p>If you have a large number of !important properties for the same styles, I bet those properties could be turned into a portable style that could be applied to multiple elements, which I’ll also talk about when I describe phase 2.</p><h4>DRY Your Rulesets</h4><p>To cut down on large numbers of repeated styles in the CSS, a little DRY coding can help. While adopting the full DRY CSS approach may be a bit draconian, being aware of when you repeat the same ruleset and then getting your group on <a
href="http://msdn.microsoft.com/en-us/magazine/dn194516.aspx">is a great practice</a>.</p><h3>Phase 2: Restructure, Adjust, and Modularize</h3><p>The techniques in phase 2 are focused on doing a moderate to high level of work to improve a site’s CSS. The changes encompass altering both the CSS and the HTML of the pages, with the changes to the HTML most likely to involve renaming or reassigning class names. The goal is to give structure and organization to the stylesheet, through grouping styles by category rather than by pages, by removing archaic HTML, clearing the excess from the selectors and creating modules to increase code efficiency.</p><p>This phase will further eliminate redundancy, make the stylesheet more lightweight by improving selector accuracy and efficiency and also aid in maintenance. This level of improvement takes more time and effort than phase 1, but it includes the bulk of the work required to make your CSS better and is estimated to dramatically cut down the number of lines of CSS code.</p><p>Here is what we are going to do:</p><ul><li>Restructure to refactor<ul><li>Categorize CSS rules in the stylesheet</li><li>Restructure styles that rely on qualifiers high in the DOM</li><li>Use class names as key selector</li></ul></li><li>Begin instituting modules<ul><li>Extend module substyles with a double hyphen (&#8211;)</li></ul></li><li>Create portable helper styles<ul><li>Surgical layout helpers</li><li>Typographical styles</li></ul></li><li>Adjust the HTML<ul><li>Eliminate inline styles</li><li>Decrease use of &lt;span&gt; for better semantics</li></ul></li></ul><h3>Restructure to Refactor</h3><p>Let’s not forget that restructuring the CSS is our main objective. These practices start the process of moving away from thinking about and creating styles that are based on and specific to page components and page hierarchy, and moving toward thinking of styles in a portable, reusable and modular manner.</p><h4>Categorize CSS Rules in the Stylesheet</h4><p>In <a
href="http://msdn.microsoft.com/en-us/magazine/jj983725.aspx">the first article in this series</a>, I suggested creating a table of contents to make finding the sections of the styles in your CSS easier. In this phase of CSS refactoring, I recommend stepping up that process several notches by transforming these sections to the types of styles they describe, following the <a
href="http://msdn.microsoft.com/en-us/magazine/dn194516.aspx">SMACSS categories</a>. These categories are:</p><ul><li><b>Base</b> The default styles, usually single element selectors that will cascade through the whole document.</li><li><b>Layout</b> The styles of the page sections.</li><li><b>Module</b> The reusable styles of the various modules of the site: callouts, sidebar sections, product, media, slideshows, lists, and so on.</li><li><b>State </b>The styles that describe how a module or layout looks in a particular state.</li><li><b>Theme</b> The styles that describe how modules or layouts might look.</li></ul><p>So now, your table of contents and document sections will look like this:</p><pre><code>/* Table of Contents</code>
<code>- Base</code>
<code>- Layout</code>
<code>- Module</code>
<code>- State</code>
<code>- Theme</code>
<code>*/</code>
<code>…</code>
<code>(later in the document…)</code>
<code>/* =Layout */ (etc.)</code></pre><p>This reorganization of the stylesheet helps lay the foundation for the rest of the phase 2 practices and is a part of phase 3 as well.</p><h4>Restructure Styles That Rely on Qualifiers High in the DOM</h4><p>This recommendation is one of most important in this whole article: to completely eliminate page specific styles—that is, styles that are based on adding a class to the body element to signify a different page. A style such as this forces the browser to check all the way up the DOM chain to the &lt;body&gt; tag.   Here’s an example:</p><pre><code>body.donations.events div#footer-columns div#col1 div.staff span.slug {</code>
<code>display: block;</code>
<code>margin: 3px 0 0 0;</code>
<code>}</code></pre><p>This practice is the root of long selector chains, super-high specificity of selectors and the need to use !important to override styles higher up the cascade, as in the following example:</p><pre><code>body.video div#lowercontent div.children.videoitem.hover a.title { background: #bc5b29; </code>
<code>color: #fff !important; </code>
<code>text-decoration: none; </code>
<code>}</code></pre><p>In other words, it’s bad. <a
href="http://www.youtube.com/watch?v=E4_tOiLB_Ko">Mmkaay</a>?</p><p>To fix it, you need to follow all of the previous suggestions, such as three or less, kill the qualifiers and reduce specificity. What you could end up with is something more like this:</p><pre><code>.donations-slug {</code>
<code>display: block;</code>
<code>margin: 3px 0 0 0;</code>
<code>}</code></pre><h4>Use Class Names as Key Selector</h4><p>Because IDs are highly specific, you should avoid using them whenever possible, as they cannot be reused as classes can. However, in creating classes you want to keep your class names semantic yet portable. The goal is to make a selector as direct as possible. By doing this, you avoid specificity problems and can then even combine styles to layer them as suggested earlier.</p><p>From SMACSS, you should instill the practice that when you create selectors, the key selector should be a .class instead of a tag name or an #id.  Always keep in mind that the far-right key selector is the most important one. If a selector can be as specific to the element in question as possible, then you’ve hit the jackpot. This way, the styles are targeted more directly because the browser matches only the exact elements.</p><p>Review all places where child selectors are used, and replace them with specific classes when possible. This also avoids having the key selector in the child combinator as an element, which is also discouraged.</p><p>For example, instead of doing this:</p><p><code>#toc &gt; LI &gt; A</code></p><p>it’s better to create a class, as shown next, and then add it to the appropriate elements.</p><p><code>.toc-anchor</code><code> </code></p><h3>Begin Instituting Modules</h3><p>Nothing epitomizes the “measure twice, cut once” adage in the scalable CSS approaches as well as modules, which are the heart and soul of all of them. Modules are components of code that can be abstracted from the design patterns—for example, frequent instances of lists of items with images that float either to the left or right or underneath; these can be abstracted into a module with a base set of styles that every module would share. Then the module can be extended (or skinned) with changes in text, background, font color, borders, floats, and so on, but the structure remains the same.</p><p>The best thing about modules is that they are portable, meaning that they are not location dependent. Abstracting a design pattern into a code module means that you can put in anywhere in any page and it will show up the same way, without you having to reinvent the wheel style-wise. Now <i>that’s</i> what CSS was made for, right?! In addition to my earlier suggestions, modularizing your CSS is one of the best ways to dramatically decrease the amount of code.</p><p>OOCSS provides a great way to think about <a
href="http://aka.ms/ModulesContainerObjects">how to structure</a> and <a
href="http://aka.ms/ModulesBlockStructures">skin a module</a> and also about <a
href="https://github.com/stubbornella/oocss/wiki/_pages">what can be made into a module</a>. SMACSS provides <a
href="http://aka.ms/ModuleRules">clear guidelines on how to name modules and extend them</a>.</p><h4>Extend Substyles with  &#8211;</h4><p>Although SMACSS gives great guidance for thinking about extending modules, I prefer the technique from CSS for Grownups of extending substyles with &#8211;. This makes a lot of sense to me because it is a visual indication that the new style is based on the previous one but is taking it further.</p><p>Here’s an example:</p><pre>#go, #pmgo{
    width: 29px;
    height: 29px;
    margin: 4px 0 0 4px;
    padding: 0;
    border: 0;
    font-size: 0;
    display: block;
    line-height: 0;
    text-indent: -9999px !important;
    background: transparent url("/images/go.jpg") 0 0 no-repeat;
    cursor: pointer; /* hand-shaped cursor */
    x-cursor: hand; /* for IE 5.x */
}
#pmgo{
    margin: 2px 0 0 3px;
    background: transparent url("/images/go.jpg") no-repeat center top;
}</pre><p>This code could be modified and changed into something more like this:</p><pre>.button-search{
    width: 29px;
    height: 29px;
    margin: 4px 0 0 4px;
    padding: 0;
    border: 0;
    font-size: 0;
    display: block;
    line-height: 0;
    text-indent: -9999px !important;
    background: transparent url("/images/go.jpg") 0 0 no-repeat;
    cursor: pointer; /* hand-shaped cursor */
    x-cursor: hand; /* for IE 5.x */
}
.button-search--pm{
margin: 2px 0 0 3px;
background: transparent url("/images/go.jpg") no-repeat center top;
}</pre><h3>Create Portable Helper Styles</h3><p>Along with the process of modularization, portable styles are another handy tool to have in your arsenal. Here are some examples from CSS for Grownups.</p><h4>Surgical Layout Helpers</h4><p>By CSS for Grownups’ standards, there’s no shame in having a little extra layout help. While a grid takes care of a lot of issues, these styles may give elements a little nudge when needed (especially in terms of vertical spacing), while eliminating lines of code.</p><pre><code>.margin-top {margin-top: 5px;}</code>
<code>.margin-bottom {margin-bottom: .5em;}</code></pre><p>Although in most cases we strive to keep names semantic when creating classes, in this instance descriptive names are fine.</p><h4>Typographical Styles</h4><p>Typographical styles are perfect if you find that much of your CSS is devoted to changing the font face, size and/or line height. Both OOCSS and CSS for Grownups suggest dedicated typographical styles that are not tied to the element, such as the following:</p><pre><code>.h-slug {font-size: .8em;}</code>
<code>.h-title {font-size: 1.5em;}</code>
<code>.h-author {font-size: 1em;}</code></pre><p>A great exercise is to search for the properties font, font-size, font-face, and h1 through h6 and marvel at the sheer magnitude of the instances of these properties. Once you’ve had a good laugh, figure out which styles apply to what, which sizes are important, and then start making some portable typographical styles.</p><h3>Adjust the HTML</h3><p>While the practices in phases 1 and 2 that we’ve covered so far offer miracles in terms of CSS cleanup, we can’t forget about the page markup. Most likely, as suggested by Andy Hume in CSS for Grownups, you’ll need to make changes to the HTML beyond adding new class names.</p><h4>Decrease Use of &lt;span&gt; for Better Semantics</h4><p>Do you have a rampant use of the &lt;span&gt; tag where a more semantic tag would be much more appropriate? Remember, the &lt;span&gt; tag is really for inline elements, not block-level elements, as stated by the W3C (<a
href="http://www.w3.org/TR/html401/struct/global.html#h-7.5.4">http://www.w3.org/TR/html401/struct/global.html#h-7.5.4</a>), so using &lt;span&gt; for headers and other elements intended to be block-level is technically incorrect.</p><p>Here, for example, the spans should really be paragraphs or header tags that indicate where this content fits in the document’s hierarchy. Either of those other elements could have provided a base for the class hooks.</p><pre><code>&lt;li&gt;</code>
<code>&lt;a href="/learning/hillman" title=""&gt;</code>
<code>&lt;img src="/images/brenda-hillman.jpg" alt="Air in the Epic" /&gt;</code>
<code>&lt;/a&gt;</code>
<code>&lt;span&gt;Brenda Hillman Essays&lt;/span&gt;</code>
<code>&lt;span&gt;&lt;a href="/learning/hillman" title="Air in the Epic" class="title"&gt;Air in the Epic&lt;/a&gt;&lt;/span&gt;</code>
<code>&lt;span&gt;Brenda Hillman&lt;/span&gt;</code>
<code>&lt;/li&gt;</code></pre><p>The following version of this code would be an improvement from a semantics standpoint:</p><pre><code>&lt;li&gt;</code>
<code>&lt;a href="/learning/hillman" title=""&gt;</code>
<code>&lt;img src="/images/brenda-hillman.jpg" alt="Air in the Epic" /&gt;</code>
<code>&lt;/a&gt;</code>
<code>&lt;p&gt;Brenda Hillman Essays &lt;/p&gt;</code>
<code>&lt;h3&gt;&lt;a href="/learning/hillman" title="Air in the Epic" class="title"&gt;Air in the Epic&lt;/a&gt;&lt;/h3&gt;</code>
<code>&lt;p&gt;Brenda Hillman&lt;/p&gt;</code>
<code>&lt;/li&gt;</code></pre><h4>Eliminate Inline Styles</h4><p>Finally, you need to get rid of inline styles. In this day and age, inline styles should rarely if ever be used. They are much too closely tied to the HTML and are akin to <a
href="http://csszengarden.com/?cssfile=http://www.brucelawson.co.uk/zen/sample.css">the days of yore when &lt;font&gt; tags were running rampant</a>. If you use inline styles to override specificity, then making the changes suggested in this article should already help you avoid specificity wars, effectively eliminating the need for inline styles.</p><p>For example, this inline style:</p><p><code>&lt;span class="text-indent: 1em"&gt;Skittles are tasty&lt;/span&gt;</code></p><p>could easily be turned into its own class that can be applied throughout the document, like so:</p><p><code>.indent {text-indent: 1em:}</code></p><p>Your mission, <a
href="http://www.hark.com/clips/ytqshsltzw-your-mission-jim-should-you-choose-to-accept-it">should you choose to accept it</a>, is to find all the instances of inline styles and see where you can make those styles portable helpers. The property you’re using could easily be made into a portable style that can be reused on the other instances of text.</p><h2>Try It, It Will Be Good for You!</h2><p>At the <a
href="http://oredev.org/">Øredev</a> Web development conference in Malmö, Sweden, I had the pleasure of seeing the brilliant <a
href="http://kytrinyx.com/">Katrina Owen</a> present “<a
href="https://vimeo.com/53154356">Therapeutic Refactoring</a>.” She suggested that when faced with a deadline, she turns to refactoring horrible code to help her gain a sense of control and rightness in the world.</p><p>You can approach restructuring your CSS for the better the same way. By healing what ails your CSS, you can gain a sense of calm and power, while beginning to make the world of your site’s stylesheets a better place, one line of code at a time.</p><p>Stick with me, though, because we aren’t quite finished. We have two more phases to cover in the MetaCoax process that will fully oust the evil from your CSS once and for all, and will also enable you to leave a legacy of goodness behind for all of the front-end devs that come after you.</p><div><em>This article is part of the HTML5 tech series from the Internet Explorer team. <a
href="http://www.microsoft.com/click/services/Redirect2.ashx?CR_CC=200210648">Try-out</a> the concepts in this article with three months of free BrowserStack cross-browser testing @<a
href="http://modern.ie/">http://modern.IE</a></em></div><h2>Links for Further Reading</h2><ul><li><a
href="https://github.com/stubbornella/csslint/wiki/_pages">CSS Lint Pages</a></li><li><a
href="https://vimeo.com/44773888">Breaking Good Habits</a> – Harry Roberts’ talk at Front Trends Conference 2012</li><li><a
href="https://speakerdeck.com/csswizardry/big-css-1">Big CSS</a> – Another great Harry Roberts presentation</li></ul><p><b>&#8212;&#8211;</b></p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/css-architectures-refactor-your-css/feed/</wfw:commentRss> <slash:comments>3</slash:comments> <series:name><![CDATA[CSS Architectures]]></series:name> </item> <item><title>CSS Architectures: Scalable and Modular Approaches</title><link>http://www.sitepoint.com/css-architectures-scalable-and-modular-approaches/</link> <comments>http://www.sitepoint.com/css-architectures-scalable-and-modular-approaches/#comments</comments> <pubDate>Wed, 01 May 2013 10:29:51 +0000</pubDate> <dc:creator>Denise Jacobs</dc:creator> <category><![CDATA[CSS]]></category> <category><![CDATA[CSS3]]></category> <category><![CDATA[Programming]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65966</guid> <description><![CDATA[Denise Jacobs continues her exploration of where CSS is headed, in this case putting the focus on keeping code manageable by keeping it scalable and modular.]]></description> <content:encoded><![CDATA[<p></p><p>As the online industry matures, so do approaches to dealing with code for large Web sites. <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl01" href="http://msdn.microsoft.com/en-us/magazine/jj983725.aspx">Cleaner CSS</a> is a great starting point, but front-end developers can elevate a site’s stylesheet to another level by applying methodologies that are part of increasingly popular scalable CSS architectures.</p><p>By using an approach in its entirety or by applying selected tenets and practices from them all, you can say good-bye to problems that typically plague the CSS for large sites, such as verbose and difficult to read code that’s painful to maintain and update and the redundancy that creates code bloat.</p><h2>Diagnosing the Origins of Bloated CSS</h2><p>If you recognize any of the following symptoms or ailments, making your stylesheet modular and more scalable is just what the doctor ordered. To get a proper handle on just how bad things are, search for certain properties and see what the numbers tell you. In Nicole Sullivan’s presentation, the <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl02" href="http://www.stubbornella.org/content/2010/07/01/top-5-mistakes-of-massive-css/">Top 5 Mistakes of Massive CSS</a>, she provides a rubric to diagnose the roots of an overabundance of several key properties:<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><ul><li>A large number of floats means there is an ineffective or nonexistent grid.</li><li>A large number of margins means you need a <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl03" href="http://meyerweb.com/eric/tools/css/reset/">reset.css</a> (or <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl04" href="http://necolas.github.com/normalize.css/">normalize.css</a>).</li><li>A large number of padding means that the design parameters aren’t explicit and thus multiple developers have tweaked details a lot.</li><li>A large number of font-size means that the cascade is not being leveraged. Headings are probably hidden within the rule sets with font-size as well.</li><li>A large number of !important means that this property is being used to override specificity and, again, that the cascade is not being leveraged.</li></ul><p>Any of this sound familiar? It’s okay, you’re in good hands, because now that you’ve diagnosed the origins of your CSS bloat, we can talk about some sure-fire cures.</p><h2>Scalable and Modular Approaches: The Essentials</h2><p>The main concepts of the different scalable approaches can be boiled down to two core practices:</p><h3>1. Reduce, Reuse and Recycle</h3><p><em>Reducing</em> means writing the shortest chain of elements possible in selectors, and dropping element qualifiers, much of which I discussed in the <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl05" href="http://www.sitepoint.com/css-architectures-new-best-practices/">previous article</a>. Equally important is creating appropriate selectors by favoring classes over IDs, avoiding the use of elements, and using combinator selectors that more directly target the element you need on the page.</p><p><em>Reusing</em> involves creating generic classes instead of overly specific ones, and combining classes to create different visual outcomes.</p><p><em>Recycling</em> involves better leveraging the cascade to cut down on redundant style declarations, modularizing page components to use throughout the site with minimum code and extending modules through subclassing.</p><h3>2. Organize, Structure and Inform</h3><p>Providing good, well-organized information is critical for clarity and understanding. The practices listed in the <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl06" href="http://www.sitepoint.com/css-architectures-new-best-practices/">first article</a>, like providing developer information in the stylesheet and creating a structure in terms of the document itself (by categorizing styles in the document), play a part in the scalable approaches. However, developers can add even more structure by breaking the style categories into multiple documents, indicating structure and meaning through a naming convention for reusable classes and establishing page structure with grids. Web site style guides are the final component for making sure the team is well informed about styles, structure and nomenclature.</p><h2>An Overview of Scalable and Modular Approaches</h2><p>Now that I’ve introduced the key concepts, let’s take a look at specific practices that support these concepts through an overview of the best-known and most popular approaches to dealing with large CSS projects. The approaches I’ll cover are DRY (Don’t Repeat Yourself) CSS, Object-Oriented CSS (OOCSS), Scalable and Modular Architecture for CSS (SMACSS), and CSS for Grownups.</p><h3 id="dry">DRY CSS</h3><p>The ease of learning and applying CSS is mitigated by the language’s lack of logic. Unlike programming languages that have reusable components like variables and functions, CSS almost encourages flagrant reuse of selectors and property-value pairs. Indeed, even when redundant and bloated, CSS is perfectly functional.</p><p><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl07" href="http://www.slideshare.net/jeremyclarke/dry-css-a-dontrepeatyourself-methodology-for-creating-efficient-unified-and-scalable-stylesheets">DRY CSS</a> is based on taking the “<a
id="ctl00_MTContentSelector1_mainContentContainer_ctl08" href="http://programmer.97things.oreilly.com/wiki/index.php/Don%27t_Repeat_Yourself">don’t repeat yourself</a>” principle of software development very literally. That’s right: when coding CSS, the goal is never to repeat a property-value pair. Ever. I know it seems rather…ah, <em>intense</em>, but it can be done.</p><h4>Get Your Group On (So to Speak)</h4><p>The core of DRY CSS is grouping, which at its roots entails structure, organizing, reducing and recycling. <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl09" href="http://simianuprising.com/">Jeremy Clarke</a>, who devised DRY CSS, suggests creating groups of selectors with shared properties, rather than repeating property-value pairs for each selector separately, as is typical when writing CSS. While a group may have many selectors, each property-value pair is deﬁned only once.</p><p>The groups actually deﬁne shared properties. With DRY CSS, you have to relinquish the deeply ingrained habit of naming classes and IDs based on semantics, like .alert-box for example. Instead, groups use descriptive names based on their appearance or on their role in the design—like .rounded-corners—but then all selectors that share that property should be grouped with that style. While doing this takes away the possibility of mixing and matching, it does lessen the amount of your code.</p><p>How do you create a group? Start by naming the group based on its role in the design. Then use the name of the group as an ID at the top of the list and a class at the bottom. Then add the rest of the selectors that share properties above the descriptive class name that they share. Jeremy gives the example shown in <strong>Figure 1</strong> in his presentation “<a
id="ctl00_MTContentSelector1_mainContentContainer_ctl10" href="http://simianuprising.com/2012/03/07/video-of-my-dry-css-talk/">DRY CSS: A don’t-repeat-yourself methodology for creating efficient, unified and Scalable stylesheets</a>.”</p><p><img
class="alignnone size-full wp-image-65967" alt="DRY CSS groupings" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/05/figure1.png" width="550" height="662" /><br
/> <strong>Figure 1.</strong><strong>Example of DRY CSS groupings</strong></p><p>What about selectors that don’t immediately seem to be part of a group? Another goal in “drying out” your CSS is to make individual selectors as rare and sparse as possible, employing them only as exceptions. This means you need to perform a mental exercise when you’re coding. As you create a style declaration for a selector, always ask &#8220;Why isn’t this part of a group?&#8221;—and then figure out how to make it part of a group if you can.</p><p>Once you create groups, you need to think about organizing them. Clarke recommends using colors, text, shapes, structures and modules as categories, but he also encourages developers to create whatever categories they feel are best for a project.</p><h4>Benefits</h4><p>In his presentation on DRY CSS, Clarke lists many benefits to the approach. Here are some that I feel are most compelling:</p><ul><li>Decreases the size of CSS files. Clearly, this is the prime objective, and by using DRY CSS you more than achieve it.</li><li>Optimises elements and generalizes selectors. The occurrence of this increases as you see their interrelatedness and how they can be inherited.</li><li>Edits to a group affect all its members, which encourages consistency. You can see the members of a group change at the same time, which is a great advantage over making changes to a lot of individual selectors.</li><li>The HTML remains untouched. This is useful for sites with generated HTML that can’t easily be controlled, such as content management systems or blogging tools.</li><li>Encourages thinking through design elements/styles and design patterns and the consistency thereof. This promotes good design practices and uniform updates.</li></ul><p>Clarke also asserts that DRY CSS integrates with other scalable architectures, such as OOCSS and SMACSS.</p><h4>Successes</h4><p>Clarke had great success applying his approach to the <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl11" href="http://globalvoicesonline.org/">Global Voices site</a>, which also had to support localization into multiple languages. According to Clarke, in developing and applying DRY CSS, the site’s stylesheet went from roughly 4,500 lines to 2,400 lines. That’s an improvement that most front-end developers would welcome.</p><h3 id="oocss">OOCSS</h3><p><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl12" href="https://github.com/stubbornella/oocss/wiki">Object-Oriented CSS</a> starts with pattern recognition: determining what page elements are similarly structured and used frequently on the site. Once a pattern is identified, the design element can be made into a module. Then the module can be skinned for the different ways it shows up across the site.</p><p>OOCSS has two key principles. The first is to separate structure and presentation (or structure from “skin”), which means decoupling the structure of an element from its looks, and treating the looks like “skins.” This principle shouldn’t be too difficult to implement, as it’s similar to one of the foundational tenets of Web standards: the separation of presentation and content.</p><p>The second principle is to separate the container and the content, which means to use styles that are specific to an element and don’t depend on location. All too often, the common way to create CSS selectors is to attach an ID or a class to an element high in the DOM (like &lt;body&gt;), and then to create long-chain selectors to create variations on elements. This practice is responsible for most heinous CSS transgressions that lead to unwieldy and difficult to maintain stylesheets. Instead, in OOCSS, a container is modified by extending it, which effectively alters the container based on the content. In other words, you add an additional CSS class to provide for the differences in appearance only.</p><p>Sullivan <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl13" href="http://www.slideshare.net/stubbornella/the-fast-and-the-fabulous">breaks down the OOCSS approach into the following steps</a>:</p><ol><li>Determine the reusable elements sitewide, such as headings, lists (action list, external link list, product list, or feature list), module headers and footers, grids, buttons, rounded-corner boxes, tabs, carousels, toggle blocks.</li><li>Delineate between:<ul><li>Container and content</li><li>Structure and skin</li><li>Contour and background</li><li>Objects and mixins</li></ul></li><li>Mix and match container and content objects to achieve high-performance design.</li><li>For visual differences, skin the modules. Skins/themes are the module’s presentation—how it looks. The goal is to have very predictable skins, changing only values that can be easily calculated or measured.</li></ol><h3>Modules: The Building Blocks of a Site</h3><p>Much of the practice of OOCSS is built on reusable components. Sullivan likens these components to Legos and refers to them as <em>modules</em>. The goal for a module is that it relies neither on the DOM tree nor on specific element types. It should be flexible enough to adapt to different containers and be skinned easily.</p><p>Identifying, creating and employing a module is a very DRY aspect of OOCSS. By finding common elements and presentations and abstracting them into reusable code modules, front-end developers don’t repeat themselves and really do practice reducing, reusing and recycling.</p><p>An excellent example of a module that can take care of images with text in various forms and incarnations is Sullivan’s .media module. The .media module was developed to handle instances of images floating off to the side of text and related permutations. She gives <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl14" href="http://www.stubbornella.org/content/2010/06/25/the-media-object-saves-hundreds-of-lines-of-code/">this example of various forms that the media module can take</a>.</p><p>Here is the HTML that forms the structure of the media module:</p><pre>        &lt;!-- media --&gt;
	&lt;div class="media"&gt;
	  &lt;img class="fixedMedia" src="myimg.jpg" /&gt;
	&nbsp;
	  &lt;div class="text"&gt;
	...
	  &lt;/div&gt;
	&lt;/div&gt;</pre><p>The CSS of the initial module establishes the basis of the style, and any differences come from extending the styles and thus the appearance of the elements.</p><pre>         /* ====== media ====== */
	.media {margin:10px;}
	.media, .bd {overflow:hidden; _overflow:visible; zoom:1;}
	.media .img {float:left; margin-right: 10px;}
	.media .img img{display:block;}
	.media .imgExt{float:right; margin-left: 10px;}</pre><p>The media module is just the tip of the iceberg. Many more modules, including buttons, grids, carousels, and content, are on <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl17" href="https://github.com/stubbornella/oocss/">the OOCSS project on GitHub</a>.</p><h4>Benefits</h4><p>Adopting OOCSS, or at least elements of the system, saves many lines of code. Furthermore, it provides an approach that is easily sandboxed and can be used by everyone on the team.</p><h4>Successes</h4><p>One of the biggest and most famous sites that Sullivan has applied OOCSS to is <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl18" href="http://facebook.com/">Facebook</a>. According to the numbers given in her presentation <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl19" href="http://www.slideshare.net/stubbornella/css-bloat">CSS Bloat</a>, she and the Facebook team cut CSS bytes per page by 19 percent and HTML bytes per page by 44 percent. Just with headers alone, they reduced the number from 958 to 25, and reduced the site’s response time by half.</p><h3 id="SMACSS">SMACSS</h3><p>SMACSS (<a
id="ctl00_MTContentSelector1_mainContentContainer_ctl20" href="https://smacss.com/">https://smacss.com/</a>) is another approach to writing scalable and modular CSS for large-scale sites. According to Jonathan Snook, its creator, “<a
id="ctl00_MTContentSelector1_mainContentContainer_ctl21" href="http://smacss.com/book/prototyping">SMACSS is about identifying patterns in your design and codifying them.</a>” Sure, I’m biased, but we could take “codifying” patterns as simply another way of describing the core tenants (reduce, reuse, and recycle; organize and structure), could we not?</p><p>Snook has several practices for applying organization and structure to large CSS projects. The core of SMACSS is the categorization of CSS rules. Categories help design patterns become more obvious, thus enabling developers to make better definitions for and of these patterns.</p><p>The categories that Snook suggests are:</p><ul><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl22" href="http://smacss.com/book/type-base">Base</a>—These are defaults styles, usually for single element selectors.</li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl23" href="http://smacss.com/book/type-layout">Layout</a>—Divides the page into sections, usually holding modules together.</li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl24" href="http://smacss.com/book/type-module">Module</a>—Reusable, modular parts of the design: callouts, sidebar sections, product lists, and so on.</li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl25" href="http://smacss.com/book/type-state">State</a>—Describes how the module or layout looks in a particular state, also in different page views.</li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl26" href="http://smacss.com/book/type-theme">Theme</a>—Describes how modules or layouts might look.</li></ul><p>In small projects, these can all be in the same file. In larger projects, multiple files are recommended.</p><p>However, there is a trick with the categories, and it involves thinking about what the styles actually do and what part of the site, design and functionality they apply to. This forces developers to ask during the building process “How are we going to code things, and why are we going to code them this way?” Thus, implicit in the categories are guidelines on how the styles are used, which further helps to prevent mixing styles across categories.</p><h4>What’s in a Name?</h4><p>The next important part of SMACSS is naming style rules. Clear class names are one of the key ways for knowing the category that a style rule is part of and what it does in the grand scheme of the page.</p><p>To indicate the differences between layout, module and state styles, Snook suggests appending prefixes to the class names. For layout, for example, you would add l- or layout-, creating a class name like .l-aside or .layout-aside. To indicate classes that create a state change, use .is-<em>state</em>, such as .is-active or .is-collapsed.</p><p>When creating names for modules, which include navigation bars, carousels, dialogs, widgets, tables, icons and so on, use the name of the module itself. For instance, an example module would be called, appropriately, .example (note that it is a class and not an ID). A callout module would be called .callout. If you need to add a state to a module, you know what to do: add .is-<em>state</em>, so, a collapsed callout module would be .callout.is-collapsed.</p><p>What about extending (or subclassing) a class? Easy. Instead of using a module’s class name as part of a combinator selector (and thus creating specificity issues), create a new class name based on the original class. For example .pod is extended by creating .pod-callout, and then you apply both styles to the element. With the new style, both styles have the same specificity, and thus the new style rules can play well with the first one.</p><h4>Focus on Good, Clean Code, and Don’t Worry About “Classitis”</h4><p>Clearly, one of the objectives of SMACSS (much like OOCSS) is to create shallow instead of deep selectors with the fewest generations of elements, striving for the shallowest selector possible. If you follow the recommendations in the <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl27" href="http://www.sitepoint.com/css-architectures-new-best-practices/">first article</a> in this series, you’re well on your way. But a little reminder never hurts, so to help limit the number of elements in a selector, follow these rules:</p><ul><li>Avoid tag selectors for common elements unless they are completely predictable. Using a class is preferable, even if you think the element is going to stay predictable. This includes qualifying classes with elements.</li><li>Use class names as the right-most (key) selector.</li><li>Use child selectors (e &gt; f) instead of descendent selectors (e f).</li></ul><p>Another goal of creating shallow selectors is to eliminate issues with selector specificity. One of the primary ways to ensure that you won’t have any specificity wars within your CSS is to avoid IDs for selectors. Don’t dismiss IDs completely, however. In SMACSS, it’s okay to use them for layout sections and for JavaScript hooks.</p><p>Some of us have had the old-school best practice “Don’t use too many classes!” deeply ingrained into our front-end development psyche. However, when it comes to SMACSS (and most of the scalable CSS approaches), you’re better off adding classes to the elements in question and repeating the class in the HTML than you are creating and applying a bevy of overly specific styles, which is the true cause of classitis. You’ll find that using multiple well-named classes clarifies intent and increases the semantics of the elements in question.</p><h4>Benefits</h4><p>The benefit of SMACSS is the clarity that comes from being conscious about your coding from the very start. Categories help slash redundancy, and naming conventions greatly aid efficiency in quickly identifying style rules in the CSS.</p><h4>Successes</h4><p>Snook developed SMACSS from his experiences working on enormous Web projects, one of the most notable being the redesign of Yahoo mail. He has had great success applying his principles with large sites built by large teams.</p><h3 id="CSS_for_GrownUps">CSS for Grown Ups</h3><p>Andy Hume, the creator of <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl28" href="https://speakerdeck.com/u/andyhume/p/css-for-grown-ups-maturing-best-practises">CSS for Grown Ups</a>, jokingly refers to his system as “CSS for grumpy old people.” (You can watch a video <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl29" href="http://www.youtube.com/watch?v=ZpFdyfs03Ug">here</a>.) Like many of the creators of scalable approaches, Hume is concerned that our industry has become married to archaic, so-called best practices (most, ironically, created by developers who worked alone). He thinks that front-end developers have trudged unwittingly down a path that creates CSS that is feared and despised in most projects. This front-end code adheres to Web standards at ridiculous lengths to keep content and session separate, but it pays no mind to managing style and project complexity.</p><p>It’s clear that we need to optimize code for change. With CSS for Grown Ups, the goal is to style modules, not pages, and to go a step further by having a style module library that you can reuse.</p><h4>Layers, Like an Onion. Or Cakes (or Parfaits)<a
id="ctl00_MTContentSelector1_mainContentContainer_ctl30" href="http://www.hark.com/clips/psfbxymylw-theres-a-lot-more-to-ogres-than-people-think">*</a></h4><p>Much like the use of categories in SMACSS, CSS for Grown Ups describes styles being in “layers.” A style’s layer is related to:</p><ul><li>Document—From HTML code, element selectors.</li><li>Base styles—Applies to element selectors, typographical styles, colors.</li><li>Module styles—Lists, navigation, promo box, and so on.</li><li>Layout styles—Establishes the grid or columns and page layout.</li></ul><p>When creating selectors, be aware of whether they are document, base or module selectors, and make an effort to keep them all at the modular level. How will you know? If there is a tag as part of the selector, it will be a document style. However, if you create a class for it, you release it from the tag and make it a module style.</p><p>The goal is to try to avoid styles that are document-, base- or layout-related, and to shoot for ones that are module-related instead. Why? Let’s look at an example:</p><pre>         .promo-box h2 { ... }</pre><p>This selector is a module-level selector (.promo-box) combined with a document level selector (h2). This is all well and good at the outset, but what if somewhere down the line the structure of the HTML changes?</p><p>Instead, we should be shooting for the document and the module to be less tightly coupled so that the selector can be scaled in the future. This example does just that:</p><pre>         .promo-box-h { ... }</pre><p>In this instance, the style is not tied to a document’s element, and is thus far more flexible and portable, as it can be applied to anything, even elements that haven’t yet been invented in HTML.</p><h4>Free Your Selector Name, and the Rest Will Follow</h4><p>It should not surprise you that CSS for Grownups epitomizes the tenets of organize, structure and inform. According to Hume, styling with clear, informative class names is “like an API into your document—an API lets you style your document in the most simple and efficient manner.” Class names should be descriptive and should have meaning within the context of the site you’re working on. They should make sense to the members of the team working on the site so that you know which shared terms to reuse.</p><p>Like the other approaches, CSS for Grownups advocates creating and using modules. And like OOCSS and SMACSS approaches, the names of the modules should be descriptive and semantic and not tied to location or appearance:</p><pre>         .promo-box { ... }</pre><p>CSS for Grownups has a methodology for extending or substyling a module. Just use the module’s name, append it with two dashes (&#8211;), and add a clear, informative name for the extension, like so:</p><pre>         .promo-box--light { ... }</pre><p>The two dashes indicate that the style is an extension of the first and also that it is dependent on the first. Thus, it must come after the first style in the source order of the CSS in order to overwrite one or more style rules in the original.</p><h4>Use Helpers. Be a Sharer</h4><p>To handle presentation issues, Hume recommends using “surgical layout helpers,” which are standalone classes that provide either padding or margin. Here’s an example:</p><pre>         .margin-top {margin-top: 1em;}</pre><p>This would be the style you could add to whatever element needed it on the page, instead of wrapping that style into a component. Then these classes can be used on a case-by-case basis when a module needs to be spaced vertically on a page. Use these helper styles in your base stylesheet so that they can be used easily throughout the project.</p><p>Finally, writing online style guides is strongly recommended as a way to codify the naming and structure established and to disseminate this information to the team, making it available for those who will work on, add to and alter the site in the future. The style guide and corresponding module library needs be in code so that team members don’t have to reinvent the wheel to implement repeated visual styles.</p><h4>Benefits</h4><p>As Hume stated in his presentation at SXSW 2012, “Nobody is really smart enough to style web pages.” And because of this, he argues that we need certain constraints and parameters such as those supplied by CSS for Grownups. Constraints are good—they are a way to manage complexity. Hume developed CSS for Grownups as a way to manage complexity of CSS over large sites, over time and amongst teams of developers. Furthermore, CSS for Grownups creates what Hume calls a “design-meets-development touchpoint,” where the design language of an organization is turned into code, and clear collaboration from both teams results in a higher-quality product.</p><h4>Successes</h4><p>CSS for Grownups has roots in the vast amount of work that Hume did while he was at Clearleft, which has had many large clients, such as Channel 4, Amnesty International, and Mozilla. Now that he is at the <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl36" href="http://www.guardiannews.com/">Guardian</a>, he has successfully applied his system to create a framework for the front-end developers there.</p><h2>Progress, Not Perfection</h2><p>In his presentation <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl37" href="https://vimeo.com/44773888">Breaking Good Habits</a>, Harry Roberts accurately states that “CSS is such a mess that even when you clean it up, it’s still a mess.” Our goal is to make our CSS better, not perfect. So look at each of these approaches with an open mind. Remember, the point is not to drive yourself crazy trying to get your CSS to fit perfectly within some methodology. Even if you adopt only some of the techniques, you still gain the benefits of fewer lines of code that will scale.</p><p>The scalable and modular approaches all have pieces of genius and brilliance to them, and are particularly great when you are starting to code a project from scratch. But what do you do when you have to deal with a mountain of existing CSS, whose sheer immensity strikes fear in your heart? The next article will share a process to coax order and sanity into the wildest of CSS beasts, so stay tuned!</p><h2>Links for Further Reading</h2><ul><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl38" href="http://gotofritz.net/blog/geekery/structuring-css/">Structuring CSS – State of Play in 2012</a></li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl39" href="http://viget.com/inspire/css-squareoff">CSS Strategy Square-off</a></li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl40" href="http://engineering.appfolio.com/2012/11/16/css-architecture/">CSS Architecture</a></li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl41" href="http://nimbleworks.co.uk/blog/css-id-selectors-never-say-never/">CSS ID Selectors: Never Say Never</a></li></ul><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/css-architectures-scalable-and-modular-approaches/feed/</wfw:commentRss> <slash:comments>1</slash:comments> <series:name><![CDATA[CSS Architectures]]></series:name> </item> <item><title>HTML5, Older Browsers and the Shiv</title><link>http://www.sitepoint.com/html5-older-browsers-and-the-shiv/</link> <comments>http://www.sitepoint.com/html5-older-browsers-and-the-shiv/#comments</comments> <pubDate>Tue, 23 Apr 2013 04:22:37 +0000</pubDate> <dc:creator>Dmitri Lau</dc:creator> <category><![CDATA[Browsers]]></category> <category><![CDATA[HTML5]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[HTML5 Dev Center]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65558</guid> <description><![CDATA[Dmitri Lau looks at how to use the HTML5Shiv tool to address the inability of certain older browsers to correctly interpret some HTML5 elements.]]></description> <content:encoded><![CDATA[<p></p><p>HTML5 introduced a few semantic elements that are not supported in older browsers. Some of these new elements are no different than generic block elements so they don&#8217;t pose any compatibility problems. All you need to ensure compatibility is to add a CSS rule to your website that causes the relevant elements to behave like block elements.</p><p>But Internet Explorer versions 8 and under pose a challenge. Any element not in the official roster of elements cannot be styled with CSS. That means we cannot make then behave like block elements or give them any formatting.</p><p>For example, the following code will not work.</p><pre class="brush: xml; title: ; notranslate">
&lt;style&gt;
section {display: block}
&lt;/style&gt;
&lt;section&gt;This is on its own line.&lt;/section&gt;
&lt;section&gt;This should appear on a separate line.&lt;/section&gt;
</pre><p>But that&#8217;s not all. These new elements behave as if they don&#8217;t exist. For example, the following CSS won&#8217;t work, since the <code>section</code> element won&#8217;t match the universal selector.</p><pre class="brush: xml; title: ; notranslate">
&lt;style&gt;
body * span {color: red}
&lt;/style&gt;
&lt;body&gt;
  &lt;section&gt;
    &lt;span&gt;This should be red, but won't be red in IE 8.&lt;/span&gt;
  &lt;/section&gt;
&lt;/body&gt;
</pre><p>Fortunately for us, a workaround exists that allows Internet Explorer (IE) to recognize these new elements allowing them to be styled, and thus giving us full use of these new semantic tags. It&#8217;s a tool called <a
href="http://code.google.com/p/html5shiv/">HTML5Shiv</a>.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p><em>As noted on the linked Google page, &#8220;shiv&#8221; and &#8220;shim&#8221; are interchangeable terms in this context.</em></p><p>But how did we go from IE not even acknowledging the existence of this element, to now being able to use it?</p><p>The trick is that calling <code>document.createElement("section")</code> will suddenly cause IE to recognize the <code>section</code> element. No one knows why, but it works and you don&#8217;t even need to use the node returned by that function.</p><p>But you need to make sure to call it early on in your website before any of those elements are used, otherwise it won&#8217;t work.</p><p>You will need to call it for each and every new HTML5 elements like so:</p><pre class="brush: jscript; title: ; notranslate">
&quot;abbr article aside audio bdi canvas data datalist details figcaption figure &quot;+
  &quot;footer header hgroup main mark meter nav output progress section &quot; +
  &quot;summary template time video&quot;
  .replace(/\w+/g, function(a){ document.createElement(a) });
</pre><p>Notice we&#8217;re using the <code>replace</code> method of the <code>string</code> object to succinctly iterate over each contiguous length of characters matched by the regular expression and executing the callback function for each character block which in turn calls <code>createElement</code>.</p><p>Here on in, we&#8217;ll call this method, &#8220;shivving the document&#8221;, so that the document can render the new HTML5 elements.</p><p>Now our previous two HTML examples work. But that&#8217;s not all there is to it.</p><h2>Pitfall 1: HTML5 and innerHTML</h2><p>If HTML is being generated using <code>innerHTML</code> and it is called on a node not currently attached to a document (AKA an orphaned node), then it&#8217;s deja vu all over again. The following two examples will not render the <code>section</code> element, even though it&#8217;s run on a document already shivved.</p><pre class="brush: jscript; title: ; notranslate">
var n1 = document.getElementById(&quot;n1&quot;);
n1.parentNode.removeChild(n1);
n1.innerHTML = &quot;&lt;section&gt;Sect 1&lt;\/section&gt;&quot;;  //won't work
</pre><pre class="brush: jscript; title: ; notranslate">
var n2 = document.createElement(&quot;div&quot;);
n2.innerHTML = &quot;&lt;section&gt;Sect 2&lt;\/section&gt;&quot;;  //won't work
</pre><p>In the second example above, if we append the node to the document first before calling <code>innerHTML</code>, then it will work:</p><pre class="brush: jscript; title: ; notranslate">
var n2 = document.createElement(&quot;div&quot;);
document.body.appendChild(n2);
n2.innerHTML = &quot;&lt;section&gt;Sect 2&lt;\/section&gt;&quot;;  //works
</pre><p>We can conclude that although we shivved the document earlier on, orphaned elements do not benefit from the shiv when calling <code>innerHTML</code>.</p><p>What can we do? For starters, whenever we need to set <code>innerHTML</code> we should append it to the document first. An alternative is to first shiv the <code>document</code> property of the orphan before working with the orphan.</p><p>First let&#8217;s put our shiv in its own function.</p><pre class="brush: jscript; title: ; notranslate">
function iehtml5shiv(doc) {
  &quot;abbr article aside audio bdi canvas data datalist details &quot; +
    &quot;figcaption figure footer header hgroup main mark meter nav &quot; +
    &quot;output progress section summary template time video&quot;
    .replace(/\w+/g, function(a){ doc.createElement(a) });
}
</pre><p>The next time we have an orphan element, we can do this:</p><pre class="brush: jscript; title: ; notranslate">
var n1 = document.createElement(&quot;div&quot;);
iehtml5shiv(n1.document);
n1.innerHTML = &quot;&lt;section&gt;Sect 1&lt;\/section&gt;&quot;;  //works
</pre><p>Notice how it&#8217;s just like shivving the document, but on the <code>document</code> property of the element. And notice we&#8217;re accessing <code>document</code> instead of <code>ownerDocument</code>. Both are different things as shown here:</p><pre class="brush: jscript; title: ; notranslate">
alert(n1.document == document);  //false
alert(n1.ownerDocument == document);  //true
</pre><p>Now we have two methods to make sure our call to <code>innerHTML</code> works when handling HTML5 elements.</p><h2>Pitfall 2: cloneNode</h2><p>It appears our cousin <code>cloneNode</code> is also susceptible to losing its shiv. Any HTML5 elements which are cloned, or have had their parents cloned, will lose their identity.</p><p>Notice how the below element has colons in its <code>nodeName</code>, meaning it&#8217;s being confused for an element from another namespace.</p><pre class="brush: jscript; title: ; notranslate">
var n2 = n1.cloneNode(true);
alert(n2.innerHTML);  //outputs: &lt;:section&gt;Sect 1&lt;/:section&gt;
</pre><p>This happens even if the node was already attached to the document.</p><p>There isn&#8217;t much we can do here except roll out your own implementation of <code>cloneNode</code>, which is trivial enough.</p><h2>Pitfall 3: Printing</h2><p>Whenever you print a webpage, IE appears to generate a new document before printing which means all the shiv workarounds are not preserved.</p><p>There isn&#8217;t much you can do to mitigate this. The HTML5Shiv tool works around this by listening for the <code>onbeforeprint</code> event and replacing all the HTML5 elements on the page with normal elements and then doing the reverse on the <code>onafterprint</code> event.</p><p>Thankfully, the HTML5Shiv tool does that nicely for us.</p><h2>References</h2><ul><li>The HTML5Shiv tool: <a
href="https://github.com/aFarkas/html5shiv">https://github.com/aFarkas/html5shiv</a></li><li>The story of the HTML5 Shiv: <a
href="http://paulirish.com/2011/the-history-of-the-html5-shiv/">http://paulirish.com/2011/the-history-of-the-html5-shiv/</a></li></ul><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/html5-older-browsers-and-the-shiv/feed/</wfw:commentRss> <slash:comments>9</slash:comments> </item> <item><title>MySQL Views</title><link>http://www.sitepoint.com/mysql-views/</link> <comments>http://www.sitepoint.com/mysql-views/#comments</comments> <pubDate>Tue, 23 Apr 2013 02:41:17 +0000</pubDate> <dc:creator>Richard Kotze</dc:creator> <category><![CDATA[Databases]]></category> <category><![CDATA[Open source]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[mysql]]></category> <category><![CDATA[RMDBS]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65554</guid> <description><![CDATA[Richard Kotze takes a look at the advantages and disadvantages of using MySQL views to manage database tables.]]></description> <content:encoded><![CDATA[<p></p><p>You have just written a new feature for your awesome application that searches through your database to find &#8216;x&#8217; and you run some tests to check that the returned result is correct.</p><p>Unfortunately, your test fails because it returns more results than expected. At first this is not obvious because it&#8217;s been a while since you worked on the application, but eventually you realise that every search should be automatically filtered out by a boolean field.</p><p>You may have run into a similar situation where you or someone has forgotten to filter by a value in field x and it&#8217;s now potentially showing incorrect data, thereby damaging business. Fortunately, there are some tests in place to catch this.</p><p>Let&#8217;s work through an example. You have a user table and, with good reason, you are utilizing a boolean field to represent what the state of the user is, perhaps to determine if it is disabled. You could copy data from a “live table” to a “disabled table” but you feel the complexity and overhead to implement this is too high, because of other user related tables.</p><p>With the above scenario in mind, I think <i>MySQL Views</i> can improve on this solution. Views are quite simple things. They present a table based on the defined SELECT query. We can create a view that will only return users that are enabled in the system and which will prevent future features from including disabled users.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p>I&#8217;ll explain how to create this view and how to use it in your application. Something to note is MySQL views are only available from version 5.</p><p>Here is the basic user table the view will be based on:</p><pre>CREATE  TABLE `users` (
`user_id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`first_name` VARCHAR(100) NULL ,
`last_name` VARCHAR(100) NULL ,
`username` VARCHAR(100) NULL ,
`dob` DATETIME NULL ,
`disabled` BIT NULL DEFAULT 0 ,
PRIMARY KEY (`user_id`) );</pre><p>Below is the query that will<i> create a MySQL view </i>for the above user table.</p><pre>CREATE OR REPLACE ALGORITHM = MERGE VIEW `v_users_enabled`
(`firstName`, `lastName`, `username`, `dob`)
AS
SELECT `first_name`, `last_name`, `username`, `dob`
FROM `users`
WHERE `disabled` = 1;</pre><h2>How does it work?</h2><p>Here is a breakdown of the keywords used to create a view.</p><h3>CREATE OR REPLACE</h3><p>This creates a new view and is required. Optionally you can add OR REPLACE if you want to make certain it is created but if you know the view exists already you can use ALTER to make changes to an existing view.</p><h3>ALGORITHM = MERGE</h3><p>This is an optional statement and by not defining one or explicitly stating ALGORITHM = UNDEFINED, MySQL will choose between two options that best fit the SELECT statement, i.e. MERGE or TEMPTABLE. MySQL will try to choose MERGE over TEMPTABLE where possible because it is more efficient. I will discuss more about the algorithm after going through these core points.</p><h3>VIEW</h3><p>Is a required statement and is used to give a name to the view. Crucially a view <b>cannot </b>have the same name as a table because they share the same name space.</p><p>The column list part is optional and by default the column names in the SELECT statement are used. If you choose to define column names they are comma separated, must be unique and match the number of columns in the SELECT.</p><h3>AS</h3><p>Is required and where you define the SELECT query.</p><p>Querying a view is the same as when querying a table. Here&#8217;s a simple example:</p><pre>SELECT * FROM v_users_enabled</pre><h2>More about the algorithm</h2><p>When defining the algorithm, you have three options to choose from: MERGE, TEMPTABLE or UNDEFINED.</p><p>We now know that UNDEFINED lets MySQL choose the appropriate option, but what do the other two options mean?</p><p><b>MERGE </b>is the fastest out of the two options. The view column list replaces what is in the SELECT statement, essentially merging faster than <b>TEMPTABLE</b> as that generates a new temporary table that is queried upon and which has <b>no indexes</b>. MySQL will warn you if you try to use MERGE when a TEMPTABLE should be used and will change it to TEMPTABLE.</p><p>When will the <b>TEMPTABLE </b>option be used? If you use any aggregation function, DISTINCT, LIMIT, GROUP BY, HAVING, sub query or literal values (i.e. no table).</p><h2>Minor performance trade off</h2><p>Unfortunately, MySQL views will hinder performance rather than improve it. It is important to think about your views and to use MERGE where possible to minimise performance reduction.</p><p>Provided your performance budgets can take the hit to better manage complexity and create a useful separation this, in my view, is a worthy trade off because you are taking a query with certain where clauses that may need to be applied to other queries. This is nicely contained within a view and database level users can query against this returning them the correct results, without them having to remember they need these additional where clauses.</p><p>The downside of this containment is that it would be possible to write a complex query within the view which is now hidden. Queries with more where clauses on this view will make the overall query a monster and potentially inefficient. A judgement call will need to be made on how complex the view SELECT query can be without compromising performance.</p><p>To better optimize for performance when using a view, use the MERGE algorithm and when creating your index add the fields in your WHERE clauses that exist in the view first. It is important they are put in the correct order, as usual when creating indexes for expected queries. You can use EXPLAIN to check your query and make sure its behaving as you expect.</p><h2>Benefits and Negatives</h2><p>The <b>benefits </b>of using a view:</p><ul><li>Provide a useful data separation from application by containing the need to remember specific fields the query needs to filter by for all SELECT statements within the database.</li><li>Tables can change over time and you need to add some new fields that you intend to filter by for most SELECT queries. All that needs to change is the SELECT statement with the new fields after altering the tables. Then updating the application will be easier as you may only need to remember to change it in a few places.</li><li>They can make your SELECT queries more readable.</li></ul><p>The <b>negatives </b>of using a view:</p><ul><li>When the TEMPTABLE algorithm is used no index is used.</li><li>They could hide a complex query and with querying the view could turn it into a sluggish query.</li><li>Using the MERGE algorithm limits your view SELECT statement to basic querying only.</li><li>You may choose the MERGE algorithm but if MySQL thinks it should use TEMPTABLE then it will change it.</li><li>If your view does not have a one-to-one relationship with the table then it is not updatable.</li><li>When you do add or change a table you will still need to update the CUD statements in your application.</li><li>You <b>cannot </b>associate a trigger with a view.</li></ul><h2>Noteworthy quirks</h2><p>If you want to use ORDER BY in your view SELECT statement it is worth noting that this cannot be overridden when you query the view using a different order.</p><p>If you decide to put a LIMIT in your view and then use another LIMIT when you query the view it is undefined which LIMIT applies.</p><p>If you are interested in making a view updatable see <a
href="http://dev.mysql.com/doc/refman/5.6/en/view-updatability.html">MySQL</a><a
href="http://dev.mysql.com/doc/refman/5.6/en/view-updatability.html">website</a>.</p><h2>Conclusion</h2><p>MySQL views are a useful tool and provide a good solution in particular scenarios. It is clear that views have their limits and it is important to be aware of them. Used in the right way your next app can benefit from flexible containment and control over how the data is accessed.</p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/mysql-views/feed/</wfw:commentRss> <slash:comments>4</slash:comments> </item> <item><title>Using CSS Grid Layout and Blend 5 to Build a Game</title><link>http://www.sitepoint.com/using-css-grid-layout-and-blend-5-to-build-a-game/</link> <comments>http://www.sitepoint.com/using-css-grid-layout-and-blend-5-to-build-a-game/#comments</comments> <pubDate>Wed, 17 Apr 2013 01:14:51 +0000</pubDate> <dc:creator>David Rousset</dc:creator> <category><![CDATA[CSS]]></category> <category><![CDATA[CSS3]]></category> <category><![CDATA[Gaming]]></category> <category><![CDATA[HTML]]></category> <category><![CDATA[HTML5]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[HTML5 Dev Center]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65462</guid> <description><![CDATA[David Rousset reveals a long-held Microsoft secret about what drove the development of CSS Grid Layout. Tetris is involved.]]></description> <content:encoded><![CDATA[<p></p><p>I’d like to share with you a mysterious internal secret kept within Microsoft for a long time. It’s the real story behind the concept of the <a
href="http://www.w3.org/TR/css3-grid-layout/">CSS Grid Layout</a> imagined by Microsoft for IE10 and Windows Store Apps.</p><p>Most of you probably think that this specification was designed to give developers a better layout engine for their websites and applications. But the original motivation was completely different. The very first aim was to be able to create a Tetris-like game in an easy way!</p><p>I’m sure you’re not convinced yet. That’s why I’m going to prove it to you using Blend 5 as a companion. Ok, let’s go!</p><p><strong><span
style="text-decoration: underline;">Pre-requisites:</span></strong> to follow this tutorial, you need first to:</p><ol><li>Download/buy &amp; install <strong>Windows 8 RTM</strong> on your machine: <a
href="http://msdn.microsoft.com/en-US/windows/apps/br229516.aspx">http://msdn.microsoft.com/en-US/windows/apps/br229516.aspx</a></li><li>Download &amp; install the free edition of <strong>Visual Studio 2012 Express RTM </strong>for Windows 8: <a
href="http://msdn.microsoft.com/en-US/windows/apps/br229516.aspx">http://msdn.microsoft.com/en-US/windows/apps/br229516.aspx</a> that includes Expression Blend 5 for Visual Studio or use the higher versions.</li></ol><h2>Step 1: discover the secret behind the CSS Grid Layout thanks to Blend 5</h2><p>Launch Expression Blend 5 and create a new HTML (Windows Store) project of type Blank App. Name it “<em><strong>TheRealCSSGridStory</strong></em>”:<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p><img
alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/2502.image_5F00_thumb_5F00_00459BE1.png" width="450" height="352" border="0" /></p><p>Replace:</p><pre class="code"><span style="color: blue;">&lt;</span><span style="color: maroon;">p</span><span style="color: blue;">&gt;</span>Content goes here<span style="color: blue;">&lt;/</span><span style="color: maroon;">p</span><span style="color: blue;">&gt;
</span></pre><p>With:</p><pre class="code"><span style="color: blue;">&lt;</span><span style="color: maroon;">div </span><span style="color: red;">class</span><span style="color: blue;">="mainGrid"&gt;
&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;
</span></pre><p>Let’s create a grid containing 10 columns and 20 lines, whatever the screen’s resolution, by using fraction units. For that, add this CSS rule:</p><pre class="code"><span style="color: maroon;">.mainGrid </span>{
    <span style="color: red;">display</span>: <span style="color: blue;">-ms-grid</span>;
    <span style="color: red;">width</span>: <span style="color: blue;">100%</span>;
    <span style="color: red;">height</span>: <span style="color: blue;">100%</span>;
    <span style="color: red;">-ms-grid-columns</span>: <span style="color: blue;">(1fr)[10]</span>;
    <span style="color: red;">-ms-grid-rows</span>: <span style="color: blue;">(1fr)[20]</span>;
}</pre><p>Select in the Live DOM the <em>&lt;div&gt; mainGrid</em> element and you should obtain this:</p><p><img
alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/7220.image_5F00_thumb_5F00_1173967B.png" width="640" height="418" border="0" /></p><p>Let’s draw a shape inside this beautiful grid. Add this block of HTML inside the main grid:</p><pre class="code"><span style="color: blue;">&lt;</span><span style="color: maroon;">div </span><span style="color: red;">class</span><span style="color: blue;">="shape1"&gt;
&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;
</span></pre><p>And insert this CSS associated with it:</p><pre class="code"><span style="color: maroon;">.shape1 </span>{
    <span style="color: red;">-ms-grid-column</span>: <span style="color: blue;">4</span>;
    <span style="color: red;">-ms-grid-row</span>: <span style="color: blue;">3</span>;
    <span style="color: red;">-ms-grid-column-span</span>: <span style="color: blue;">3</span>;
    <span style="color: red;">-ms-grid-row-span</span>: <span style="color: blue;">2</span>;
    <span style="color: red;">background-color</span>: <span style="color: blue;">red</span>;
}</pre><p>You should now see that in Blend 5:</p><p><img
alt="image" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/5556.image17_5F00_thumb_5F00_4CB47F2B.png" width="450" height="276" border="0" /></p><p>Cool, but nothing yet looks like to a Tetris gaming piece. Let’s work on that. Add these two DIVs inside the shape1:</p><pre class="code"><span style="color: blue;">&lt;</span><span style="color: maroon;">div </span><span style="color: red;">class</span><span style="color: blue;">="line1shape1"&gt;&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;
&lt;</span><span style="color: maroon;">div </span><span style="color: red;">class</span><span style="color: blue;">="line2shape1"&gt;&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;
</span></pre><p>and replace the previous <em>.shape1</em> rule with this block of CSS:</p><pre class="code"><span style="color: maroon;">.shape1 </span>{
    <span style="color: red;">-ms-grid-column</span>: <span style="color: blue;">4</span>;
    <span style="color: red;">-ms-grid-row</span>: <span style="color: blue;">3</span>;
    <span style="color: red;">-ms-grid-column-span</span>: <span style="color: blue;">3</span>;
    <span style="color: red;">-ms-grid-row-span</span>: <span style="color: blue;">2</span>;
    <span style="color: red;">display</span>: <span style="color: blue;">-ms-grid</span>;
    <span style="color: red;">-ms-grid-columns</span>: <span style="color: blue;">1fr 1fr 1fr</span>;
    <span style="color: red;">-ms-grid-rows</span>: <span style="color: blue;">1fr 1fr</span>;
    <span style="color: red;">width</span>: <span style="color: blue;">100%</span>;
    <span style="color: red;">height</span>: <span style="color: blue;">100%</span>;
}
<span style="color: maroon;">.line1shape1 </span>{
    <span style="color: red;">-ms-grid-column-span</span>: <span style="color: blue;">2</span>;
    <span style="color: red;">background-color</span>: <span style="color: blue;">red</span>;
}
<span style="color: maroon;">.line2shape1 </span>{
    <span style="color: red;">-ms-grid-column</span>: <span style="color: blue;">2</span>;
    <span style="color: red;">-ms-grid-row</span>: <span style="color: blue;">2</span>;
    <span style="color: red;">-ms-grid-column-span</span>: <span style="color: blue;">2</span>;
    <span style="color: red;">background-color</span>: <span style="color: blue;">red</span>;
}</pre><p>The shape1 is currently spanning on three columns and two rows. I’ll then create a new grid inside this area defined by three columns and two rows in order to have cells having exactly the same size as the cells of the main grid, whatever the resolution might be.</p><p>Once done, I’ll create two lines in order to mimic the Z shape of the Tetris game. You should now have this result:</p><p><img
alt="z-shape in Tetris" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/0334.image_5F00_thumb_5F00_520EF183.png" width="450" height="274" border="0" /></p><p>Even better, play with the various views available in the Device tab and you’ll see that our game is already implementing a <a
href="http://en.wikipedia.org/wiki/Responsive_web_design">responsive design</a>! This is freaking cool, isn’t it?</p><p>Here, for instance, is the outputs for the snapped view and the portrait view:</p><p><img
alt="" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/1488.image_5F00_thumb_5F00_544E09F5.png" width="550" height="262" border="0" /><br
/> <img
alt="z-shape in landscape view" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/8345.image_5F00_thumb_5F00_119670D0.png" width="325" height="286" border="0" /></p><p>Let’s now resolve another problem.</p><p>The Tetris grid gaming grid is composed of squares. Our current responsive design is stretching 100% width. Building a Windows 8 application for the Windows Store will most of the time meet widescreen monitors (current tablets are 1366&#215;768 or 1920&#215;1080 and most desktop PC have a 16/9 ratio). Let’s then assume that targeting a widescreen ratio is addressing almost all cases. To compute the proper responsive width, you need to do: 9/16 * 10/20 (the ratio of the main gaming grid) which equals to: <strong>28.125%.</strong></p><p>Add this rule to target the main grid in full screen landscape mode:</p><pre class="code"><span style="color: blue;">@media </span>screen and (-ms-view-state: fullscreen-landscape) {
    <span style="color: maroon;">.mainGrid </span>{
        <span style="color: red;">width</span>: <span style="color: blue;">28.125%</span>;
        }
}</pre><p>Let’s now center the gaming grid by using… the CSS Grid Layout again! (And you should now start to believe it was truly designed for Tetris!)</p><p>Switch the <em>body</em> element to <em>–ms-grid</em> made of one column and one row:</p><pre class="code"><span style="color: maroon;">body </span>{
    <span style="color: red;">display</span>: <span style="color: blue;">-ms-grid</span>;
    <span style="color: red;">-ms-grid-columns</span>: <span style="color: blue;">1fr</span>;
    <span style="color: red;">-ms-grid-rows</span>: <span style="color: blue;">1fr</span>;
    <span style="color: red;">width</span>: <span style="color: blue;">100%</span>;
    <span style="color: red;">height</span>: <span style="color: blue;">100%</span>;
}</pre><p>Now simply add this attribute to the CSS associated to the the main grid:</p><pre class="code"><span style="color: red;">-ms-grid-column-align</span>: <span style="color: blue;">center</span>;</pre><p>And the grid is now centered:</p><p><img
alt="" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/2553.image_5F00_thumb_5F00_110B1794.png" width="640" height="332" border="0" /></p><p>At this stage, you’re probably already shocked. &#8220;<em>How could I have missed this incredible secret?</em>&#8221; you’re wondering to yourself.</p><p>Take a breath.</p><p>Now that you know THE secret, let’s continue this tutorial together to discover other awesome possibilities delivered by the CSS specifications combined together.</p><h2>Step 2: moving or rotating a shape</h2><p>My first idea was to try avoiding JS by using as much CSS as possible. I then first tried to use <a
href="http://blogs.msdn.com/b/davrous/archive/2011/12/06/introduction-to-css3-animations.aspx">CSS3 Animations</a> to move and animate the shape on the various rows/columns. But the bad news is that you can’t change the <em>–ms-grid-column</em> or <em>–ms-grid-row</em> values via CSS3 animations. This will then be the job of some JavaScript code.</p><p>I then started to think about how I will rotate the shape. <a
href="http://www.w3.org/TR/css3-transforms/">CSS Transforms</a> seemed to be perfectly adapted for that. Let’s check that by doing some experiments. Blend 5 is really cool for that as you can directly see live the outcome of your changes.</p><p>Add a rotation of 90 degrees on <em>shape1</em> by adding this class to its DIV element:</p><pre class="code"><span style="color: maroon;">.shape1rotated </span>{
    <span style="color: red;">transform</span>: <span style="color: blue;">rotate(90deg)</span>;
}</pre><p>I’m sure you weren’t expecting this:</p><p><img
title="image" alt="Rotated shape" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/4666.image_5F00_thumb_5F00_15CE3F67.png" width="240" height="122" /></p><p>Problem: it’s not properly aligned to the gaming grid. To align our shape to the grid, we need some small adjustments:</p><pre class="code"><span style="color: maroon;">.shape1rotated </span>{
    <span style="color: red;">transform-origin</span>: <span style="color: blue;">33% 50%</span>;
    <span style="color: red;">transform</span>: <span style="color: blue;">rotate(90deg) translateX(-33%)</span>;
}</pre><p>And we now have the same rotation as a Tetris-like game. Here are two screenshots before/after the rotation:</p><p><img
alt="z-shape before rotation" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/3414.image_5F00_22C81F78.png" /><br
/> <img
alt="z-shape after rotation" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/8272.image_5F00_0E4560AB.png" /></p><p>We can even go further than that by using a transition set on shape1 via this:</p><pre class="code"><span style="color: red;">transition</span>: <span style="color: blue;">all 1s ease-out</span>;</pre><p>And now, removing/adding the <em>.shape1rotated</em> class on the shape1 DIV will trigger a smooth rotation animation.</p><p>Check out the result inside Blend 5 thanks to this short video:</p><div
class="video-js-box"><video
id="MSPointerEventsArticleVideo" class="video-js" poster="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo1.jpg" preload="preload" controls="controls" width="800" height="450"><source
type="video/mp4; codecs=&quot;avc1.42E01E, mp4a.40.2&quot;" src="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo1.mp4" /><source
type="video/webm; codecs=&quot;vp8, vorbis&quot;" src="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo1.webm" /><object
id="flash_fallback_1" class="vjs-flash-fallback" data="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf"<br /> width="800" type="application/x-shockwave-flash" height="450"><param
name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" /><param
name="allowfullscreen" value="true" /><param
name="flashvars" value="config={&quot;playlist&quot;:[&quot;http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo1.jpg&quot;, {&quot;url&quot;: &quot;http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo1.mp4&quot;,&quot;autoPlay&quot;:false,&quot;autoBuffering&quot;:true}]}" /> <img
title="No video playback capabilities." alt="Poster Image" src="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo1.jpg" width="800" height="450" /> </object></video></p><p
class="vjs-no-video"><strong>Download Video:</strong> <a
href="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo1.mp4">MP4</a>, <a
href="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo1.webm">WebM</a>, <a
href="http://videojs.com">HTML5 Video Player</a> by VideoJS</p></div><p>At this stage, we could think that this approach is the good one to build our game. But this is unfortunately not yet the case. Here’s why. Try moving the shape by simply changing its <em>–ms-grid-column</em> property. Blend 5 will reflect the changes directly. When not rotated, the shape can be moved up to the 8th column:</p><p><img
alt="z-shape moved to the 8th column" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/0118.image_5F00_4D7445B9.png" /></p><p>So far so good. But when you’re rotating it by adding the <em>.shape1rotated</em> class to the DIV:</p><p><img
alt="z-shape rotated to the 8th column" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/0525.image_5F00_5A70B67B.png" /></p><p>You see that there is still 1 row available on the right for the shape’s move. If you think we simply need to move it to the 9th row, you’re wrong! Indeed, here is what we’ll obtain on the 9th row:</p><p><img
alt="z-shape gets compressed when moved to the 9th row" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/1185.image_5F00_27A340B8.png" /></p><p>You probably forgot that we’re currently moving a DIV element displaying a grid layout of three columns and two rows matching exactly the underlying gaming grid. When moving it, we really have the feeling that this is a block part of the main grid we’re moving. But for this trick to work, we need at least three columns available to contain our shape element. If it’s contained in two columns (when set to the 9th column) or less, it will be “compressed”, as in the screenshot.</p><p>There are two ways to resolve that.</p><p>1 – Stop using CSS Transforms and draw the rotated shape using another grid definition. For instance, using three divs inside the shape instead of two. But using such an approach will prevent us having the nice CSS Animations in place.<br
/> 2 – Redefined the main grid to work on 12 columns instead of 10 and we’ll use only the columns from 2 to 11 (a sort of clipping area if you wish). This will resolve our “overflow” problem.</p><p>Let’s implement the second solution.</p><p>Redefine the main grid using this:</p><pre class="code"><span style="color: maroon;">.mainGrid </span>{
    <span style="color: red;">display</span>: <span style="color: blue;">-ms-grid</span>;
    <span style="background-color: #ffff00;"><span style="color: red;">-ms-grid-columns</span>: <span style="color: blue;">(1fr)[12]</span>;</span>
    <span style="color: red;">-ms-grid-rows</span>: <span style="color: blue;">(1fr)[20]</span>;
    <span style="color: red;">-ms-grid-column-align</span>: <span style="color: blue;">center</span>;
    <span style="color: red;">width</span>: <span style="color: blue;">100%</span>;
    <span style="color: red;">height</span>: <span style="color: blue;">100%</span>;
}</pre><p>To also have the proper ratio, you need to update the associated media query:</p><pre class="code"><span style="color: blue;">@media </span>screen and (-ms-view-state: fullscreen-landscape) {
    <span style="color: maroon;">.mainGrid </span>{
        <span style="background-color: #ffff00;"><span style="color: red;">width</span>: <span style="color: blue;">33.75%</span>;</span>
        }
}</pre><p>33.75% = 9/16 *12/20</p><p>Let’s also add a “virtual grid” to delimitate the space where we will be able to move the shapes.  Inside the main grid DIV, insert this one:</p><pre class="code"><span style="color: blue;">&lt;</span><span style="color: maroon;">div </span><span style="color: red;">class</span><span style="color: blue;">="virtualGrid"&gt;
&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;
</span></pre><p>Associated with this block of CSS:</p><pre class="code"><span style="color: maroon;">.virtualGrid </span>{
    <span style="color: red;">-ms-grid-column</span>: <span style="color: blue;">2</span>;
    <span style="color: red;">-ms-grid-column-span</span>: <span style="color: blue;">10</span>;
    <span style="color: red;">-ms-grid-row-span</span>: <span style="color: blue;">20</span>;
    <span style="color: red;">border-right-style</span>: <span style="color: blue;">dashed</span>;
    <span style="color: red;">border-left-style</span>: <span style="color: blue;">dashed</span>;
    <span style="color: red;">background-color</span>: <span style="color: blue;">#505A5A</span>;
}</pre><p>It will help to delimit the gaming area with a grey background and some dashed border lines.</p><p>Now, if I’m moving the Z shape on column 9, row 2, here is the result:</p><p><img
alt="z-shape at column 9" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/4544.image_5F00_21CDE152.png" /></p><p>If I’m rotating it with CSS Transforms, I can move it correctly on column 10:</p><p><img
alt="Rotated z-shape moved correctly to column 9" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/4048.image_5F00_07FC3BD4.png" /></p><h4>Bonus – handling the Portrait mode:</h4><p>If you’d like to support the portrait mode (which is even better for the Tetris grid game), add this CSS Media Query definition:</p><pre class="code"><span style="color: blue;">@media </span>screen and (-ms-view-state: fullscreen-portrait) {
        <span style="color: maroon;">.mainGrid </span>{
        <span style="color: red;">width</span>: <span style="color: blue;">106.66%</span>;
        }
}</pre><p>As the ratio need to be computed as = 16/9 * 12/20 = 106,66%.</p><p><img
alt="Tetris grid in landscape" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/1411.image_5F00_32C79A6A.png" /></p><h2>Step 3: adding some code to handle part of the game logic</h2><p>Now that we’ve solved the graphics part of the game using only some pure CSS &amp; HTML code, we need the help of JavaScript to move/rotate the shape in the gaming area. We’re going to re-implement the CSS logic via a JS object that’s going to be defined thanks to <a
href="http://msdn.microsoft.com/fr-fr/library/windows/apps/br229776.aspx">WinJS.Class</a>.</p><p>Open the &#8220;<em>TheRealCSSGridStory</em>&#8221; in Visual Studio 2012.</p><p>Create a <em>TetrisShapeZ.js</em> file in the JS directory and copy/paste this code:</p><pre>(<span style="color: blue;">function </span>() {
    <span style="color: maroon;">"use strict"</span>;
    <span style="color: blue;">var </span>ShapeZ = WinJS.Class.define(
    <span style="color: #006400;">/// Constructor - columnIndex is optional. If provided, defines the column the shape starts in
        </span><span style="color: blue;">function </span>(columnIndex) {
            <span style="color: #006400;">// We're creating the equivalent of this HTML block :
            // &lt;div class="shape1 "&gt;
            //     &lt;div class="line1shape1"&gt;&lt;/div&gt;
            //     &lt;div class="line2shape1"&gt;&lt;/div&gt;
            // &lt;/div&gt;
            </span><span style="color: blue;">this</span>._shape1 = document.createElement(<span style="color: maroon;">"div"</span>);
            <span style="color: blue;">var </span>line1 = document.createElement(<span style="color: maroon;">"div"</span>);
            <span style="color: blue;">var </span>line2 = document.createElement(<span style="color: maroon;">"div"</span>);
            <span style="color: blue;">this</span>._shape1.className = <span style="color: maroon;">"shape1"</span>;
            line1.className = <span style="color: maroon;">"line1shape1"</span>;
            line2.className = <span style="color: maroon;">"line2shape1"</span>;
            <span style="color: blue;">this</span>._shape1.appendChild(line1);
            <span style="color: blue;">this</span>._shape1.appendChild(line2);
            <span style="color: #006400;">// Boolean to indicate if the shape is in its default orientation mode or not
            // True means not rotated, false means rotated
            </span><span style="color: blue;">this</span>._defaultOrientation = <span style="color: blue;">true</span>;
            <span style="color: #006400;">// Setting the column position in the main grid
            </span><span style="color: blue;">if </span>(columnIndex) {
                <span style="color: blue;">this</span>._currentColPos = columnIndex;
                <span style="color: blue;">this</span>._shape1.style.msGridColumn = <span style="color: blue;">this</span>._currentColPos;
            }
            <span style="color: blue;">else </span>{
                <span style="color: blue;">this</span>._currentColPos = 1;
            }
            <span style="color: #006400;">// We always start at line 1
            </span><span style="color: blue;">this</span>._currentLinePos = 1;
            <span style="color: #006400;">// Boolean to know if the shape can be move/rotate or not
            // If true, this means we've reached the last line possible
            </span><span style="color: blue;">this</span>._fixed = <span style="color: blue;">false</span>;
        },
        {
            <span style="color: #006400;">/// Specify in which HTML element displayed in CSS Grid you'd like to work with
            /// width is the number of columns of the grid &amp; height is the number of lines
            </span>insertIntoGrid: <span style="color: blue;">function </span>(element, width, height) {
                element.appendChild(<span style="color: blue;">this</span>._shape1);
                <span style="color: blue;">this</span>._gridWidth = width;
                <span style="color: blue;">this</span>._gridHeight = height;
                <span style="color: #006400;">// These are the left &amp; bottom max limit for this shape
                // when displayed in default orientation mode
                </span><span style="color: blue;">this</span>._maxLeft = width - 3;
                <span style="color: blue;">this</span>._maxBottom = height - 1;
            },
            <span style="color: #006400;">/// Rotate the Z shape 90 degrees anti/clockwise using CSS Transforms
            /// by simply removing/adding the shape1rotated class
            </span>rotate: <span style="color: blue;">function </span>() {
                <span style="color: blue;">if </span>(!<span style="color: blue;">this</span>._fixed &amp;&amp; <span style="color: blue;">this</span>._defaultOrientation) {
                    <span style="color: #006400;">// rotating 90 degrees clockwise, it will trigger also the CSS Transition
                    </span>WinJS.Utilities.addClass(<span style="color: blue;">this</span>._shape1, <span style="color: maroon;">"shape1rotated"</span>);
                    <span style="color: blue;">this</span>._defaultOrientation = <span style="color: blue;">false</span>;
                    <span style="color: #006400;">// the left limit is now +1 vs the default orientation
                    </span><span style="color: blue;">this</span>._maxLeft = <span style="color: blue;">this</span>._gridWidth - 2;
                }
                <span style="color: blue;">else </span>{
                    <span style="color: blue;">if </span>(!<span style="color: blue;">this</span>._fixed &amp;&amp; <span style="color: blue;">this</span>._currentColPos &lt; <span style="color: blue;">this</span>._maxLeft) {
                        <span style="color: #006400;">// removing the shape1rotated will automatically reset the shape
                        // to its initial matrix and again the CSS Transition will do the
                        // animation for you
                        </span>WinJS.Utilities.removeClass(<span style="color: blue;">this</span>._shape1, <span style="color: maroon;">"shape1rotated"</span>);
                        <span style="color: blue;">this</span>._defaultOrientation = <span style="color: blue;">true</span>;
                        <span style="color: blue;">this</span>._maxLeft = <span style="color: blue;">this</span>._gridWidth - 3;
                    }
                }
            },
            <span style="color: #006400;">// Internal function called by public moveLeft/moveRight
            </span>_moveHorizontally: <span style="color: blue;">function </span>(direction) {
                <span style="color: blue;">if </span>(!<span style="color: blue;">this</span>._fixed &amp;&amp; (<span style="color: blue;">this</span>._currentColPos &lt; <span style="color: blue;">this</span>._maxLeft || direction === -1) &amp;&amp;
                (<span style="color: blue;">this</span>._currentColPos &gt; 2 || direction === 1)) {
                    <span style="color: blue;">this</span>._currentColPos = <span style="color: blue;">this</span>._currentColPos + direction;
                    <span style="color: blue;">this</span>._shape1.style.msGridColumn = <span style="color: blue;">this</span>._currentColPos;
                }
            },
            <span style="color: #006400;">/// Move the shape on the immediate left column
            /// Test if you've reached the left limit or not
            </span>moveLeft: <span style="color: blue;">function </span>() {
                <span style="color: blue;">this</span>._moveHorizontally(-1);
            },
            <span style="color: #006400;">/// Move the shape on the immediate right column
            /// Test if you've reached the right limit or not
            </span>moveRight: <span style="color: blue;">function </span>() {
                <span style="color: blue;">this</span>._moveHorizontally(1);
            },
            <span style="color: #006400;">/// Move the shape down on the immediate below line
            /// Test if you've reached the bottom limit or not
            </span>moveDown: <span style="color: blue;">function </span>() {
                <span style="color: blue;">if </span>(!<span style="color: blue;">this</span>._fixed) {
                    <span style="color: blue;">this</span>._currentLinePos = <span style="color: blue;">this</span>._currentLinePos + 1;
                    <span style="color: blue;">this</span>._shape1.style.msGridRow = <span style="color: blue;">this</span>._currentLinePos;
                    <span style="color: blue;">if </span>(<span style="color: blue;">this</span>._currentLinePos === <span style="color: blue;">this</span>._maxBottom) {
                        <span style="color: blue;">this</span>._fixed = <span style="color: blue;">true</span>;
                    }
                }
            }
        }
    );
    WinJS.Namespace.define(<span style="color: maroon;">"CSSTetris"</span>, { ShapeZ: ShapeZ });
} ());</pre><p>Simply read the code to understand what it’s doing. It should be commented enough to be self-explicit.</p><p>Add a reference to this script file in <em>default.html </em>and keep only this block of HTML inside the body:</p><pre class="code"><span style="color: blue;">&lt;</span><span style="color: maroon;">div </span><span style="color: red;">class</span><span style="color: blue;">="mainGrid"&gt;
    &lt;</span><span style="color: maroon;">div </span><span style="color: red;">class</span><span style="color: blue;">="virtualGrid"&gt;
    &lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: maroon;">div</span><span style="color: blue;">&gt;
</span></pre><p>Jump into <em>default.js</em>.</p><p>The cool part of having well-documented code is that we now have interesting IntelliSense details like for the <strong>constructor</strong>:</p><p><img
alt="Intellisense for ShapeZ(columnIndex) constructor" src="http://blogs.msdn.com/cfs-filesystemfile.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/0574.image_5F00_3C57958D.png" /></p><p>or the <strong>rotate</strong> function:</p><p><img
alt="Intellisense for the rotate function" src="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-10-46-metablogapi/0160.image_5F00_1BD2E68C.png" /></p><p>To properly use this code, add this block of JS just after <em>processAll</em> call:</p><pre class="code">document.addEventListener(<span style="color: maroon;">"keydown"</span>, OnKeyDown, <span style="color: blue;">false</span>);
mainGrid = document.getElementsByClassName(<span style="color: maroon;">"mainGrid"</span>)[0];
myShape = <span style="color: blue;">new </span>CSSTetris.ShapeZ(4);
myShape.insertIntoGrid(mainGrid, 12, 20);
init();</pre><p>And add these two functions:</p><pre class="code"><span style="color: blue;">function </span>init() {
    setInterval(<span style="color: blue;">function </span>() {
        myShape.moveDown();
    }, 1000);
}
<span style="color: blue;">function </span>OnKeyDown(event) {
    <span style="color: blue;">switch </span>(event.keyCode) {
        <span style="color: blue;">case </span>KEYCODE_X:
            myShape.rotate();
            <span style="color: blue;">break</span>;
        <span style="color: blue;">case </span>KEYCODE_LEFT:
            myShape.moveLeft();
            <span style="color: blue;">break</span>;
        <span style="color: blue;">case </span>KEYCODE_RIGHT:
            myShape.moveRight();
            <span style="color: blue;">break</span>;
        <span style="color: blue;">case </span>KEYCODE_DOWN:
            myShape.moveDown();
            <span style="color: blue;">break</span>;
    }
}</pre><p>And we’re done! We now have a very basic game using CSS Grid Layout coupled with CSS Transforms &amp; Animations for the graphics part and a couple of JS lines of code to have the beginning of the basics of a Tetris-like game.</p><p>Here is a short video demonstrating the final result:</p><div
class="video-js-box"><video
id="MSPointerEventsArticleVideo" class="video-js" poster="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo2.jpg" preload="preload" controls="controls" width="705" height="450"><source
type="video/mp4; codecs=&quot;avc1.42E01E, mp4a.40.2&quot;" src="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo2.mp4" /><source
type="video/webm; codecs=&quot;vp8, vorbis&quot;" src="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo2.webm" /><object
id="flash_fallback_1" class="vjs-flash-fallback" data="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf"<br /> width="705" type="application/x-shockwave-flash" height="450"><param
name="movie" value="http://releases.flowplayer.org/swf/flowplayer-3.2.1.swf" /><param
name="allowfullscreen" value="true" /><param
name="flashvars" value="config={&quot;playlist&quot;:[&quot;http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo2.jpg&quot;, {&quot;url&quot;: &quot;http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo2.mp4&quot;,&quot;autoPlay&quot;:false,&quot;autoBuffering&quot;:true}]}" /><br
/> <img
title="No video playback capabilities." alt="Poster Image" src="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo2.jpg" width="705" height="450" /><br
/> </object></video></p><p
class="vjs-no-video"><strong>Download Video:</strong> <a
href="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo2.mp4">MP4</a>, <a
href="http://david.blob.core.windows.net/videos/TheRealCSSGridStoryVideo2.webm">WebM</a>, <a
href="http://videojs.com">HTML5 Video Player</a> by VideoJS</p></div><p>You can download the final Visual Studio solution corresponding to the three steps of this tutorial here: <a
title="http://david.blob.core.windows.net/win8/TheRealCSSGridStory.zip" href="http://david.blob.core.windows.net/win8/TheRealCSSGridStory.zip">http://david.blob.core.windows.net/win8/TheRealCSSGridStory.zip</a></p><p>So, are you now convinced that CSS Grid Layout was made to simplify the creation of Tetris-like games?</p> <footer><hr
/><p>This article is part of the HTML5 tech series from the Internet Explorer team. Try-out the concepts in this article with 3 months of free BrowserStack cross-browser testing @ <a
href="http://modern.IE">http://modern.IE</a>.</p><hr
/><p>This article originally appeared on David Rousset&#8217;s MSDN blog, Coding4Fun on <a
href="http://blogs.msdn.com/b/davrous/archive/2013/02/12/coding4fun-build-a-tetris-like-game-using-css-grid-layout-amp-blend-5.aspx">12 Feb 2013</a>.</p> </footer><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/using-css-grid-layout-and-blend-5-to-build-a-game/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>What Happened when we Talked PHP with the Experts</title><link>http://www.sitepoint.com/what-happened-when-we-talked-php-with-the-experts/</link> <comments>http://www.sitepoint.com/what-happened-when-we-talked-php-with-the-experts/#comments</comments> <pubDate>Sat, 13 Apr 2013 02:50:38 +0000</pubDate> <dc:creator>Sarah Hawk</dc:creator> <category><![CDATA[Community]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[OOPHP]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[talk with the experts]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65417</guid> <description><![CDATA[Last Thursday I swapped my coffee for a wine and ran a Talk with the Experts session in the evening (down under), making it a bit more time-zone friendly for our UK audience. The subject was PHP and our expert was Lorna Mitchell. Here is what went down.]]></description> <content:encoded><![CDATA[<p></p><p>Last Thursday I broke with tradition slightly and ran a <em>Talk with the Experts</em> session in the evening (down under), making it a bit more time-zone friendly for our UK audience. It also meant that I was able to swap my usual coffee for a wine, which probably made the session run a bit more smoothly. The subject was PHP and our expert was Lorna Mitchell, tutor of <a
title="Object-oriented PHP" href="https://learnable.com/courses/object-oriented-php-2734" target="_blank">Object-oriented PHP</a> and co-author of <a
title="PHP Master: Write Cutting-edge Code" href="https://learnable.com/books/phppro1" target="_blank">PHP Master: Write Cutting-edge Code</a>.</p><p>Here is a list of useful resources that came out of the session:</p><p>What is PHP? <a
href="http://en.wikipedia.org/wiki/PHP" target="_blank">http://en.wikipedia.org/wiki/PHP</a></p><p>A great beginners course on PHP <a
href="https://learnable.com/courses/php-mysql-web-development-for-beginners-13" target="_blank">https://learnable.com/courses/php-mysql-web-development-for-beginners-13</a></p><p>Paul&#8217;s PHP client for Beanstalkd <a
href="https://github.com/pda/pheanstalk" target="_blank">https://github.com/pda/pheanstalk</a></p><p>Why use frameworks? <a
href="http://www.phpandstuff.com/articles/top-10-reasons-why-you-should-use-a-php-framework" target="_blank">http://www.phpandstuff.com/articles/top-10-reasons-why-you-should-use-a-php-framework</a></p><p>Unit testing framework <a
href="http://www.phpunit.de/" target="_blank">http://www.phpunit.de/</a></p><p>Using composition rather than inheritance <a
href="http://en.wikipedia.org/wiki/Composition_over_inheritance" target="_blank">http://en.wikipedia.org/wiki/Composition_over_inheritance</a></p><p>Static site generators:<br
/> <a
href="http://middlemanapp.com/" target="_blank">http://middlemanapp.com/</a><br
/> <a
href="http://www.phrozn.info/en/" target="_blank">http://www.phrozn.info/en/</a><br
/> <a
href="http://sculpin.io/" target="_blank">http://sculpin.io/</a></p><p>An excellent SSH client <a
href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" target="_blank">http://www.chiark.greenend.org.uk/~sgtatham/putty/</a></p><p>Find transcripts of past sessions here <a
title="Transcripts" href="http://www.sitepoint.com/forums/showthread.php?873280-Transcripts-From-Past-Sessions" target="_blank">http://www.sitepoint.com/forums/showthread.php?873280-Transcripts-From-Past-Sessions</a></p><p>Sign up for email notifications of future sessions here <a
href="https://www.facebook.com/sitepoint/app_115462065200508" target="_blank">https://www.facebook.com/sitepoint/app_115462065200508</a></p><p>And on the subject of future sessions, next up we have Talk Getting Started in the Industry with the Experts, with SitePoint devs Jude Aakjaer &amp; Ben &#8216;The Axe&#8217; Axnick. That will be taking place on Wed 1 May at 2pm PDT or you can <a
title="Timezone calculator" href="http://www.timeanddate.com/worldclock/fixedtime.html?msg=Talk+Getting+Started+in+the+Industry+with+the+Experts&amp;iso=20130502T07&amp;p1=152&amp;ah=1" target="_blank">find out what time it will be at your place here</a>.</p><p>If you missed last Thursday&#8217;s session but are keen to know what went down, you can read the entire transcript here:</p><table><tbody
id="log"><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_655d8f50849a013025c312313d00cc71">Ok, well since Lorna is here, we may as well kick off. The format here is basically a free for all &#8211; if anyone has a question then throw it out there now.</div><div
id="event_6d118800849a013025c312313d00cc71">I&#8217;ll monitor the questions and make sure that they all get answered.</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_716f9770849a013025c312313d00cc71">can we start w frameworks?</div></blockquote></td></tr><tr><td
title="SEO2013">SEO2013 <img
alt="SEO2013" src="https://assets3.talkerapp.com/avatar/f0209d11cf9b7a55343f05b2fde3e8cc.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7c60fe70849a013025c312313d00cc71">Can we start with &#8211; What is PHP? :)</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_821f3760849a013025c312313d00cc71"><p>Sure thing @mycritter &#8211; did you have a specific question relating to frameworks?</p><div
id="event_91846f40849a013025c312313d00cc71">Here you go @SEO2013 <a
href="http://en.wikipedia.org/wiki/PHP" target="_blank">http://en.wikipedia.org/wiki/PHP</a></div><div
id="event_9e2db6e0849a013025c312313d00cc71">BTW, I&#8217;ll be posting a full transcript of this session up on sitepoint.com tomorrow, along with resources</div></div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a835f030849a013025c312313d00cc71">well, what is the real world benefit of using a fw and which are really right for solid dev?</div></blockquote></td></tr><tr><td
title="SEO2013">SEO2013 <img
alt="SEO2013" src="https://assets3.talkerapp.com/avatar/f0209d11cf9b7a55343f05b2fde3e8cc.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_b1564550849a013025c312313d00cc71">Thanks for the link. How long on average does it take to learn PHP?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ba88bcf0849a013025c312313d00cc71">@mycritter that&#8217;s a great starting question!</div></blockquote></td></tr><tr><td
title="Jerry">Jerry <img
alt="Jerry" src="https://assets1.talkerapp.com/avatar/de9b6e9323dc8667cae804acb537e5f9.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_c4770e70849a013025c312313d00cc71">@SEO what prog languages are you familiar with now?</div></blockquote></td></tr><tr><td
title="SEO2013">SEO2013 <img
alt="SEO2013" src="https://assets3.talkerapp.com/avatar/f0209d11cf9b7a55343f05b2fde3e8cc.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_d7166670849a013025c312313d00cc71">None unfortunately which I&#8217;m sure isn&#8217;t the answer you wanted :/ I&#8217;d really like to learn though.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_dd602930849a013025c312313d00cc71">Frameworks give you structure, and they also give you a quick start on the things that are the same in every project, they usually have routing, logging, templating &#8230; that sort of thing. So they save some of the repetitive work for you</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_e4687aa0849a013025c312313d00cc71">I&#8217;d also like to plug Lorna&#8217;s latest contribution to the Learnable/SitePoint network, which is her course on Object-oriented PHP <a
href="https://learnable.com/courses/object-oriented-php-2734" target="_blank">https://learnable.com/courses/object-oriented-php-2734</a></div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_e989ede0849a013025c312313d00cc71">@seo2013 you just gotta get the book</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_f6be6990849a013025c312313d00cc71">Frameworks also give a common way to do things, so they make it easier to bring in a new developer to the team and that that person pick up the project much more quickly</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_013d5450849b013025c312313d00cc71">@SEO2013 This is a great beginners course <a
href="https://learnable.com/courses/php-mysql-web-development-for-beginners-13" target="_blank">https://learnable.com/courses/php-mysql-web-development-for-beginners-13</a></div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_12485b50849b013025c312313d00cc71">@mycritter I&#8217;d say that the benefit is mostly to developers and to speed and quality of development &#8211; much more than how much difference it makes to the end product. Frameworks are about getting things done.</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_1d96fc30849b013025c312313d00cc71">@lornaJane, do you use an out of the box framework or a platform like a cms for your web dev?</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_3d822470849b013025c312313d00cc71">Welcome to anyone that has just joined us. We&#8217;re LornaJane is our expert today and we&#8217;re currently talking the benefits of using frameworks.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_3dc95f00849b013025c312313d00cc71">As for which frameworks are solid &#8211; they all have their strengths. For example ZF2 and Symfony2 are totally comprehensive, but they can be pretty heavy if you&#8217;re only building something simple. There are lightweight frameworks, where you will need to do some of the work yourself such as Silex or Slim. And then there are frameworks that are more aimed at friendliness than performance &#8211; that might be something like CakePHP</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_533c1250849b013025c312313d00cc71">@mycritter I&#8217;m a consultant so I work with whatever my client has. My personal projects have been a mix, some ZF, some Slim, depending what I was building. Hope that helps give you some ideas!</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_57569ba0849b013025c312313d00cc71">Quick question about frameworks?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_6b81cd20849b013025c312313d00cc71">@TheCliff go for it</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_6e2d31c0849b013025c312313d00cc71">I am curious does heavy frameworks put more load on my server?</div><div
id="event_728bdc50849b013025c312313d00cc71">for rendering and things?</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7f00a390849b013025c312313d00cc71">speed of the code being rendered and so on.</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_941fe960849b013025c312313d00cc71">Lorna, do you have to spend a lot of time with each project learning its environment before being productive, or is there a small enough pool of common frameworks that you generally have it covered?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_9506c730849b013025c312313d00cc71">@TheCliff yes, it certainly can do. The frameworks can do lots of work in the background to make for easy, rapid development. For a very performant application, a full-stack framework probably isn&#8217;t the right tool. For 95% of sites, it&#8217;s absolutely fine</div></blockquote></td></tr><tr><td
title="ridinQwerty">ridinQwe&#8230; <img
alt="ridinQwerty" src="https://assets0.talkerapp.com/avatar/456724630296485f2e168660bebc7a4a.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a14a7f70849b013025c312313d00cc71">Php &amp; Mysql &#8220;Novice to Ninja&#8221; is a pretty good starting point @SEO2013</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_aae7b950849b013025c312313d00cc71">Awesome answer thanks!</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_b4c11920849b013025c312313d00cc71">@TheCliff: generally the extra load is negligible, and if you have enough traffic for it to be a problem, you can afford to scale the site across multiple servers. The benefit of writing less/easier code faster with a framework outweigh the execution (in)efficiency.</div></blockquote></td></tr><tr><td
title="Jerry">Jerry <img
alt="Jerry" src="https://assets1.talkerapp.com/avatar/de9b6e9323dc8667cae804acb537e5f9.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_b8dfae00849b013025c312313d00cc71">Impressions of Twitter Bootstrap compared to other frameworks? That&#8217;s the only one I&#8217;ve used, mainly because it was the first I found and was pretty easy to pick up</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_c486e2e0849b013025c312313d00cc71">@MikeH Many of the frameworks have good documentation and lots of shared ideas. For example many of them are MVC, they have routing, the templating tools are alike even if not exactly the same &#8230; and I&#8217;m very good at debugging after lots of practice! So I usually dive in and learn that way.</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_c77fa120849b013025c312313d00cc71">I should introduce Paul.Annesley. Paul is a senior dev with the SitePoint group.</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_e5d3bb10849b013025c312313d00cc71">An important aspect of using a framework is the security is can provide; default escaping of variables in HTML output, sanitizing user input, handling common gotchas, quoting/escaping database queries to mitigate SQL injection etc.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_e8eb6210849b013025c312313d00cc71">@theCliff: That&#8217;s a good point from @Paul.Annesley &#8211; mostly, the developer&#8217;s time will be MUCH more expensive than your hosting costs. So it&#8217;s a net win to use the framework and get your product shipped</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_fe93dc20849b013025c312313d00cc71">The flipside of that, is that you inherit any security vulnerabilities present in the framework you use, which happens in all frameworks from time to time.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_0abc6000849c013025c312313d00cc71">@Jerry The twitter bootstrap is more of a frontend framework, this discussion is more about the server-side frameworks which are written in PHP. The learning curve is different for the various frameworks, but as I said, many of them have excellent docs</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_1aa26530849c013025c312313d00cc71">Paul—as a senior dev do you become more specialized or broader in the languages you use server side?</div></blockquote></td></tr><tr><td
title="BrandonKasteler">BrandonK&#8230; <img
alt="BrandonKasteler" src="https://assets3.talkerapp.com/avatar/a324ad8ad0a220c609e26222af09504d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_252a3e40849c013025c312313d00cc71">@Paul.Annesley On that note, for someone who is relatively new to PHP, would you say the benefits of having pre-built security outweigh those of potentially missing certain aspects in our own code?</div></blockquote></td></tr><tr><td
title="Jerry">Jerry <img
alt="Jerry" src="https://assets1.talkerapp.com/avatar/de9b6e9323dc8667cae804acb537e5f9.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_348736d0849c013025c312313d00cc71">Do you know of any good comparisons of pros/cons for various frameworks?</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_3eb17a30849c013025c312313d00cc71">@lornaJane, on basics, do you have good recommendations for securing our code for beginners. ways to stay ahead of hackers.</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_45c613c0849c013025c312313d00cc71">@MikeH: Both :) I learned a lot about PHP language and tools. I did so by taking on side projects like creating the PHP client for beanstalkd:<a
href="https://github.com/pda/pheanstalk" target="_blank">https://github.com/pda/pheanstalk</a> … I also learn other languages when I have time, and mainly write Ruby these days.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_5cf10490849c013025c312313d00cc71">@mycritter: The built in functionality of frameworks can really help with security, as they will include database escaping and filtering input values and things</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_6a94bc20849c013025c312313d00cc71">@BrandonKasteler: I certainly pick the benefits of a framework over trying to do it all myself… the latter results in attempting to build your own framework, and you end up with no time to build what you&#8217;re setting out to build.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_6d38f610849c013025c312313d00cc71">@mycritter: my top tip though is to use the Filter extension in PHP for the incoming variables. Make that a requirement and it will reward you :)</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7cd87480849c013025c312313d00cc71">Would you recommend PHP coders to get into Frameworks &#8212; MVC style of programming? I have been coding in PHP for 5 years now. Part of the reason I haven&#8217;t gone into Frameworks is because over the past couple of years I&#8217;ve put together a great &#8220;functions&#8221; file that has tons of stuff for me to use during coding to speed things up. I would need to find out if a framework has what my functions do in order for me to consider using it. I am really not sure what a framework really does to speed up writing code. For the most part I just need basic Mysql_query&#8217;s, while loops, and basic math. Would a framework really help that much trying to speed up basic php commands?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_87f10f60849c013025c312313d00cc71">@Jerry: framework comparisons are pretty difficult, they are all aimed at doing different jobs so it&#8217;s comparing apples to oranges in many cases. I don&#8217;t know of any good benchmarks</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_aba64d30849c013025c312313d00cc71">@TheCliff: I&#8217;d say that for a really basic site, it probably doesn&#8217;t matter. Once you start building things that are a bit more dynamic, they will really make your life easier &#8211; particularly once you get past the learning curve</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ec564ea0849c013025c312313d00cc71">To anyone that has just joined, welcome. We&#8217;re currently talking frameworks, but if you have a question on any aspect of PHP (or OOP PHP) please throw it out there at any stage</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_edddd740849c013025c312313d00cc71">I have a general point I&#8217;d like to add: PHP started as pretty much a way of embedding bits of code into HTML; making it a templating language. And using it like that is not a bad way to start learning it. But to build a serious website, one needs to learn to separate the templates from the logic of the website. Frameworks make that much easier to do (they provide models, controllers etc, which are pure PHP and don&#8217;t contain HTML).</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_101fde90849d013025c312313d00cc71">Can you give me a quick example of one way that frameworks save time? Like a type of command or something that it would help with.</div></blockquote></td></tr><tr><td
title="BrandonKasteler">BrandonK&#8230; <img
alt="BrandonKasteler" src="https://assets3.talkerapp.com/avatar/a324ad8ad0a220c609e26222af09504d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_112effd0849d013025c312313d00cc71">@LornaJane Bookmarked the various frameworks you&#8217;ve mentioned to look at later. Thank you kindly for that information.</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_217bde00849d013025c312313d00cc71">or a site that would show me why using frameworks save time and how.</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_266ed5b0849d013025c312313d00cc71">Lorna—do you work mostly with larger custom apps, or still on (WordPress|Concrete|Magento|LemonStand|Joomla) based sites?</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_379c73f0849d013025c312313d00cc71">@TheCliff <a
href="http://www.phpandstuff.com/articles/top-10-reasons-why-you-should-use-a-php-framework" target="_blank">http://www.phpandstuff.com/articles/top-10-reasons-why-you-should-use-a-php-framework</a></div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_4768b890849d013025c312313d00cc71">@TheCliff the simplest example is things like building forms, you define a form and the framework does client side validation, server side validation, handles the failures, displays the form itself, and gives you back valid data when it&#8217;s done. Saves a lot of repeat code for every form on every project &#8211; and you never forget to validate one field</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_4fc9f7e0849d013025c312313d00cc71">@lornaJane, most of my clients want a cms. there are great options out there. recommendations on going w them vs building proprietary?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_542ed170849d013025c312313d00cc71">@Cliff: also things like there are database libraries already setup, and logging libraries</div><div
id="event_5a8c76e0849d013025c312313d00cc71">@BrandonKasteler that&#8217;s my pleasure, good luck with those</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_6091bc20849d013025c312313d00cc71">@lornaJane that could be very useful. I&#8217;m looking at that page now @hAWK</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_69900580849d013025c312313d00cc71">@mikeH, just saw your q. great minds think alike ;-)</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_79763d00849d013025c312313d00cc71">@MikeH: I work almost entirely on custom apps, built with frameworks. I&#8217;ve got wordpress as my blog, but that&#8217;s all (and I didn&#8217;t build it myself!). I&#8217;m API specialist so I work more with integrating systems, and they are usually framework-built bespoke apps, just because that&#8217;s the best tool for these particular jobs</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7cf6faf0849d013025c312313d00cc71">Hi Lorna: When writing a class is it always important to follow a design pattern. A lot of my classes seem to follow no design pattern at all. Is this a bad thing?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_99108370849d013025c312313d00cc71">@mycritter: going with an existing open source CMS and customising it means that you get all the work done in the existing one for free, your client only needs to pay for the extra bits that are specific to their system, and you only have to do interesting and unusual bits of development, rather than repeating yourself all the time</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_9a1e24f0849d013025c312313d00cc71">@oatley, ooh, now we&#8217;re getting into the fun stuff ;-)</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a8859a80849d013025c312313d00cc71">stuff like Drupal has loads of extensions and will offer you security updates all the time &#8211; and your own code won&#8217;t do that with zero work from you :)</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a940c1f0849d013025c312313d00cc71">Specialization begets productivity IMO. Having to swap often between frameworks, libraries or CMS brings a lot of overhead, and requires a lot more research time</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_c9c65d90849d013025c312313d00cc71">@Oatley: not a bad thing at all. Too many design patterns is a bad thing. Not following patterns isn&#8217;t a problem. In fact, if you read a design patterns textbook, you&#8217;d probably find many more familiar patterns than you expect. The bottom line is that we&#8217;re developers and that means we solve problems. Whether those solutions have complicated-sounding names or not doesn&#8217;t matter IMO</div></blockquote></td></tr><tr><td
title="ridinQwerty">ridinQwe&#8230; <img
alt="ridinQwerty" src="https://assets0.talkerapp.com/avatar/456724630296485f2e168660bebc7a4a.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ce8e6c20849d013025c312313d00cc71">I&#8217;m still really new to PHP, and haven&#8217;t touched a framework yet, but wouldn&#8217;t it pretty much be like a comparison to jquery and javascript? The dirty work simplified down into managed solutions?</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_e483efd0849d013025c312313d00cc71">@ridinQwerty broadly speaking &#8212; yes</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ee6d8700849d013025c312313d00cc71">@MikeH That&#8217;s not my experience, I find it helpful both in terms of getting things done and in terms of code quality to build on the existing libraries available in the open source world. Switching between them is hard work, but worth it, at least for me</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_02dfe610849e013025c312313d00cc71">Thanks for that page @hAWK</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_03c9cc60849e013025c312313d00cc71">@RidinQwerty that&#8217;s a nice analogy, yes :) Some frameworks are little more than a few libraries &#8211; and you might add a few more to make something you&#8217;re comfortable with. But they&#8217;re just there to wrap things up and make them quicker to use</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_047e3040849e013025c312313d00cc71">@ridinQwerty: main difference; jQuery is a library that you call from your code. A framework generally defines where you should put code so that the framework can call it when appropriate.</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_08b148c0849e013025c312313d00cc71">@TheCliff np</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_13210f80849e013025c312313d00cc71">@LornaJane I agree on building on their foundations. I just find it hard to keep up with multiple systems.</div></blockquote></td></tr><tr><td
title="ccovey">ccovey <img
alt="ccovey" src="https://assets0.talkerapp.com/avatar/c19bcbebb8c249af97576400977a3c8f.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_26c9ffd0849e013025c312313d00cc71">For those of us without code reviews, etc. any ways of knowing when our OOP code is no longer procedural code in class? I feel like mine is haha.</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_38bbb920849e013025c312313d00cc71">@lornaJane so for beginners what framework would you recommend getting started with? I&#8217;ve had tons of people tell me that Yii is the best one as of late. What are your thoughts as far as learning curves, ease of use, etc. are concerned?</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_4b338dd0849e013025c312313d00cc71">@ccovey &lt;?php class Ccovey { public function__construct() { $this-&gt;isProduceduralInAClass = false; } } ?&gt;</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_4ddd9240849e013025c312313d00cc71">@ccovey: Method length is usually a clue. If your methods are really long then you&#8217;re probably still working in quite a procedural style. Some methods will always end up long though &#8211; such as a controller action for a complicated page</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_4dfe7840849e013025c312313d00cc71">Apart from your own excellent sitepoint book (which I found out about at you at one of your excellent training courses i attended at Leeds NTI!) what other OOP books would you recommend?</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_4f07f020849e013025c312313d00cc71">@ccovey &#8230;problem solved</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_508b0190849e013025c312313d00cc71">ccovey: one way is to try writing unit tests for your code… if you manage, it&#8217;s probably decent enough OO. If it&#8217;s really painful, maybe it needs refactoring to be more OO :)</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_6d367a50849e013025c312313d00cc71">@TheCliff: I haven&#8217;t used Yii but I&#8217;ve had people who do both front end and back end enjoy it. I usually recommend that people get comfortable with OOP, then try out something like CakePHP &#8211; it&#8217;s not too complicated a framework but is built by smart people and has a fabulous community behind it.</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7b1070e0849e013025c312313d00cc71">@Paul.Annesley speaking of, what is the Unit Testing framework de jour?</div></blockquote></td></tr><tr><td
title="ccovey">ccovey <img
alt="ccovey" src="https://assets0.talkerapp.com/avatar/c19bcbebb8c249af97576400977a3c8f.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7b92c1a0849e013025c312313d00cc71">I have been trying to keep methods under 20ish lines if possible and have started testing on my recent side project</div></blockquote></td></tr><tr><td
title="TheCliff">TheCliff <img
alt="TheCliff" src="https://assets1.talkerapp.com/avatar/d195d33df101578798877d1f8db635d3.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_82f92c60849e013025c312313d00cc71">awesome. I&#8217;ll look into that!</div></blockquote></td></tr><tr><td
title="ccovey">ccovey <img
alt="ccovey" src="https://assets0.talkerapp.com/avatar/c19bcbebb8c249af97576400977a3c8f.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a05219a0849e013025c312313d00cc71">MikeH if only I would&#8217;ve known that years ago :)</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a3d82450849e013025c312313d00cc71">@Oatley: PHP Master is the only resource you&#8217;ll ever need!! Seriously though, there aren&#8217;t a lot of OOP books out there. Once you&#8217;re at the level where PHP Master is making sense, you&#8217;re better reading the blog articles so make sure you&#8217;re subscribed to phpdeveloper.org and the Sitepoint sites including phpmaster.com &#8211; that&#8217;s where much of the advanced content goes, and it&#8217;s properly up to date. Many of the books are pre-PHP 5.3 right now, although I&#8217;m seeing updates coming out</div></blockquote></td></tr><tr><td
title="ridinQwerty">ridinQwe&#8230; <img
alt="ridinQwerty" src="https://assets0.talkerapp.com/avatar/456724630296485f2e168660bebc7a4a.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_af860070849e013025c312313d00cc71">@Paul.Annesley I probably have awhile before I will be able to ingest what you just said. I&#8217;m still goofing around with filling tables with data I create and ect&#8230; Not too far along at all in other words. I&#8217;ve just gotten comfortable with the front end of things, so it&#8217;s time to progress. I&#8217;ve got the first two books you guys offer on it though, and am enjoying them. The one on OOP with be the next.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_afd8f8e0849e013025c312313d00cc71">@ccovey: that sounds to me like you are on the right tracks already, great work</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_c74c3f90849e013025c312313d00cc71">I assume you guys know about Lorna&#8217;s OOP course&#8230;<a
href="https://learnable.com/courses/object-oriented-php-2734" target="_blank">https://learnable.com/courses/object-oriented-php-2734</a></div></blockquote></td></tr><tr><td
title="ridinQwerty">ridinQwe&#8230; <img
alt="ridinQwerty" src="https://assets0.talkerapp.com/avatar/456724630296485f2e168660bebc7a4a.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_e492d360849e013025c312313d00cc71">Sure do</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_e5530020849e013025c312313d00cc71">@MikeH: sorry for the delay… I believe PHPUnit is where it&#8217;s at. <a
href="http://www.phpunit.de/" target="_blank">http://www.phpunit.de/</a></div><div
id="event_f0c31070849e013025c312313d00cc71">I&#8217;ve mostly used SimpleTest in the past, but I don&#8217;t recommend it, and don&#8217;t let the name fool you… it&#8217;s not simpler :)</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_0546eca0849f013025c312313d00cc71">Good. I started to dabble with that one a few years ago.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_054f2470849f013025c312313d00cc71">And what @HAWK said &#8211; if you&#8217;re looking for an intro to OOP, I have the Learnable course up now, mix of me talking (and drawing pictures!) and showing code, which I hope will help. For those who learn better from reading, the PHP Master book has an OOP chapter but also chapters on Design Patterns and on Databases, using PDO which is also object oriented</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_0a73ead0849f013025c312313d00cc71">I definitely recommend learning to write unit tests if you want to do object oriented proramming.</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_12f51d90849f013025c312313d00cc71">@lornaJane, are we talking applying OOP to PHP, or implementing new powerful PHP versions?</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_192c3800849f013025c312313d00cc71">Hi Lorna. Thanks for all your help by the way. Another one for you When I&#8217;m writing classes I can never seem to extend them. In examples I constantly see things like cat extends animal, which makes sense. But in the real world I&#8217;m never going to be building a &#8216;cat&#8217;! Say I&#8217;m building something like a website, what would be a good example of using extends here?</div></blockquote></td></tr><tr><td
title="ridinQwerty">ridinQwe&#8230; <img
alt="ridinQwerty" src="https://assets0.talkerapp.com/avatar/456724630296485f2e168660bebc7a4a.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_20f37aa0849f013025c312313d00cc71">I had to switch my email address to join because it said someone was using it, on a unrelated but related note. ?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_228d2a60849f013025c312313d00cc71">@mycritter I can take any questions you have</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_3375a420849f013025c312313d00cc71">@ridinQwerty same with me. Remembered my email from a chat months and months ago and wouldn&#8217;t let me in</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_4069d450849f013025c312313d00cc71">Same. Fake email addresses all round :)</div></blockquote></td></tr><tr><td
title="ridinQwerty">ridinQwe&#8230; <img
alt="ridinQwerty" src="https://assets0.talkerapp.com/avatar/456724630296485f2e168660bebc7a4a.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_44ed69d0849f013025c312313d00cc71">Lol</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_53b01fe0849f013025c312313d00cc71">@ridinQwerty and @MikeH Yeah, that is a very frustrating bug with this s/w &#8211; I don&#8217;t even know why it stores the emails, I can&#8217;t aces them. The good news is that we have our own interface well on the way to completion and with any luck I&#8217;ll be using that for the next session.</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_5479d6b0849f013025c312313d00cc71">Related fact: did you know example.com and example.org etc are reserved for testing, so you know nobody will get email sent to them?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_57a33d70849f013025c312313d00cc71">@Oatley For example you might make a base model, and your other models extend from that &#8211; same for controllers. Quite often I do this the other way around. When you copy and paste something into another class, then instead you should create a common parent, rather than looking to create a child</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_588132c0849f013025c312313d00cc71">guess we should all log out before closing the browser</div></blockquote></td></tr><tr><td
title="Jerry">Jerry <img
alt="Jerry" src="https://assets1.talkerapp.com/avatar/de9b6e9323dc8667cae804acb537e5f9.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_623e82b0849f013025c312313d00cc71">I had to try 3 fake email addresses before I found one it would accept. :)</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_8a0abe00849f013025c312313d00cc71">PHP Pros &#8212; do you do any front end dev work (excluding personal projects)? Or put another way do you get to focus on the server side?</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_8c912c20849f013025c312313d00cc71">Yeah, sorry about that. Annoyingly, they don&#8217;t answer support tickets either so there isn&#8217;t much I can do except bin the product.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_8ee465f0849f013025c312313d00cc71">@Oatley also if you&#8217;re using a framework, have a look around in it&#8217;s source code &#8211; you&#8217;ll see some very good &#8220;real&#8221; examples there of when classes are extended &#8211; and sometimes you&#8217;ll want to extend their classes yourself to add things</div></blockquote></td></tr><tr><td
title="Jerry">Jerry <img
alt="Jerry" src="https://assets1.talkerapp.com/avatar/de9b6e9323dc8667cae804acb537e5f9.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a6e4a490849f013025c312313d00cc71">np @Hawk</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_aef28200849f013025c312313d00cc71">@MikeH I do not do any frontend dev work. To put it politely, it&#8217;s not where my talents lie :) It isn&#8217;t a problem because I do APIs rather than websites a lot of the time</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ce462880849f013025c312313d00cc71">Lorna, I&#8217;m a ZCE 5.3. Do you know of when/if the exam will involve the very latest version of ph</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ce4c2640849f013025c312313d00cc71">@MikeH: I&#8217;m no pro in frontend stuff, but I like to do some occasionally to keep up to date. I think when you&#8217;re working server-side, it&#8217;s important to understand how the data you&#8217;re pushing to the frontend layer is going to be worked with and displayed.</div></blockquote></td></tr><tr><td
title="mycritter">mycritte&#8230; <img
alt="mycritter" src="https://assets2.talkerapp.com/avatar/7ff1b5523a2e105b3d781cc5380899e5.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_d93a9f00849f013025c312313d00cc71">@lornaJane, when you say &#8220;do APIs&#8221;, do you mean build or integrate them?</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ec7d8770849f013025c312313d00cc71">Indeed.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ec86e1c0849f013025c312313d00cc71">@oatley: I can&#8217;t see the ZCE exams updating any time soon. It&#8217;s a huge investment for Zend to make that happen and I&#8217;m confident they aren&#8217;t working on that at the moment</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_0826645084a0013025c312313d00cc71">Github? Is it as ubiquitous as the all the kids say?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_0d6005e084a0013025c312313d00cc71">@mycritter: either/both. I build lots of APIs, but also go in and make systems talk to one another with whatever functionality they have available. I spend more with data and servers than with browsers, by a long way</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_2d863d5084a0013025c312313d00cc71">@MikeH I think source control is ubiquitous. Many companies use alternative hosting as GitHub is expensive for private repositories, but the idea of having remotely hosted collaborative source control is standard, in my experience</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_50643d2084a0013025c312313d00cc71">Welcome to those of you that have just come in. We&#8217;ve mostly talked frameworks so far and are now touching on source control.</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_5ecd988084a0013025c312313d00cc71">Thanks Lorna, with extends can you extend anything? For example I see this &#8220;has a&#8221; vs &#8220;is a&#8221; debate, so for example would it make sense for something like a class FormBuilder to extend the class validation? (keeping things separate?) thanks.</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a40256f084a0013025c312313d00cc71">Oatley: keep in mind inheritance isn&#8217;t the only way to bring functionality into a class. Check out <a
href="http://en.wikipedia.org/wiki/Composition_over_inheritance" target="_blank">http://en.wikipedia.org/wiki/Composition_over_inheritance</a>… you can just write small methods on your class which call out to other classes dedicated to that particular job.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_b2ef2db084a0013025c312313d00cc71">@Oatley the &#8220;is a&#8221; and &#8220;has a&#8221; debate is useful in terms of naming things and thinking about how they go together. If you try to extend one thing into another incorrectly, I usually find that you&#8217;ll realise that this makes no sense pretty quickly :) My advice is to try out your ideas on a small scale, and see if you think it works for your application</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_cc4a751084a0013025c312313d00cc71">contrived example which might help illustrate composition, as opposed to inheritance:</div><div
id="event_cdf0820084a0013025c312313d00cc71"><pre id="past_pre_cc52b98758de1c24d118">class Form {
  public function validate($field) {
    $validator = new Validator();
    return $validator-&gt;validate($field);
  }
}</pre></div><div
id="event_da6375f084a0013025c312313d00cc71">so Form is &#8220;composed of&#8221; Validator… it uses it, but doesn&#8217;t have to deal with the complexity of inheriting from it.</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_0820256084a1013025c312313d00cc71">Thanks Paul &amp; Lorna :-)</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_15598db084a1013025c312313d00cc71">it could also have a translate() method which calls out to a Translator class… much harder to extend/inherit from two different base classes :)</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_3a25f57084a1013025c312313d00cc71">One thing ive always wondered In a class before you write any methods at the very top you declare your properties (ie public, private, protected) a lot of the time when I have forgotten to do this my script class is fine so why do they need to be declared?</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_64eb122084a1013025c312313d00cc71">@Oatley they don&#8217;t need to be &#8211; if you just start using properties, they work fine. BUT by declaring them, you can document them, and also if you don&#8217;t want the properties to be public (which often they shouldn&#8217;t be) then you will need to declare them and their visibility</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_6e8585e084a1013025c312313d00cc71">@Oatley it&#8217;s good practice to declare them, but PHP will roll with it if you don&#8217;t, it&#8217;s very tolerant</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7471d53084a1013025c312313d00cc71">@LornaJane: does failing to declare them raise warnings at certain error_reporting levels in modern PHP?</div></blockquote></td></tr><tr><td
title="ccovey">ccovey <img
alt="ccovey" src="https://assets0.talkerapp.com/avatar/c19bcbebb8c249af97576400977a3c8f.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7f3e9c2084a1013025c312313d00cc71">Depends on usage</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_8980acc084a1013025c312313d00cc71">PHP borrows heavily from Java for its class/object model, and Java being a statically compiled language depends on those properties being declared up front.</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_8c9bc16084a1013025c312313d00cc71">@hawk. Will a article of all the questions and answers today asked be somewhere on would be very useful. Thanks</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_9b72444084a1013025c312313d00cc71">I seem to remember having problem with __set() and __get() magic methods when not declaring properties. Details hazy.</div></blockquote></td></tr><tr><td
title="ccovey">ccovey <img
alt="ccovey" src="https://assets0.talkerapp.com/avatar/c19bcbebb8c249af97576400977a3c8f.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a03c4de084a1013025c312313d00cc71">$this-&gt;foo += &#8216;bar&#8217;; will throw a warning if not declared. But that is a bit of a different issue</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_af813c1084a1013025c312313d00cc71">@Paul.Annesley no warnings from PHP, it&#8217;s a backward compatibility thing. PHP 4 had no visibility, so public was the default then, and that&#8217;s still the case now. You can just use properties and PHP will assume that you meant to do that</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_e5c36f9084a1013025c312313d00cc71">@oatley Yup. I&#8217;ll post a transcript of the session on sitepoint.com tomorrow :)</div></blockquote></td></tr><tr><td
title="Oatley">Oatley <img
alt="Oatley" src="https://assets1.talkerapp.com/avatar/c6bbeefa683ccd0159f32886a7715dcd.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_f819100084a1013025c312313d00cc71">I&#8217;m trying and write a mini framework that creates drivers or for any PDO queries, or read any XML files passed into my system. Is this a good idea, or is it overkill?</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_0140bd5084a2013025c312313d00cc71">Maybe problems with serialize() or json_encode() if you don&#8217;t declare them? I&#8217;m clutching at straws :) But they should definitely be declared.</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_033fe9e084a2013025c312313d00cc71">@oatley And all transcripts of these sessions can be found here <a
href="http://www.sitepoint.com/forums/showthread.php?873280-Transcripts-From-Past-Sessions" target="_blank">http://www.sitepoint.com/forums/showthread.php?873280-Transcripts-From-Past-Sessions</a></div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_5b08291084a2013025c312313d00cc71">@Oatley it sounds like a good project to me. You might try to make them as standalone classes &#8211; then you can add them to any other project, even if you&#8217;re using a framework, by including your classes in the autoloader</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_65cd6ae084a2013025c312313d00cc71">Here&#8217;s an interesting thing to consider: if you have a site that doesn&#8217;t need a database etc, but you want the benefits of using PHP to create it (e.g. shared header/footer/layout/components etc), consider a static site generator. Write your site in PHP, generate it to HTML files, and deploy them to a static website host or Amazon S3. Never get hacked ;) In Ruby-land, I&#8217;d recommend <a
href="http://middlemanapp.com/" target="_blank">http://middlemanapp.com/</a> for that. Googling around for PHP examples, I see <a
href="http://www.phrozn.info/en/" target="_blank">http://www.phrozn.info/en/</a> and <a
href="http://sculpin.io/" target="_blank">http://sculpin.io/</a> and various others, but haven&#8217;t tried them.</div><div
id="event_a2341d6084a2013025c312313d00cc71">@MikeH: going back a bit… I&#8217;m a massive fan of git and GitHub. git is not trivial to learn, but I consider it well worth it… definitely one of my most valued development tools. I `git init` and commit to any old directory I write code/docs in, even if it&#8217;s just a one-day-one-developer project.</div><div
id="event_c8dd4af084a2013025c312313d00cc71">And git doesn&#8217;t lock you into GitHub… there&#8217;s other hosts, or you can host your own, or if you&#8217;re a solo developer you can just not push your code to a remote server. Git can run entirely locally, doesn&#8217;t need a server.</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_d2e03a1084a2013025c312313d00cc71"></div><div
id="event_efa4282084a2013025c312313d00cc71">I&#8217;m going to jump in and say that we have 5 minutes left of the session (at which point you are welcome to chat amongst yourselves but I&#8217;ll cut Lorna free) so if anyone has a question that they haven&#8217;t asked, now would be the time</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_f554dac084a2013025c312313d00cc71">@Paul.Annesley I&#8217;m pretty ignorant with VC, except that I do understand it&#8217;s benefits. Is Git (without the hub) still good for getting code onto different machines? Do you need to setup a host?</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_02f4c57084a3013025c312313d00cc71">Never mind, you answered that</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_05f045a084a3013025c312313d00cc71">@MikeH: git works great over SSH, so you can push/pull easily between any hosts you can SSH between.</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_23f078c084a3013025c312313d00cc71">It might not be something I should admit publicly, but I use Windows and would have to learn SSH too</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_45b9fad084a3013025c312313d00cc71">:) PuTTY is an excellent SSH client: <a
href="http://www.chiark.greenend.org.uk/~sgtatham/putty/" target="_blank">http://www.chiark.greenend.org.uk/~sgtatham/putty/</a> … it&#8217;s been years since I&#8217;ve used it though, and I&#8217;ve never used git on windows.</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_46c88ca084a3013025c312313d00cc71">@MikeH You are in good company there, plenty of windows users around</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_4961665084a3013025c312313d00cc71">There&#8217;s a Windows GitHub client though.</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_68415d5084a3013025c312313d00cc71">Thanks.<br
/> What about code documenting? I used to use PhpDocumenter, but I couldn&#8217;t get the latest version to work</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_6b7046f084a3013025c312313d00cc71">If you have the time and interest, I&#8217;d recommend running a linux (Ubuntu?) virtual machine on your windows machine, so you can play with and learn tools like git/php/etc in the environment they were built for.</div></blockquote></td></tr><tr><td
title="ccovey">ccovey <img
alt="ccovey" src="https://assets0.talkerapp.com/avatar/c19bcbebb8c249af97576400977a3c8f.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_7779da6084a3013025c312313d00cc71">I use gitbash on windows wish comes with ssh already installed for you so then you just need to generate keys ect.</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_78418b1084a3013025c312313d00cc71">I&#8217;m usually running an Ubuntu Server virtual machine on my Mac, which I SSH into.</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_82e518d084a3013025c312313d00cc71">And&#8230; that&#8217;s a wrap. Thanks very much to everyone that participated. I&#8217;ll post a transcript up on SitePoint tomorrow. Don&#8217;t forget to check out Lorna&#8217;s course <a
href="https://learnable.com/courses/object-oriented-php-2734" target="_blank">https://learnable.com/courses/object-oriented-php-2734</a> and lastly&#8230; a huge thanks to Lorna for her time, and to Paul for stepping in at the last minute to help out. Much appreciated.</div><div
id="event_84acd49084a3013025c312313d00cc71">You&#8217;re all free to stick around here for as long as you like, but the session will no longer be moderated. :)</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_901d8d9084a3013025c312313d00cc71">@MikeH definitely phpDocumentor, I&#8217;m sure their IRC channel or mailing list would help you with setup problems</div></blockquote></td></tr><tr><td
title="Jerry">Jerry <img
alt="Jerry" src="https://assets1.talkerapp.com/avatar/de9b6e9323dc8667cae804acb537e5f9.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_9403f3d084a3013025c312313d00cc71">Thanks Lorna, Paul, Hawk</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_9902f7f084a3013025c312313d00cc71">If you&#8217;d like to sign up for email notifications of future sessions, you can do so here <a
href="https://www.facebook.com/sitepoint/app_115462065200508" target="_blank">https://www.facebook.com/sitepoint/app_115462065200508</a></div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_9970b83084a3013025c312313d00cc71">I&#8217;m a generalist, so my to-learn list is as long as my arm. Might not extend to Linux.Thanks @LornaJane, @HAWK</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_9d81ba8084a3013025c312313d00cc71">No worries @Jerry</div></blockquote></td></tr><tr><td
title="LornaJane">LornaJan&#8230; <img
alt="LornaJane" src="https://assets0.talkerapp.com/avatar/aaa499647571a040329ad88814e5e63d.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a02e29b084a3013025c312313d00cc71">Thanks for having me everyone, some good questions today</div></blockquote></td></tr><tr><td
title="HAWK">HAWK <img
alt="HAWK" src="https://assets0.talkerapp.com/avatar/22176bf7a749020fa6ceb1bd0f3eb8a1.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a10d6ca084a3013025c312313d00cc71">See ya everyone</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_a52e98d084a3013025c312313d00cc71">Cool, thanks everybody for the questions and interest.</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_d5eabaa084a3013025c312313d00cc71">Maybe my inability to spell &#8216;documentor&#8217; was the problem? Thanks</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_dcc8101084a3013025c312313d00cc71">I&#8217;m <a
href="http://twitter.com/pda" target="_blank">http://twitter.com/pda</a> on Twitter, although you&#8217;ll see more about Ruby etc than PHP there ;)</div></blockquote></td></tr><tr><td
title="Jerry">Jerry <img
alt="Jerry" src="https://assets1.talkerapp.com/avatar/de9b6e9323dc8667cae804acb537e5f9.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_ef1e9f2084a3013025c312313d00cc71">GitBash on Windows is handy just for the Unix tools that come with it (grep, etc.)</div></blockquote></td></tr><tr><td
title="MikeH">MikeH <img
alt="MikeH" src="https://assets2.talkerapp.com/avatar/be151fa409735403535c3e880d3daa3b.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_150d2b7084a4013025c312313d00cc71">Paul, do you find Ruby (on Rails I presume) to be a lot faster for CRUD like apps than PHP?</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_faa4edc084a4013025c312313d00cc71">@MikeH: honestly, I don&#8217;t build many small apps in any language, so it&#8217;s hard to comment on that.</div></blockquote></td></tr><tr><td
title="Paul.Annesley">Paul.Ann&#8230; <img
alt="Paul.Annesley" src="https://assets2.talkerapp.com/avatar/e5bbf54758d562838e15cebcc924a141.jpg?s=18" /><b></b></td><td><blockquote><div
id="event_0a5bb97084a5013025c312313d00cc71">I much prefer the Ruby language to the PHP language, despite it being slower</div><div
id="event_225b762084a5013025c312313d00cc71">and Rails is an impressive framework, but it&#8217;s incredibly large and therefore complicated… takes a long time to really learn it.</div><div
id="event_4fc1914084a5013025c312313d00cc71">My answer is: web development is hard. :)</div></blockquote></td></tr></tbody></table><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/what-happened-when-we-talked-php-with-the-experts/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Fabric.js: Advanced</title><link>http://www.sitepoint.com/fabric-js-advanced/</link> <comments>http://www.sitepoint.com/fabric-js-advanced/#comments</comments> <pubDate>Sat, 13 Apr 2013 00:05:14 +0000</pubDate> <dc:creator>Juriy Zaytsev</dc:creator> <category><![CDATA[HTML5]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[HTML5 Dev Center]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65236</guid> <description><![CDATA[In his first two articles, Juriy Zaytsev covered most of the basics of using Fabric.js. Here, he moves on to more advanced features: groups, serialization (and deserialization) and classes.]]></description> <content:encoded><![CDATA[<p></p><p>We’ve covered most of the basics of Fabric in the <a
href="http://www.sitepoint.com/introduction-to-fabric-js/"> first</a> and <a
href="http://www.sitepoint.com/fabric-js-the-fun-stuff/"> second</a> parts of this series. In this article, I’ll move on to more advanced features: groups, serialization (and deserialization) and classes.</p><h2>Groups</h2><p>The first topic I’ll talk about is groups, one of Fabric’s most powerful features. Groups are exactly what they sound like—a simple way to group Fabric objects into a single entity so that you can work with those objects as a unit. (See <strong>Figure 1</strong>.)</p><p><img
class="alignnone size-full wp-image-65395" alt="A Selection Becomes a Group in Fabric" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure18.png" width="275" height="275" /><br
/> <strong>Figure 1. A Selection Becomes a Group in Fabric</strong></p><p>Remember that any number of Fabric objects on the canvas can be grouped with the mouse to form a single selection. Once grouped, the objects can be moved and even modified as one. You can scale the group, rotate it, and even change its presentational properties—its color, transparency, borders, and so on.</p><p>Every time you select objects like this on the canvas, Fabric creates a group implicitly, behind the scenes. Given this, it only makes sense to provide access to groups programmatically, which is where <code>fabric.Group</code> comes in.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p>Let’s create a group from two objects, a circle and text:</p><pre>       var text = new fabric.Text('hello world', {
	  fontSize: 30
	});
	var circle = new fabric.Circle({
	  radius: 100,
	  fill: '#eef',
	  scaleY: 0.5
	});
	var group = new fabric.Group([ text, circle ], {
	  left: 150,
	  top: 100,
	  angle: -10
	});
	canvas.add(group);</pre><p>First, I created a &#8220;hello world&#8221; text object. Then, I created a circle with a 100 px radius, filled with the &#8220;#eef&#8221; color and squeezed vertically (scaleY=0.5). I next created a <code>fabric.Group</code> instance, passing it an array with these two objects and giving it a position of 150/100 at a -10 degree angle. Finally, I added the group to the canvas, as I would with any other object, by using <code>canvas.add()</code>.</p><p>Voila! You see an object on the canvas as shown in <strong>Figure 2</strong>, a labeled ellipse, and can now work with this object as a single entity. To modify that object, you simply change properties of the group, here giving it custom left, top and angle values.</p><p><img
class="alignnone size-full wp-image-65396" alt="A Group Created Programmatically" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure23.png" width="275" height="162" /><br
/> <strong>Figure 2</strong>. <strong>A Group Created Programmatically</strong></p><p>And now that we have a group on our canvas, let’s change it up a little:</p><pre>       group.item(0).set({
	  text: 'trololo',
	  fill: 'white'
	});
	group.item(1).setFill('red');</pre><p>Here, we access individual objects in a group via the item method and modify their properties. The first object is the text, and the second is the squeezed circle. <strong>Figure 3</strong> shows the results.</p><p><img
class="alignnone size-full wp-image-65397" alt=" Squeezed Red Circle with New Text" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure33.png" width="275" height="170" /><br
/> <strong>Figure 3. Squeezed Red Circle with New Text</strong></p><p>One important idea you’ve probably noticed by now is that objects in a group are all positioned relative to the center of the group. When I changed the text property of the text object, it remained centered even when I changed its width. If you don’t want this behavior, you need to specify an object’s left/top coordinates, in which case they’ll be grouped according to those coordinates.</p><p>Here’s how to create and group three circles so that they’re positioned horizontally one after the other, such as those shown in <strong>Figure 4</strong>.</p><pre>       var circle1 = new fabric.Circle({
	  radius: 50,
	  fill: 'red',
	  left: 0
	});
	var circle2 = new fabric.Circle({
	  radius: 50,
	  fill: 'green',
	  left: 100
	});
	var circle3 = new fabric.Circle({
	  radius: 50,
	  fill: 'blue',
	  left: 200
	});
	var group = new fabric.Group([ circle1, circle2, circle3 ], {
	  left: 200,
	  top: 100
	});
	canvas.add(group);</pre><p><img
class="alignnone size-full wp-image-65398" alt="A Group with Three Circles Aligned Horizontally" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure43.png" width="275" height="126" /><br
/> <strong>Figure 4. A Group with Three Circles Aligned Horizontally</strong></p><p>Another point to keep in mind when working with groups is the state of the objects. For example, when forming a group with images, you need to be sure those images are fully loaded. Since Fabric already provides helper methods for ensuring that an image is loaded, this operation becomes fairly easy, as you can see in this code and in Figure 5.</p><pre>       fabric.Image.fromURL('/assets/pug.jpg', function(img) {
	  var img1 = img.scale(0.1).set({ left: 100, top: 100 });
	  fabric.Image.fromURL('/assets/pug.jpg', function(img) {
	    var img2 = img.scale(0.1).set({ left: 175, top: 175 });
	    fabric.Image.fromURL('/assets/pug.jpg', function(img) {
	      var img3 = img.scale(0.1).set({ left: 250, top: 250 });
	      canvas.add(new fabric.Group([ img1, img2, img3],
	        { left: 200, top: 200 }))
	    });
	  });
	});</pre><p><img
class="alignnone size-full wp-image-65400" alt="A Group with Three Images" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure52.png" width="275" height="310" /><br
/> <strong>Figure 5. A Group with Three Images</strong></p><p>Several other methods are available for working with groups:</p><ul><li>getObjects works exactly like fabric.Canvas#getObjects() and returns an array of all objects in a group</li><li>size represents the number of objects in a group</li><li>contains allows you to check whether a particular object is in a group</li><li>item (which you saw earlier) allows you to retrieve a specific object from a group</li><li>forEachObject also mirrors fabric.Canvas#forEachObject, but in relation to group objects</li><li>add and remove add and remove objects from a group, respectively</li></ul><p>You can add or remove objects with or without updating group dimensions and position. Here are several examples:</p><p>To add a rectangle at the center of a group (left=0, top=0), use this code:</p><pre>       group.add(new fabric.Rect({
	  ...
	}));</pre><p>To add a rectangle 100 px from the center of the group, do this:</p><pre>       group.add(new fabric.Rect({
	  ...
	  left: 100,
	  top: 100
	}));</pre><p>To add a rectangle at the center of a group and update the group’s dimensions, use the following code:</p><pre>       group.addWithUpdate(new fabric.Rect({
	  ...
	  left: group.getLeft(),
	  top: group.getTop()
	}));</pre><p>To add a rectangle at 100 px off from the center of a group and update the group’s dimensions, do this:</p><pre>       group.addWithUpdate(new fabric.Rect({
	  ...
	  left: group.getLeft() + 100,
	  top: group.getTop() + 100
	}));</pre><p>Finally, if you want to create a group with objects that are already present on the canvas, you need to clone them first:</p><pre>       // create a group with copies of existing (2) objects
	var group = new fabric.Group([
	  canvas.item(0).clone(),
	  canvas.item(1).clone()
	]);
	// remove all objects and re-render
	canvas.clear().renderAll();
	// add group onto canvas
	canvas.add(group);</pre><h2>Serialization</h2><p>As soon as you start building a stateful application of some sort—perhaps one that allows users to save results of canvas contents on a server or streaming contents to a different client—you need canvas serialization. There’s always an option to export the canvas to an image, but uploading a large image to a server requires a lot of bandwidth. Nothing beats text when it comes to size, and that’s exactly why Fabric provides an excellent support for canvas serialization and deserialization.</p><h2>toObject, toJSON</h2><p>The backbone of canvas serialization in Fabric are the <code>fabric.Canvas#toObject</code> and <code>fabric.Canvas#toJSON</code> methods. Let’s take a look at a simple example, first serializing an empty canvas:</p><pre>       var canvas = new fabric.Canvas('c');
	JSON.stringify(canvas); // '{"objects":[],"background":"rgba(0, 0, 0, 0)"}'</pre><p>Here I’m using the ES5 <code>JSON.stringify</code> method, which implicitly calls the toJSON method on the passed object if that method exists. Because a canvas instance in Fabric has a toJSON method, it’s as though we called <code>JSON.stringify(canvas.toJSON())</code> instead.</p><p>Notice the returned string that represents the empty canvas. It’s in JSON format, and essentially consists of &#8220;objects&#8221; and &#8220;background&#8221; properties. The &#8220;objects&#8221; property is currently empty because there’s nothing on the canvas, and &#8220;background&#8221; has a default transparent value (&#8220;rgba(0, 0, 0, 0)&#8221;).</p><p>Let’s give our canvas a different background and see how things change:</p><pre>canvas.backgroundColor = 'red';
	JSON.stringify(canvas); // '{"objects":[],"background":"red"}'</pre><p>As you would expect, the canvas representation reflects the new background color. Now let’s add some objects:</p><pre>       canvas.add(new fabric.Rect({
	  left: 50,
	  top: 50,
	  height: 20,
	  width: 20,
	  fill: 'green'
	}));
	console.log(JSON.stringify(canvas));</pre><p>The logged output is as follows:</p><pre><code>'{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,
"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,
"perPixelTargetFind":false,"rx":0,"ry":0}],"background":"rgba(0, 0, 0, 0)"}'</code></pre><p>Wow! At first sight, quite a lot has changed, but looking more closely, you can see that the newly added object is now part of the &#8220;objects&#8221; array, serialized into JSON. Notice how its representation includes all its visual traits—left, top, width, height, fill, stroke and so on.</p><p>If we were to add another object—say, a red circle positioned next to the rectangle—you would see that the representation changed accordingly:</p><pre>canvas.add(new fabric.Circle({
	  left: 100,
	  top: 100,
	  radius: 50,
	  fill: 'red'
	}));
	console.log(JSON.stringify(canvas));</pre><p>Here’s the logged output now:</p><pre><code>'{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,"fill":"green","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,
"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,
"perPixelTargetFind":false,"rx":0,"ry":0},"type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red",
"overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,
"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
"transparentCorners":true,"perPixelTargetFind":false,"radius":50}],"background":"rgba(0, 0, 0, 0)"}'</code></pre><p>Notice the &#8220;type&#8221;:&#8221;rect&#8221; and &#8220;type&#8221;:&#8221;circle&#8221; parts so that you can see better where those objects are. Even though it might seem like a lot of output at first, it is nothing compared to what you would get with image serialization. Just for fun, take a look at about one-tenth (!) of a string you would get with <code>canvas.toDataURL('png')</code>:</p><pre><code>data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAK8CAYAAAAXo9vkAAAgAElEQVR4Xu3dP4xtBbnG4WPAQOQ2YBCLK1qpoQE1
/m+NVlCDwUACicRCEuysrOwkwcJgAglEItRQaWz9HxEaolSKtxCJ0FwMRIj32zqFcjm8e868s2fNWoJygl+e397rWetk5xf5pyZd13wPwIEC
BAgQIAAAQIECBxI4F0H+hwfQ4AAAQIECBAgQIAAgQsCxENAgAABAgQIECBAgMDBBATIwah9EAECBAgQIECAAAECAsQzQIAAAQIECBAgQIDAw
QQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAgAABAgQIECBAgMDBBATIwah9EAECBAgQI
ECAAAECAsQzQIAAAQIECBAgQIDAwQQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAgAABA
gQIECBAgMDBBATIwah9EAECBAgQIECAAAECAsQzQIAAAQIECBAgQIDAwQQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBq
H0QAQIECBAgQIAAAQICxDNAgAABAgQIECBAgMDBBATIwah9EAECBAgQIECAAAECAsQzQIAAAQIECBAgQIDAwQQEyMGofRABAgQIECBAgAABA
gLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAgAABAgQIECBAgMDBBATIwah9EAECBAgQIECAAAECAsQzQIAAAQIECBAgQ
IDAwQQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAgAABAgQIECBAgMDBBATIwah9EAECB
AgQIECAAAECAsQzQIAAAQIECBAgQIDAwQQEyMGofRABAgQIECBAgAABAgLEM0CAAAECBAgQIECAwMEEBMjBqH0QAQIECBAgQIAAAQICxDNAg
AABAgQIECBAgMDBBATIwah9EAECBAgQIECAAAECyw+Qb134RU2fevC8q+5esGWESBAgAABAgQIEFiOwPLMC5AlvO0OBMCBAgQIECAAAECJxQ
QICcE9HYCBAgQIECAAAECBPYXECD7W3klAQIECBAgQIAAAQInFBAgJwT0dgIECBAgQIAAAQIE9hcQIPtbeSUBAgQIECBAgAABAicUECAnBPR
2AgQIECBAgAABAgT2FxAg+1t5JQECBAgQIECAAAECJxQQICcE9HYCBAgQIECAAAECBPYXECD7W3klAQIECBAgQIAAAQInFBAgJwTc9+3z49y
vmNd+dI7PzPHJOW6Y4wNzXD3HlXNc9pZdb85/vzbHK3P8aY7n5vj1HL+Y43dz417f97O9jgABAgQIECBAgMBSBATIKd2JCY5dWNwyx5fn+Pw
cV5U/6tXZ99M5fjjHk3Mjd6HifwQIECBAgAABAgQWLSBAirdnouP6WXfvHHfOcU1x9T6rXp4XPTLHA3NTX9jnDV5DgAABAgQIECBA4NACAuS
E4hMdl8+Kr83xzTmuO+G61ttfnEXfnuN7c4PfaC21hwABAgQIECBAgMBJBQTIJQpOeFw7b71/jtsvccWh3vbYfNB9c6NfOtQH+hwCBAgQIEC
AAAECFxMQIMd8No7C4+F5283HfOtZv/ypOYG7hMhZ3wafT4AAAQIECBDYtoAA2fP+H/1Vqwd3f4jf8y1Lfdkunu7xV7OWenucFwECBAgQIEB
g3QICZI/7O/Fxx7xs9wf3t36r3D3evciX7L7F7+6rIY8u8uycFAECBAgQIE</code></pre><p>&#8230;and there’s approximately 17,000 characters more.</p><p>You might be wondering why there&#8217;s also<code> fabric.Canvas#toObject.</code> Quite simply, <code>toObject</code> returns the same representation as toJSON, only in a form of the actual object, without string serialization. For example, using the earlier example of a canvas with just a green rectangle, the output for <code>canvas.toObject</code> is as follows:</p><pre>       { "background" : "rgba(0, 0, 0, 0)",
	  "objects" : [
	    {
	      "angle" : 0,
	      "fill" : "green",
	      "flipX" : false,
	      "flipY" : false,
	      "hasBorders" : true,
	      "hasControls" : true,
	      "hasRotatingPoint" : false,
	      "height" : 20,
	      "left" : 50,
	      "opacity" : 1,
	      "overlayFill" : null,
	      "perPixelTargetFind" : false,
	      "scaleX" : 1,
	      "scaleY" : 1,
	      "selectable" : true,
	      "stroke" : null,
	      "strokeDashArray" : null,
	      "strokeWidth" : 1,
	      "top" : 50,
	      "transparentCorners" : true,
	      "type" : "rect",
	      "width" : 20
	    }
	  ]
	}</pre><p>As you can see, toJSON output is essentially stringified <code>toObject</code> output. Now, the interesting (and useful) thing is that <code>toObject</code> output is smart and lazy. What you see inside an &#8220;objects&#8221; array is the result of iterating over all canvas objects and delegating to each object’s own <code>toObject</code> method. For example, <code>fabric.Path</code> has its own <code>toObject</code> that knows to return path’s &#8220;points&#8221; array, and <code>fabric.Image</code> has a <code>toObject</code> that knows to return image’s &#8220;src&#8221; property. In true object-oriented fashion, all objects are capable of serializing themselves.</p><p>This means that when you create your own class, or simply need to customize an object&#8217;s serialized representation, all you need to do is work with the <code>toObject</code> method, either completely replacing it or extending it. Here’s an example:</p><pre>var rect = new fabric.Rect();
	rect.toObject = function() {
	  return { name: 'trololo' };
	};
	canvas.add(rect);
	console.log(JSON.stringify(canvas));</pre><p>The logged output is:</p><pre><code>'{"objects":[{"name":"trololo"}],"background":"rgba(0, 0, 0, 0)"}'</code></pre><p>As you can see, the objects array now has a custom representation of our rectangle. This kind of override brings the point across but is probably not very useful. Instead, here’s how to extend a rectangle&#8217;s <code>toObject</code> method with an additional property:</p><pre>var rect = new fabric.Rect();
	rect.toObject = (function(toObject) {
	  return function() {
	    return fabric.util.object.extend(toObject.call(this), {
	      name: this.name
	    });
	  };
	})(rect.toObject);
	canvas.add(rect);
	rect.name = 'trololo';
	console.log(JSON.stringify(canvas));</pre><p>And here’s the logged output:</p><pre><code>'{"objects":[{"type":"rect","left":0,"top":0,"width":0,"height":0,"fill":"rgb(0,0,0)","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,
"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
"transparentCorners":true,"perPixelTargetFind":false,"rx":0,"ry":0,"name":"trololo"}],
"background":"rgba(0, 0, 0, 0)"}'</code></pre><p>I extended the object&#8217;s existing <code>toObject </code>method with the additional property &#8220;name&#8221;, which means that property is now part of the <code>toObject </code>output, and as a result it appears in the canvas JSON representation. One other item worth mentioning is that if you extend objects like this, you&#8217;ll also want to be sure the object&#8217;s &#8220;class&#8221; (<code>fabric.Rect</code> in this case) has this property in the &#8220;stateProperties&#8221; array so that loading a canvas from a string representation will parse and add it to an object correctly.</p><h2>toSVG</h2><p>Another efficient text-based canvas representation is in SVG format. Since Fabric specializes in SVG parsing and rendering on canvas, it makes sense to make this a two-way process and provide canvas-to-SVG conversion. Let&#8217;s add the same rectangle to our canvas and see what kind of representation is returned from the <code>toSVG</code> method:</p><pre>       canvas.add(new fabric.Rect({
	  left: 50,
	  top: 50,
	  height: 20,
	  width: 20,
	  fill: 'green'
	}));
	console.log(canvas.toSVG());</pre><p>The logged output is as follows:</p><pre><code>'&lt;?xml version="1.0" standalone="no" ?&gt;&lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="800" height="700"
xml:space="preserve"&gt;&lt;desc&gt;Created with Fabric.js 0.9.21&lt;/desc&gt;&lt;rect x="-10" y="-10"
rx="0" ry="0" width="20" height="20" style="stroke: none; stroke-width: 1; stroke-dasharray: ; fill: green;
opacity: 1;" transform="translate(50 50)" /&gt;&lt;/svg&gt;'</code></pre><p>Just like with <code>toJSON</code> and <code>toObject</code>, the <code>toSVG</code> method—when called on canvas—delegates its logic to each individual object, and each individual object has its own <code>toSVG</code> method that is special to the type of object. If you ever need to modify or extend an SVG representation of an object, you can do the same thing with <code>toSVG</code> as I did earlier with <code>toObject</code>.</p><p>The benefit of SVG representation, compared to Fabric&#8217;s proprietary <code>toObject</code>/<code>toJSON</code>, is that you can throw it into any SVG-capable renderer (browser, application, printer, camera, and so on), and it should just work. With <code>toObject</code>/<code>toJSON</code>, however, you first need to load it onto a canvas.</p><p>And speaking of loading things onto a canvas, now that you know how to serialize a canvas into an efficient chunk of text, how do you go about loading this data back onto canvas?</p><h2>Deserialization and the SVG Parser</h2><p>As with serialization, there&#8217;s two ways to load a canvas from a string: from JSON representation or from SVG. When using JSON representation, there are the <code>fabric.Canvas#loadFromJSON</code> and <code>fabric.Canvas#loadFromDatalessJSON</code> methods. When using SVG, there are <code>fabric.loadSVGFromURL</code> and <code>fabric.loadSVGFromString</code>.</p><p>Notice that the first two methods are instance methods and are called on a canvas instance directly, whereas the other two methods are static methods and are called on the &#8220;fabric&#8221; object rather than on canvas.</p><p>There&#8217;s not much to say about most of these methods. They work exactly as you would expect them to. Let&#8217;s take as an example the previous JSON output from our canvas and load it on a clean canvas:</p><pre>       var canvas = new fabric.Canvas();
	canvas.loadFromJSON('{"objects":[{"type":"rect","left":50,"top":50,"width":20,"height":20,
fill":"green","overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,
"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,
"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,
"rx":0,"ry":0},"type":"circle","left":100,"top":100,"width":100,"height":100,"fill":"red",
"overlayFill":null,"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,
"angle":0,"flipX":false,"flipY":false,"opacity":1,"selectable":true,"hasControls":true,
"hasBorders":true,"hasRotatingPoint":false,"transparentCorners":true,"perPixelTargetFind":false,
"radius":50}],"background":"rgba(0, 0, 0, 0)"}');</pre><p>Both objects magically appear on canvas, as shown in <strong>Figure 6</strong>.</p><p><img
class="alignnone size-full wp-image-65401" alt="A Circle and a Square Rendered on Canvas" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure62.png" width="275" height="269" /><br
/> <strong>Figure 6. A Circle and a Square Rendered on Canvas</strong></p><p>So loading canvas from a string is pretty easy, but what about that strange-looking <code>loadFromDatalessJSON</code> method? How is it different from <code>loadFromJSON</code>, which we just used? To understand why you need this method, look at a serialized canvas that has a more or less complex path object, like the one shown in <strong>Figure 7</strong>.</p><p><img
class="alignnone size-full wp-image-65402" alt="A Complex Shape Rendered on Canvas" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure72.png" width="275" height="258" /><br
/> <strong>Figure 7. A Complex Shape Rendered on Canvas</strong></p><p>JSON.stringify(canvas) output for the shape in <strong>Figure 7</strong> is as follows:</p><pre><code>{"objects":[{"type":"path","left":184,"top":177,"width":175,"height":151,"fill":"#231F20","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":-19,"flipX":false,
"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
"transparentCorners":true,"perPixelTargetFind":false,"path":[["M",39.502,61.823],["c",-1.235,-0.902,-3.038,
-3.605,-3.038,-3.605],["s",0.702,0.4,3.907,1.203],["c",3.205,0.8,7.444,-0.668,10.114,-1.97],["c",2.671,-1.302,
7.11,-1.436,9.448,-1.336],["c",2.336,0.101,4.707,0.602,4.373,2.036],["c",-0.334,1.437,-5.742,3.94,-5.742,3.94],
["s",0.4,0.334,1.236,0.334],["c",0.833,0,6.075,-1.403,6.542,-4.173],["s",-1.802,-8.377,-3.272,-9.013],["c",-1.468,
-0.633,-4.172,0,-4.172,0],["c",4.039,1.438,4.941,6.176,4.941,6.176],["c",-2.604,-1.504,-9.279,-1.234,-12.619,
0.501],["c",-3.337,1.736,-8.379,2.67,-10.083,2.503],["c",-1.701,-0.167,-3.571,-1.036,-3.571,-1.036],["c",1.837,
0.034,3.239,-2.669,3.239,-2.669],["s",-2.068,2.269,-5.542,0.434],["c",-3.47,-1.837,-1.704,-8.18,-1.704,-8.18],
["s",-2.937,5.909,-1,9.816],["C",34.496,60.688,39.502,61.823,39.502,61.823],["z"],["M",77.002,40.772],["c",0,0,
-1.78,-5.03,-2.804,-8.546],["l",-1.557,8.411],["l",1.646,1.602],["c",0,0,0,-0.622,-0.668,-1.691],["C",72.952,
39.48,76.513,40.371,77.002,40.772],["z"],["M",102.989,86.943],["M",102.396,86.424],["c",0.25,0.22,0.447,0.391,
0.594,0.519],["C",102.796,86.774,102.571,86.578,102.396,86.424],["z"],["M",169.407,119.374],["c",-0.09,-5.429,
-3.917,-3.914,-3.917,-2.402],["c",0,0,-11.396,1.603,-13.086,-6.677],["c",0,0,3.56,-5.43,1.69,-12.461],["c",
-0.575,-2.163,-1.691,-5.337,-3.637,-8.605],["c",11.104,2.121,21.701,-5.08,19.038,-15.519],["c",-3.34,-13.087,
-19.63,-9.481,-24.437,-9.349],["c",-4.809,0.135,-13.486,-2.002,-8.011,-11.618],["c",5.473,-9.613,18.024,-5.874,
18.024,-5.874],["c",-2.136,0.668,-4.674,4.807,-4.674,4.807],["c",9.748,-6.811,22.301,4.541,22.301,4.541],["c",
-3.097,-13.678,-23.153,-14.636,-30.041,-12.635],["c",-4.286,-0.377,-5.241,-3.391,-3.073,-6.637],["c",2.314,
-3.473,10.503,-13.976,10.503,-13.976],["s",-2.048,2.046,-6.231,4.005],["c",-4.184,1.96,-6.321,-2.227,-4.362,
-6.854],["c",1.96,-4.627,8.191,-16.559,8.191,-16.559],["c",-1.96,3.207,-24.571,31.247,-21.723,26.707],["c",
2.85,-4.541,5.253,-11.93,5.253,-11.93],["c",-2.849,6.943,-22.434,25.283,-30.713,34.274],["s",-5.786,19.583,
-4.005,21.987],["c",0.43,0.58,0.601,0.972,0.62,1.232],["c",-4.868,-3.052,-3.884,-13.936,-0.264,-19.66],["c",
3.829,-6.053,18.427,-20.207,18.427,-20.207],["v",-1.336],["c",0,0,0.444,-1.513,-0.089,-0.444],["c",-0.535,
1.068,-3.65,1.245,-3.384,-0.889],["c",0.268,-2.137,-0.356,-8.549,-0.356,-8.549],["s",-1.157,5.789,-2.758,
5.61],["c",-1.603,-0.179,-2.493,-2.672,-2.405,-5.432],["c",0.089,-2.758,-1.157,-9.702,-1.157,-9.702],["c",
-0.8,11.75,-8.277,8.011,-8.277,3.74],["c",0,-4.274,-4.541,-12.82,-4.541,-12.82],["s",2.403,14.421,-1.336,
14.421],["c",-3.737,0,-6.944,-5.074,-9.879,-9.882],["C",78.161,5.874,68.279,0,68.279,0],["c",13.428,16.088,
17.656,32.111,18.397,44.512],["c",-1.793,0.422,-2.908,2.224,-2.908,2.224],["c",0.356,-2.847,-0.624,-7.745,
-1.245,-9.882],["c",-0.624,-2.137,-1.159,-9.168,-1.159,-9.168],["c",0,2.67,-0.979,5.253,-2.048,9.079],["c",
-1.068,3.828,-0.801,6.054,-0.801,6.054],["c",-1.068,-2.227,-4.271,-2.137,-4.271,-2.137],["c",1.336,1.783,
0.177,2.493,0.177,2.493],["s",0,0,-1.424,-1.601],["c",-1.424,-1.603,-3.473,-0.981,-3.384,0.265],["c",0.089,
1.247,0,1.959,-2.849,1.959],["c",-2.846,0,-5.874,-3.47,-9.078,-3.116],["c",-3.206,0.356,-5.521,2.137,-5.698,
6.678],["c",-0.179,4.541,1.869,5.251,1.869,5.251],["c",-0.801,-0.443,-0.891,-1.067,-0.891,-3.473],...</code></pre><p>&#8230;and that&#8217;s only 20 percent of the entire output!</p><p>What&#8217;s going on here? Well, it turns out that this <code>fabric.Path</code> instance—this shape—consists of literally hundreds of Bezier lines dictating how exactly it is to be rendered. All those ["c",0,2.67,-0.979,5.253,-2.048,9.079] chunks in JSON representation correspond to each one of those curves. And when there&#8217;s hundreds (or even thousands) of them, the canvas representation ends up being quite enormous.</p><p>Situations like these are where <code>fabric.Canvas#toDatalessJSON</code> comes in handy. Let&#8217;s try it:</p><pre>       canvas.item(0).sourcePath = '/assets/dragon.svg';
	console.log(JSON.stringify(canvas.toDatalessJSON()));</pre><p>Here’s the logged output:</p><pre><code>{"objects":[{"type":"path","left":143,"top":143,"width":175,"height":151,"fill":"#231F20","overlayFill":null,
"stroke":null,"strokeWidth":1,"strokeDashArray":null,"scaleX":1,"scaleY":1,"angle":-19,"flipX":false,
"flipY":false,"opacity":1,"selectable":true,"hasControls":true,"hasBorders":true,"hasRotatingPoint":false,
"transparentCorners":true,"perPixelTargetFind":false,"path":"/assets/dragon.svg"}],"background":"rgba(0, 0, 0, 0)"}</code></pre><p>That&#8217;s certainly smaller, so what happened? Notice that before calling <code>toDatalessJSO</code>N, I gave the path (dragon shape) object a <code>sourcePat</code>h property of &#8220;/assets/dragon.svg&#8221;. Then, when I called <code>toDatalessJSON</code>, the entire humongous path string from the previous output (those hundreds of path commands) is replaced with a single &#8220;dragon.svg&#8221; string.</p><p>When you’re working with lots of complex shapes, <code>toDatalessJSON</code> allows you to reduce canvas representation even further and replace huge path data representations with a simple link to SVG.</p><p>You can probably guess that the <code>loadFromDatalessJSON</code> method simply allows you to load a canvas from a data less version of a canvas representation. The <code>loadFromDatalessJSON</code> method pretty much knows how to take those &#8220;path&#8221; strings (like &#8220;/assets/dragon.svg&#8221;), load them, and use them as the data for corresponding path objects.</p><p>Now, let&#8217;s take a look at SVG-loading methods. We can use either string or URL. Let’s look at the string example first:</p><pre>       fabric.loadSVGFromString('...', function(objects, options) {
	  var obj = fabric.util.groupSVGElements(objects, options);
	  canvas.add(obj).renderAll();
	});</pre><p>The first argument is the SVG string, and the second is the callback function. The callback is invoked when SVG is parsed and loaded and receives two arguments—objects and options. The first, objects, contains an array of objects parsed from SVG—paths, path groups (for complex objects), images, text, and so on. To group those objects into a cohesive collection—and to make them look the way they do in an SVG document—we&#8217;re using <code>fabric.util.groupSVGElement</code>s and passing it both objects and options. In return, we get either an instance of <code>fabric.Path</code> or <code>fabric.PathGroup</code>, which we can then add onto our canvas.</p><p>The <code>fabric.loadSVGFromURL</code> method works the same way, except that you pass a string containing a URL rather than SVG contents. Note that Fabric will attempt to fetch that URL via XMLHttpRequest, so the SVG needs to conform to the usual SOP rules.</p><h2>Subclassing</h2><p>Since Fabric is built in a truly object-oriented fashion, it&#8217;s designed to make subclassing and extension simple and natural. As described in the first article in this series, there&#8217;s an existing hierarchy of objects in Fabric. All two-dimensional objects (paths, images, text, and so on) inherit from <code>fabric.Object</code>, and some &#8220;classes&#8221;—like <code>fabric.PathGroup</code> — even form a third-level inheritance.</p><p>So how do you go about subclassing one of the existing &#8220;classes&#8221; in Fabric, or maybe even creating a class of your own?</p><p>For this task you need the <code>fabric.util.createClass</code> utility method. This method is nothing but a simple abstraction over JavaScript&#8217;s prototypal inheritance. Let&#8217;s first create a simple Point &#8220;class&#8221;:</p><pre>       var Point = fabric.util.createClass({
	  initialize: function(x, y) {
	    this.x = x || 0;
	    this.y = y || 0;
	  },
	  toString: function() {
	    return this.x + '/' + this.y;
	  }
	});</pre><p>The <code>createClass</code> method takes an object and uses that object&#8217;s properties to create a class with instance-level properties. The only specially treated property is initialize, which is used as a constructor. Now, when initializing Point, we&#8217;ll create an instance with x and y properties and the <code>toString</code> method:</p><pre>       var point = new Point(10, 20);
	point.x; // 10
	point.y; // 20
	point.toString(); // "10/20"</pre><p>If we wanted to create a child of &#8220;Point&#8221; class—say a colored point—we would use <code>createClass</code> like so:</p><pre>       var ColoredPoint = fabric.util.createClass(Point, {
	  initialize: function(x, y, color) {
	    this.callSuper('initialize', x, y);
	    this.color = color || '#000';
	  },
	  toString: function() {
	    return this.callSuper('toString') + ' (color: ' + this.color + ')';
	  }
	});</pre><p>Notice how the object with instance-level properties is now passed as a second argument. And the first argument receives Point &#8220;class&#8221;, which tells <code>createClass</code> to use it as a parent class of this one. To avoid duplication, we&#8217;re using the <code>callSuper</code> method, which calls the method of a parent class. This means that if we were to change <code>Point</code>, the changes would also propagate to the <code>ColoredPoint</code> class.</p><p>Here’s ColoredPoint in action:</p><pre>var redPoint = new ColoredPoint(15, 33, '#f55');
	redPoint.x; // 15
	redPoint.y; // 33
	redPoint.color; // "#f55"
	redPoint.toString(); "15/35 (color: #f55)"</pre><p>Now let’s see how to work with existing Fabric classes. For example, let’s create a <code>LabeledRect</code> class that will essentially be a rectangle that has some kind of label associated with it. When rendered on our canvas, that label will be represented as a text inside a rectangle (similar to the earlier group example with a circle and text). As you&#8217;re working with Fabric, you&#8217;ll notice that combined abstractions like this can be achieved either by using groups or by using custom classes.</p><pre>       var LabeledRect = fabric.util.createClass(fabric.Rect, {
	  type: 'labeledRect',
	  initialize: function(options) {
	    options || (options = { });
	    this.callSuper('initialize', options);
	    this.set('label', options.label || '');
	  },
	  toObject: function() {
	    return fabric.util.object.extend(this.callSuper('toObject'), {
	      label: this.get('label')
	    });
	  },
	  _render: function(ctx) {
	    this.callSuper('_render', ctx);
	    ctx.font = '20px Helvetica';
	    ctx.fillStyle = '#333';
	    ctx.fillText(this.label, -this.width/2, -this.height/2 + 20);
	  }
	});</pre><p>It looks like there&#8217;s quite a lot going on here, but it&#8217;s actually pretty simple. First, we&#8217;re specifying the parent class as <code>fabric.Rect</code>, to utilize its rendering abilities. Next, we define the type property, setting it to &#8220;<code>labeledRect</code>&#8220;. This is just for consistency, because all Fabric objects have the type property (rect, circle, path, text, and so on.) Then there&#8217;s the already-familiar constructor (initialize), in which we utilize <code>callSuper</code> once again. Additionally, we set the object&#8217;s label to whichever value was passed via options. Finally, we&#8217;re left with two methods—<code>toObject</code> and <code>_render</code>. The <code>toObjec</code>t method, as you already know from the serialization section, is responsible for object (and JSON) representation of an instance. Since <code>LabeledRect</code> has the same properties as regular <code>rect</code> but also a label, we&#8217;re extending the parent&#8217;s <code>toObject</code> method and simply adding a label into it. Last but not least, the <code>_render</code> method is what&#8217;s responsible for the actually drawing of an instance. There&#8217;s another <code>callSuper</code> call in it, which is what renders rectangle, and an additional three lines of text-rendering logic.</p><p>If you were to render such object, you do something like the following. <strong>Figure 8</strong> shows the results.</p><pre>       var labeledRect = new LabeledRect({
	  width: 100,
	  height: 50,
	  left: 100,
	  top: 100,
	  label: 'test',
	  fill: '#faa'
	});
	canvas.add(labeledRect);</pre><p><img
class="alignnone size-full wp-image-65403" alt="Rendering of labeledRect" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure82.png" width="275" height="216" /><br
/> <strong>Figure 8. Rendering of labeledRect</strong></p><p>Changing the label value or any of the other usual rectangle properties would obviously work as expected, as you can see here and in <strong>Figure 9</strong>.</p><pre>labeledRect.set({
	  label: 'trololo',
	  fill: '#aaf',
	  rx: 10,
	  ry: 10
	}</pre><p><img
class="alignnone size-full wp-image-65404" alt="Modified labeledRect" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure92.png" width="275" height="248" /><br
/> <strong>Figure 9. Modified labeledRect</strong></p><p>Of course, at this point you’re free to modify the behavior of this class anyway you want. For example, you could make certain values the default values to avoid passing them every time to the constructor, or you could make certain configurable properties available on the instance. If you do make additional properties configurable, you might want to account for them in <code>toObject</code> and <code>initialize</code>, as I’ve shown here:</p><pre>       ...
	initialize: function(options) {
	  options || (options = { });
	  this.callSuper('initialize', options);
	  // give all labeled rectangles fixed width/height of 100/50
	  this.set({ width: 100, height: 50 });
	  this.set('label', options.label || '');
	}
	...
	_render: function(ctx) {
	  // make font and fill values of labels configurable
	  ctx.font = this.labelFont;
	  ctx.fillStyle = this.labelFill;
	  ctx.fillText(this.label, -this.width/2, -this.height/2 + 20);
	}
	...</pre><h2>Wrapping Up</h2><p>That closes the third installment of this series, in which I’ve dived into some of the more advanced aspects of Fabric. With help from groups, serialization and deserialization and classes, you can take your app to a whole new level.</p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/fabric-js-advanced/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>SEO Can Help You Communicate</title><link>http://www.sitepoint.com/seo-can-help-you-communicate/</link> <comments>http://www.sitepoint.com/seo-can-help-you-communicate/#comments</comments> <pubDate>Thu, 11 Apr 2013 09:48:01 +0000</pubDate> <dc:creator>Georgina Laidlaw</dc:creator> <category><![CDATA[Business]]></category> <category><![CDATA[Content strategy]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[SEO and SEM]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65288</guid> <description><![CDATA[Search engine optimization can drive site owners to do some funny things. Georgina Laidlaw wishes they'd understand that SEO can enhance effective communication with site visitors.]]></description> <content:encoded><![CDATA[<p></p><p>I never met a developer who advocated SEO. Most of the entrepreneurs I know see it as a business essential—like a bank account, or a band name. And copywriters seem divided: SEO is either the way to structure any and all text, or a last-minute add-on to make the marketers happy.</p><p>Recently, I was working with a client who realised half-way through copy development that he wanted to include the current website&#8217;s existing body text into the new content we were writing.</p><p>Why? SEO. He was worried his business would lose search rank if he replaced the current web text.</p><p>I suggested keeping the current text intact as it was and framing the new copy around it, but he liked our new copy better. He wanted to shoehorn existing sentences into the new content wherever they might fit (so long as it was fairly high up on the page).</p><p>He revised a page of our draft text to integrate these sentences. We&#8217;re not talking a lot of copy here: maybe 50-75 words. But it read <em>badly</em>. In fact, the <a
href="http://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_Readability_Test">readability scores</a> for his revised text were two full grades higher than our original copy.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p>When I pointed this out, along with some factual issues in the current text that we were aiming to eliminate with the new text, he gave me this answer:</p><blockquote><p>&#8220;Oh, I don&#8217;t think that matters. No one will read it anyway—I think they&#8217;ll just read the headings here and click through to the product demo.&#8221;</p></blockquote><p>Well then, I wondered, why clutter up the page with all these boring words anyway? Let&#8217;s delete them, leave the headings, and let the people just click on through (if indeed that&#8217;s what they were going to do).</p><h2>The problem with SEO as SEO</h2><p>This client saw SEO as a separate issue from communication. Of <em>course</em> we couldn&#8217;t delete the words no one was going to read from this page—they were the thing that would get us search traffic.</p><p>But once those people came, they wouldn&#8217;t bother <em>reading</em> the text, they&#8217;d just click through. Right?</p><p>Well, maybe. I don&#8217;t know about you, but as a searcher, when I click through from a search result, the first thing I do is look for the words I&#8217;m searching for on the page that&#8217;s displayed. Ideally, they&#8217;ll be contained in headings, because I&#8217;m scanning at this point, and keywords in headings act like signposts: here&#8217;s what you&#8217;re searching for.</p><p>If not headings, it&#8217;s good if keywords are contained in links because they&#8217;re scannable too. If not there, then I guess I&#8217;ll just have to start scanning actual sentences (<em>yawn</em>). Or maybe I&#8217;ll just hit the Back button and try another search result.</p><p>I don&#8217;t think this is an abnormal use case. I believe this is how a lot of people often behave with search results.</p><p>Don&#8217;t dismiss SEO. Use it to your advantage. It doesn&#8217;t <em>have</em> to be about keyword stuffing to address machine algorithms. SEO <em>can</em> be about providing potential users of your product or service with the information they&#8217;re looking for.</p><h2>SEO can help communication</h2><p>Woah, what? SEO can help communication? Come on. Who are we kidding here?</p><p>Okay, we all know that keywords and phrases are never going to comprise your brand messaging (I hope!) or your entire content (I hope!), though if they&#8217;re particular enough, some of them may creep into your <a
href="http://www.sitepoint.com/tell-the-story-of-your-brand-service-or-product-with-a-brand-vocabulary/">brand vocabulary</a>.</p><p>But knowing what people are searching for, and how your product or service meets that need, can help you communicate more clearly—and more quickly—with those users.</p><p>It can tie your brand closely to the user&#8217;s need from the outset.</p><p><img
class="alignnone size-full wp-image-65289" alt="OMO woollens" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/omowoollens.png" width="576" height="742" /></p><p><em>Search term: washing woollens</em></p><p>It can present your unique offering as the precise solution to a generic problem—at a glance.</p><p><img
src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/logocontestsmelbourne.png" alt="Logo contests, melbourne" width="468" height="430" class="alignnone size-full wp-image-65290" /></p><p><em>Search term: logo design in Melbourne</em></p><p>SEO isn&#8217;t just about long-form text and sales speak. It&#8217;s about making a page answer the user&#8217;s questions clearly and efficiently—from the opening phrase (whether that&#8217;s your IA or page headline) to the &#8220;Buy [keyword] now&#8221; button.</p><p>It&#8217;s about playing with content elements to tell new arrivals to your site that they&#8217;re in the right place. Content elements such as:</p><ul><li>headings and subheadings</li><li>links</li><li>calls to action</li><li>case studies and testimonial blurbs</li><li>and, of course, body content.</li></ul><p>If you&#8217;re the type who&#8217;s happy to keyword-stuff your copy because you don&#8217;t think anyone will read it, then do us all a favor: just delete it.</p><p>Instead, write something that&#8217;s useful for all prospective customers—including those coming through search who don&#8217;t know where they&#8217;ve ended up.</p><p>How well does your website content meet this goal? Do you think SEO can help you communicate with prospective customers and users? Let us know your position on SEO in the comments.</p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/seo-can-help-you-communicate/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Introduction to Fabric.js: the Fun Stuff</title><link>http://www.sitepoint.com/fabric-js-the-fun-stuff/</link> <comments>http://www.sitepoint.com/fabric-js-the-fun-stuff/#comments</comments> <pubDate>Thu, 11 Apr 2013 03:30:31 +0000</pubDate> <dc:creator>Juriy Zaytsev</dc:creator> <category><![CDATA[HTML5]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[HTML5 Dev Center]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65234</guid> <description><![CDATA[Juriy Zaytsev takes us deeper into the world of Fabric.js, including some of the more entertaining aspects such as animating objects. ]]></description> <content:encoded><![CDATA[<p></p><p>In the <a
href="http://www.sitepoint.com/introduction-to-fabric-js/">first article in this series</a>, I looked at the reasons to use Fabric.js, at its object model and object hierarchy, and at different kinds of entities available in Fabric—simple shapes, images, and complex paths. I also described how to perform simple operations with Fabric objects on a canvas. Now that most of the basics are out of the way, let&#8217;s get down to the fun stuff.</p><h2>Animation</h2><p>No respectable canvas library goes without an animation facility, and Fabric is no exception. Given Fabric’s powerful object model and graphical capabilities, it would be a shame not to have animation helpers built in.</p><p>Remember how easy it is to change the property of any object? You just call the set method, passing the corresponding values:</p><pre>        rect.set('angle', 45);</pre><p>Animating an object is just as easy. Every Fabric object has an animate method that, well&#8230; animates that object.</p><pre>        rect.animate('angle', 45, {
	  onChange: canvas.renderAll.bind(canvas)
	});</pre><p>The first argument is the property to animate, and the second argument is the ending value of the animation. If a rectangle has a -15° angle, and you pass 45 in the second argument, the rectangle is animated from -15° to 45°. The third argument is an optional object specifying finer details of animation, such as duration, callbacks, easing, and so on. I’ll show examples of these shortly.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p>One convenient feature of the animate method is that it supports relative values. For example, if you want to animate an object&#8217;s left property by 100px, you can do it like this:</p><pre>        rect.animate('left', '+100', { onChange: canvas.renderAll.bind(canvas) });</pre><p>Similarly, rotating an object 5 degrees counterclockwise can be accomplished like so:</p><pre>        rect.animate('angle', '-5', { onChange: canvas.renderAll.bind(canvas) });</pre><p>You might wonder why I always specify an <code>onChange</code> callback here. As I mentioned, the third argument is optional, but calling <code>canvas.renderAll</code> on each animation frame is what allows you to see actual animation. When you call the animate method, it only animates a property value over time, following a specific algorithm (for example, <code>easing</code>). So, <code>rect.animate('angle', 45)</code> changes an object&#8217;s angle but won&#8217;t rerender the canvas after each change of the angle. And, obviously, you need this rerendering to see the animation.</p><p>Remember that there&#8217;s an entire object model beneath that canvas surface. Objects have their own properties and relations, and a canvas is responsible only for projecting the objects’ existence to the outside world.</p><p>The reason animate doesn&#8217;t automatically rerender the canvas after each change is performance. After all, you can have hundreds or thousands of animating objects on a canvas, and it wouldn&#8217;t be wise if every one of them tried to rerender the screen. Most of the time, you probably need to explicitly specify <code>canvas.renderAll</code> as the <code>onChange</code> callback.</p><p>Other options you can pass to animate are the following:</p><ul><li><code>from</code> Allows you to specify a starting value of the property being animated (if you don&#8217;t want to use the current value).</li><li><code>duration</code> Defaults to 500 ms. This option can be used to change the duration of an animation.</li><li><code>onComplete</code> The callback that&#8217;s invoked at the end of the animation.</li><li><code>easing</code> The easing function.</li></ul><p>All of these options should be self-explanatory, except perhaps <code>easing</code>. Let&#8217;s take a closer look at it.</p><p>By default, animate uses a linear function for animation. If that&#8217;s not what you need, there&#8217;s a slew of easing options available in <code>fabric.util.ease</code>. For example, if you want to move an object to the right in a bouncy fashion, do this:</p><pre>        rect.animate('left', 500, {
	  onChange: canvas.renderAll.bind(canvas),
	  duration: 1000,
	  easing: fabric.util.ease.easeOutBounce
	});</pre><p>Notice that <code>fabric.util.ease.easeOutBounce</code> is an easing option. Other notable options include <code>easeInCubic</code>, <code>easeOutCubic</code>, <code>easeInElastic</code>, <code>easeOutElastic</code>, <code>easeInBounce</code>, and <code>easeOutExpo</code>.</p><p>Just to give you some idea of what becomes possible with animation in Fabric, you can animate an object&#8217;s angle to make it rotate; animate left or top properties to make it move; animate its width and height to make it shrink and grow; animate opacity to make it fade in and out; and so on.</p><h2>Image filters</h2><p>In the first article in this series, you saw how to work with images in Fabric. There&#8217;s the <code>fabric.Image</code> constructor that accepts an image element. There&#8217;s also the <code>fabric.Image.fromURL</code> method, which can create an image instance from a URL string. Any of these images can be thrown and rendered on a canvas just like any other object.</p><p>But as fun as it is to work with images, it&#8217;s even cooler to apply image filters to them. Fabric provides a few filters by default (you can view them <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl07" href="http://fabricjs.com/image-filters/">here</a>) and makes defining your own filters easy. Some of the built-in filters you might already be familiar with are a filter to remove a white background, the grayscale filter, or invert or brightness filters. Others might be a little less familiar, such as gradient transparency, sepia, or noise.</p><p>Every instance of <code>fabric.Image</code> has a filters property, which is a simple array of filters. Each of the filters in that array is an instance of one of the Fabric filters or an instance of a custom filter.</p><p>Here’s the code you use to create a grayscale image. <strong>Figure 1</strong> shows the results.</p><pre>        fabric.Image.fromURL('pug.jpg', function(img) {
	 // add filter
	  img.filters.push(new fabric.Image.filters.Grayscale());
	  // apply filters and re-render canvas when done
	  img.applyFilters(canvas.renderAll.bind(canvas));
	  // add image onto canvas
	  canvas.add(img);
	});</pre><p><img
class="alignnone size-full wp-image-65318" alt="Applying a Grayscale Image Filter" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure15.png" width="250" height="250" /><br
/> <strong>Figure 1. Applying a Grayscale Image Filter</strong></p><p>And here’s how to create a sepia version of an image, which results in the image effects shown in <strong>Figure 2</strong>.</p><pre>        fabric.Image.fromURL('pug.jpg', function(img) {
	  img.filters.push(new fabric.Image.filters.Sepia());
	  img.applyFilters(canvas.renderAll.bind(canvas));
	  canvas.add(img);
	});</pre><p><img
class="alignnone size-full wp-image-65319" alt="Applying a Sepia Image Filter" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure22.png" width="250" height="250" /><br
/> <strong>Figure 2. Applying a Sepia Image Filter</strong></p><p>Because the filters property is a simple array, you can perform any operation you want with it in the usual way—remove a filter (via pop, splice, or shift), add a filter (via push, splice, unshift), or even combine multiple filters. Any filters present in the filters array will be applied one by one when you call <code>applyFilters</code>.</p><p>Here’s how you can create an image that&#8217;s both sepia and bright. <strong>Figure 3</strong> shows the results.</p><pre>        fabric.Image.fromURL('pug.jpg', function(img) {
	  img.filters.push(
	    new fabric.Image.filters.Sepia(),
	    new fabric.Image.filters.Brightness({ brightness: 100 }));
	  img.applyFilters(canvas.renderAll.bind(canvas));
	  canvas.add(img);
	});</pre><p><img
class="alignnone size-full wp-image-65320" alt="Combining a Sepia and a Bright Image Filter" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure32.png" width="250" height="250" /><br
/> <strong>Figure 3. Combining a Sepia and a Bright Image Filter</strong></p><p>Notice that I also passed the <code>{ brightness: 100 }</code> object to the brightness filter. That&#8217;s because some filters can be applied without any additional configuration (for example, grayscale, invert, sepia), and others provide finer control for their behavior. For the brightness filter, it&#8217;s the actual brightness level <code>(0–255)</code>. For the noise filter, it&#8217;s the noise value <code>(0–1000)</code>. For the remove white filter, it&#8217;s the threshold and distance values. And so on.</p><p>Now that you’re familiar with Fabric filters, it&#8217;s time to break out of the box and create your own. The template for creating a filter is pretty straightforward. You need to create a class and then define an <code>applyTo</code> method. Optionally, you might give the filter the <code>toJSON</code> method (support for JSON serialization) or the <code>initialize</code> method (support for optional parameters). Below is an example of the code, with the results shown in <strong>Figure 4</strong>.</p><pre>        fabric.Image.filters.Redify = fabric.util.createClass({
	  type: 'Redify',
	  applyTo: function(canvasEl) {
	    var context = canvasEl.getContext('2d'),
	      imageData = context.getImageData(0, 0,
	        canvasEl.width, canvasEl.height),
	      data = imageData.data;
	    for (var i = 0, len = data.length; i &lt; len; i += 4) {
	      data[i + 1] = 0;
	      data[i + 2] = 0;
	    }
	    context.putImageData(imageData, 0, 0);
	  }
	});
	fabric.Image.filters.Redify.fromObject = function(object) {
	  return new fabric.Image.filters.Redify(object);
	};</pre><p><img
class="alignnone size-full wp-image-65321" alt="Applying a Custom Image Filter" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure42.png" width="250" height="250" /><br
/> <strong>Figure 4. Applying a Custom Image Filter</strong></p><p>Without delving too much into this code, the main action happens in a loop, where I replace the green <code>(data[i+1])</code> and blue <code>(data[i+2])</code> components of each pixel with 0, essentially removing them. The red component of standard RGB values stays untouched, essentially painting the entire image red. As you can see, the <code>applyTo</code> method is passed to the main canvas element representing the entire image. From there, you can iterate over its pixels <code>(getImageData().data)</code>, modifying them in any way you want.</p><h2>Colors</h2><p>Whether you&#8217;re more comfortable working with hex, RGB, or RGBA colors, Fabric provides a solid color foundation to help you express yourself most naturally. Here are some of the ways in which you can define a color in Fabric:</p><pre>        new fabric.Color('#f55');
	new fabric.Color('#123123');
	new fabric.Color('356735');
	new fabric.Color('rgb(100,0,100)');
	new fabric.Color('rgba(10, 20, 30, 0.5)');</pre><p>Conversion is straightforward as well. The <code>toHex()</code> method converts color instances to hex representation, <code>toRgb()</code> to RGB colors, and <code>toRgba()</code> to RGB with alpha channel.</p><pre>        new fabric.Color('#f55').toRgb(); // "rgb(255,85,85)"
	new fabric.Color('rgb(100,100,100)').toHex(); // "646464"
	new fabric.Color('fff').toHex(); // "FFFFFF"</pre><p>Conversion is not the only step you can take with colors. You can also overlay one color with another or turn it to a grayscale version.</p><pre>        var redish = new fabric.Color('#f55');
	var greenish = new fabric.Color('#5f5');
	redish.overlayWith(greenish).toHex(); // "AAAA55"
	redish.toGrayscale().toHex(); // "A1A1A1"</pre><h2>Gradients</h2><p>An even more expressive way to work with colors is via gradients. Gradients allow you to blend one color with another, creating some stunning graphical effects.</p><p>Fabric supports gradients through the <code>setGradientFill</code> method, which is defined on all objects. Calling <code>setGradientFill</code> is just like setting the fill value of an object, except that you fill the object with a gradient rather than a single color. Below is some sample code, with the visual effect shown in <strong>Figure 5</strong>.</p><pre>        var circle = new fabric.Circle({
	  left: 100,
	  top: 100,
	  radius: 50
	});
	circle.setGradientFill({
	  x1: 0,
	  y1: 0,
	  x2: 0,
	  y2: circle.height,
	  colorStops: {
	  0: '#000',
	  1: '#fff'
	}
	});</pre><p><img
class="alignnone size-full wp-image-65322" alt="Applying a Gradient Fill to an Object" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure51.png" width="172" height="170" /><br
/> <strong>Figure 5. Applying a Gradient Fill to an Object</strong></p><p>In this example, I create a circle at location <code>100,100,</code> with a 50px radius. I then set its fill to a gradient from white to black that spans the entire height of that circle.</p><p>The argument passed to a method is an options object, which expects two coordinate pairs (<code>x1, y1</code> and <code>x2, y2</code>), as well as a <code>colorStops</code> object. Coordinates specify where a gradient starts and where it ends. The <code>colorStops</code> object specifies which colors a gradient is made of. You can define as many color stops as you want, as long as they range from 0 to 1 (for example, 0, 0.1, 0.3, 0.5, 0.75, 1, and so on). Zero (0) represents the beginning of a gradient, and 1 represents its end.</p><p>Here&#8217;s code that creates a left-to-right, red-blue gradient. <strong>Figure 6</strong> shows the results.</p><pre>        circle.setGradientFill({
	  x1: 0,
	  y1: circle.height / 2,
	  x2: circle.width,
	  y2: circle.height / 2,
	  colorStops: {
	    0: "red",
	    1: "blue"
	  }
	});</pre><p><img
class="alignnone size-full wp-image-65323" alt="A Gradient Created Using Color Stops" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure61.png" width="174" height="167" /><br
/> <strong>Figure 6. A Gradient Created Using Color Stops</strong></p><p>The code below shows a five-stop rainbow gradient, with colors spanning even 20 percent intervals. <strong>Figure 7</strong> shows the results.</p><pre>        circle.setGradientFill({
	  x1: 0,
	  y1: circle.height / 2,
	  x2: circle.width,
	  y2: circle.height / 2,
	  colorStops: {
	  0: "red",
	    0.2: "orange",
	    0.4: "yellow",
	    0.6: "green",
	    0.8: "blue",
	    1: "purple"
	}
	});</pre><p><img
class="alignnone size-full wp-image-65324" alt="A Rainbow Gradient" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure71.png" width="161" height="146" /><br
/> <strong>Figure 7. A Rainbow Gradient</strong></p><p>Which cool versions can you come up with?</p><h2>Text</h2><p>What if you want to display not only images and vector shapes on a canvas but also text? Fabric has you covered through <code>fabric.Text</code> objects.</p><p>There are two reasons for providing text abstraction in Fabric. First, it allows you to work with text in an object-oriented fashion. Native canvas methods—as usual—only allow you to fill or stroke text on a very low level. By instantiating <code>fabric.Text</code> instances, you can work with text just like you work with any other Fabric object—move it, scale it, change its properties, and so on.</p><p>The second reason is to provide much richer functionality than what the canvas element gives us. Some of the Fabric additions include:</p><p><strong>Multiline support</strong> Native text methods, unfortunately, simply ignore new lines.<br
/> <strong>Text alignment </strong>Left, center, and right. Useful when working with multiple lines of text.<br
/> <strong>Text background </strong>Background also respects text alignment.<br
/> <strong>Text decoration </strong>Underline, overline, and strikethrough.<br
/> <strong>Line height</strong>  Useful when working with multiple lines of text.</p><p>Here’s a “hello world” example:</p><pre>        var text = new fabric.Text('hello world', { left: 100, top: 100 });
	  canvas.add(text);
	});</pre><p>That&#8217;s right! Displaying text on a canvas is as simple as adding an instance of <code>fabric.Text</code> at a specified location. As you can see, the only required parameter is the actual text string. The second argument is the usual options object, which can have any of the usual properties, such as left, top, fill, opacity, and so on.</p><p>But, of course, text objects also have their own text-related properties. Let&#8217;s look at some of them.</p><h3>fontFamily</h3><p>Set as Times New Roman by default, the <code>fontFamily</code> property allows you to change the font family used to render a text object. Changing the property immediately renders text in the new font. <strong>Figure 8</strong> shows the effects created by using the following code.</p><pre>        var comicSansText = new fabric.Text("I'm in Comic Sans", {
	  fontFamily: 'Comic Sans'
	});</pre><p><img
class="alignnone size-full wp-image-65325" alt="A Change to the fontFamily Property" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure81.png" width="400" height="140" /><br
/> <strong>Figure 8. A Change to the fontFamily Property</strong></p><h3>fontSize</h3><p>Font size controls the size of rendered text. Note that unlike with other objects in Fabric, you can&#8217;t change a text object&#8217;s width and height properties directly. Instead, you need to change the <code>fontSize</code> value to make text objects larger, as you can see in <strong>Figure 9</strong>. (Either that, or you can use <code>scaleX/scaleY</code> properties.)</p><pre>        var text40 = new fabric.Text("I'm at fontSize 40", {
	  fontSize: 40
	});
	var text20 = new fabric.Text("I'm at fontSize 20", {
	  fontSize: 20
	});</pre><p><img
class="alignnone size-full wp-image-65326" alt="Controlling Font Size" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure91.png" width="400" height="170" /><br
/> <strong>Figure 9. Controlling Font Size</strong></p><h3>fontWeight</h3><p>Font weight lets you make text look thicker or thinner. Just as in CSS, you can use keywords (such as normal or bold—see <strong>Figure 10</strong> for an example) or numbers (100, 200, 400, 600, 800). Whether you can use certain weights depends on the availability of that weight for a chosen font. If you&#8217;re using a remote font, you need to be sure you provide both normal and bold (as well as any other required weight) font definitions.</p><pre>        var normalText = new fabric.Text("I'm a normal text", {
	  fontWeight: 'normal'
	});
	var boldText = new fabric.Text("I'm at bold text", {
	  fontWeight: 'bold'
	});</pre><p><img
class="alignnone size-full wp-image-65327" alt="Font Weight Can Be Controlled by Keywords or Numerical Values" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure101.png" width="401" height="171" /><br
/> <strong>Figure 10. Font Weight Can Be Controlled by Keywords or Numerical Values</strong></p><h3>textDecoration</h3><p>You use text decoration to add underline, overline, or strikethrough to text. Again, this is similar to CSS, but Fabric goes a little further and allows you to use any combination of these decorations together. So, you can have text that&#8217;s both underlined and overlined, underlined with strikethrough, and so on, as you can see in <strong>Figure 11</strong>.</p><pre>        var underlineText = new fabric.Text("I'm underlined text", {
	  textDecoration: 'underline'
	});
	var strokeThroughText = new fabric.Text("I'm stroke-through text", {
	  textDecoration: 'line-through'
	});
	var overlineText = new fabric.Text("I'm overlined text", {
	  textDecoration: 'overline'
	});</pre><p><img
class="alignnone size-full wp-image-65328" alt="Examples of text decorations" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure111.png" width="460" height="210" /><br
/> <strong>Figure 11. Examples of text decorations</strong></p><h3>textShadow</h3><p>Text shadows consist of four components: color, horizontal offset, vertical offset, and blur size. These effects might be very familiar if you&#8217;ve worked with shadows in CSS. Lots of combinations are possible (see <strong>Figure 12</strong>) by changing these values.</p><pre>        var shadowText1 = new fabric.Text("I'm a text with shadow", {
	  textShadow: 'rgba(0,0,0,0.3) 5px 5px 5px'
	});
	var shadowText2 = new fabric.Text("And another shadow", {
	  textShadow: 'rgba(0,0,0,0.2) 0 0 5px'
	});
	var shadowText3 = new fabric.Text("Lorem ipsum dolor sit", {
	  textShadow: 'green -5px -5px 3px'
	});</pre><p><img
class="alignnone size-full wp-image-65329" alt="Examples of Text Shadows fontStyle" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure121.png" width="458" height="219" /><br
/> <strong>Figure 12. Examples of Text Shadows</strong></p><h3>fontStyle</h3><p>A font style can be one of two values: normal or italic. This is similar to the CSS property of the same name. The following code shows some examples of using <code>fontStyle</code>, and <strong>Figure 13</strong> shows the results.</p><pre>        var italicText = new fabric.Text("A very fancy italic text", {
	  fontStyle: 'italic',
	  fontFamily: 'Delicious'
	});
	var anotherItalicText = new fabric.Text("another italic text", {
	  fontStyle: 'italic',
	  fontFamily: 'Hoefler Text'
	});</pre><p><img
class="alignnone size-full wp-image-65330" alt="Examples of Italic Font Styles" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure131.png" width="385" height="155" /><br
/> <strong>Figure 13. Examples of Italic Font Styles</strong></p><h3>strokeStyle and strokeWidth</h3><p>By combining <code>strokeStyle</code> (color of the stroke) and <code>strokeWidth</code> (its width), you can achieve some interesting text effects, as shown in <strong>Figure 14</strong>. Here are a couple of code examples:</p><pre>        var textWithStroke = new fabric.Text("Text with a stroke", {
	  strokeStyle: '#ff1318',
	  strokeWidth: 1
	});
	var loremIpsumDolor = new fabric.Text("Lorem ipsum dolor", {
	  fontFamily: 'Impact',
	  strokeStyle: '#c3bfbf',
	  strokeWidth: 3
	});</pre><p><img
class="alignnone size-full wp-image-65331" alt="Text Effects Using strokeStyle and strokeWidth" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure141.png" width="500" height="240" /><br
/> <strong>Figure 14. Text Effects Using strokeStyle and strokeWidth</strong></p><h3>textAlign</h3><p>Text alignment is useful when you’re working with a multiline text object. With a one-line text object, the width of the bounding box always matches that line&#8217;s width, so there&#8217;s nothing to align.</p><p>Allowed values for <code>textAlign</code> are left, center, and right. <strong>Figure 15</strong> shows right-aligned text.</p><pre>        var text = 'this is\na multiline\ntext\naligned right!';
	var alignedRightText = new fabric.Text(text, {
	  textAlign: 'right'
	});</pre><p><img
class="alignnone size-full wp-image-65332" alt="Right-Aligned Text" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure151.png" width="296" height="133" /><br
/> <strong>Figure 15. Right-Aligned Text</strong></p><h3>lineHeight</h3><p>Another property that might be familiar from CSS is <code>lineHeight</code>. It allows you to change vertical spacing between text lines in multiline text. In the following example, the first chunk of text has <code>lineHeight</code> set to 3, and the second one to 1. The results you see are shown in <strong>Figure 16</strong>.</p><pre>        var lineHeight3 = new fabric.Text('Lorem ipsum ...', {
	  lineHeight: 3
	});
	var lineHeight1 = new fabric.Text('Lorem ipsum ...', {
	  lineHeight: 1
	});</pre><p><img
class="alignnone size-full wp-image-65333" alt="Examples of Line Height" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure16.png" width="440" height="320" /><br
/> <strong>Figure 16. Examples of Line Height</strong></p><h3>backgroundColor</h3><p>Finally, <code>backgroundColor</code> is what allows you to give text a background. Note that a background fills only the space occupied by text characters, not the entire bounding box, as you can see in <strong>Figure 17</strong>. This means that text alignment changes the way the text background is rendered—and so does line height, because background respects vertical spacing between lines created by <code>lineHeight</code>.</p><pre>        var text = 'this is\na multiline\ntext\nwith\ncustom lineheight\n&amp;background';
	var textWithBackground = new fabric.Text(text, {
	  backgroundColor: 'rgb(0,200,0)'
	});</pre><p><img
class="alignnone size-full wp-image-65334" alt="Text Background Effects" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure17.png" width="271" height="219" /><br
/> <strong>Figure 17. Text Background Effects</strong></p><h2>Events</h2><p>The event-driven architecture is the basis for some amazing power and flexibility within a framework. Fabric is no exception, and it provides an extensive event system, starting from low-level mouse events to high-level object ones.</p><p>These events allow you to tap into different moments of various actions happening on a canvas. Do you want to know when the mouse was pressed? Just observe the <code>mouse:down</code> event. How about when an object was added to a canvas? In this case, <code>object:added</code> is there for you. And what about when the entire canvas is rerendered? Just use <code>after:render</code>.</p><p>The event API is very simple and resembles that of jQuery, Underscore.js, or other popular JS libraries. There&#8217;s an <code>on</code> method to initialize the event listener, and an <code>off</code> method to remove it.</p><p>Here’s an example:</p><pre>        var canvas = new fabric.Canvas('...');
	canvas.on('mouse:down', function(options) {
	  console.log(options.e.clientX, options.e.clientY);
	});</pre><p>In this code, I’m adding the <code>mouse:down</code> event listener onto the canvas and giving it an event handler that will log coordinates of where the event originated. In other words, the handler will log where exactly on the canvas the mouse was pressed. The event handler receives an options object, which has two properties: <code>e</code>, which is the original event, and <code>target</code>, which is a clicked object on the canvas, if any. The event is present at all times, but the target exists only if a user actually does click an object on the canvas. Also, the target is passed to handlers of events only where it makes sense—for example, for <code>mouse:down</code> but not for <code>after:render</code> (which denotes that the entire canvas was redrawn).</p><pre>        canvas.on('mouse:down', function(options) {
	  if (options.target) {
	    console.log('an object was clicked! ', options.target.type);
	  }
	});</pre><p>This example will log &#8220;an object was clicked!&#8221; if you click an object. It will also add the type of object clicked.</p><p>Some of the other mouse-level events available in Fabric are <code>mouse:move</code> and <code>mouse:up</code>. Generic events include <code>after:render</code>, and there are also selection-related events: <code>before:selection:created</code>, <code>selection:created</code>, <code>selection:cleared</code>. And finally, object events include <code>object:modified</code>, <code>object:selected</code>, <code>object:moving</code>, <code>object:scaling</code>, <code>object:rotating</code>, and <code>object:added</code>.</p><p>Events like <code>object:moving</code> (or <code>object:scaling</code>) are fired continuously every time an object is moved (or scaled) even by a pixel. On the other hand, events like <code>object:modified</code> or <code>selection:created</code> are fired only at the end of the action (object modification or selection creation).</p><p>Note how events are attached right onto the canvas (<code>canvas.on('mouse:down', ...)</code>). As you can imagine, this means that events are all scoped to canvas instances. If you have multiple canvases on a page, you can attach different event listeners to each of them. They&#8217;re all independent and respect only events that are assigned to them.</p><p>For convenience, Fabric takes the event system even further and allows you to attach listeners directly to canvas objects. Take a look at this code:</p><pre>        var rect = new fabric.Rect({ width: 100, height: 50, fill: 'green' });
	rect.on('selected', function() {
	  console.log('selected a rectangle');
	});
	var circle = new fabric.Circle({ radius: 75, fill: 'blue' });
	circle.on('selected', function() {
	  console.log('selected a circle');
	});</pre><p>Here I’m attaching event listeners directly to rectangle and circle instances. Instead of <code>object:selected</code>, I’m using the selected event. Similarly, I could have used the modified event (<code>object:modified</code> when attaching to the canvas), the rotating event <code>(object:rotating</code> when attaching to the canvas), and so on.</p><p>Check this <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl32" href="http://fabricjs.com/events/">events demo</a> for a more extensive exploration of Fabric&#8217;s event system.</p><p>In the next article, I’ll move on to more advanced features: groups, serialization (and deserialization) and classes.</p><p><em> This article was originally published at <a
href="http://msdn.microsoft.com/en-us/magazine/jj856929.aspx">http://msdn.microsoft.com/en-us/magazine/jj856929.aspx</a> and is reproduced here with permission.</em></p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/fabric-js-the-fun-stuff/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>How Much Do You Really Know About PHP?</title><link>http://www.sitepoint.com/how-much-do-you-really-know-about-php/</link> <comments>http://www.sitepoint.com/how-much-do-you-really-know-about-php/#comments</comments> <pubDate>Tue, 09 Apr 2013 04:26:29 +0000</pubDate> <dc:creator>Sarah Hawk</dc:creator> <category><![CDATA[Community]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[PHP]]></category> <category><![CDATA[talk with the experts]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65250</guid> <description><![CDATA[No matter how much you do or don't know about PHP, we're confident that our experts can shed some light on your burning questions. Make sure you join our free 'Talk Object-Oriented PHP with the Experts' session at 7am BST this Thursday April 11th.]]></description> <content:encoded><![CDATA[<p></p><p>What do you <em>actually</em> know about PHP…? Why not test your knowledge by answering the questions below (you can find the answers at <a
title="QuizPoint" href="http://quizpoint.com/" target="_blank">http://quizpoint.com/</a>)?</p><p>1. What was the <i>original</i> definition of the acronym PHP?</p><p>2. PHP is a loosely typed language. What does this mean?</p><p>3. What are magic quotes?</p><p>4. Why might you use &#8220;htmlspecialchars($name, ENT_QUOTES, &#8216;UTF-8&#8242;)&#8221;?</p><p>5. What does the following code output?</p><p>&lt;?php<br
/> $var1 = &#8220;Hi&#8221;;<br
/> $var2 = 3;<br
/> $var2 = $var1;<br
/> $var1 = &#8220;Bye&#8221;;<br
/> echo $var2;<br
/> ?&gt;</p><p>No matter what you scored, we&#8217;re confident that our experts can shed some light on your burning PHP questions. Make sure you join our free <strong>Talk Object-Oriented PHP with the Experts </strong>session at <b>7am BST this Thursday April 11th.</b></p><p>Our expert is Lorna Mitchell &#8211; tutor of the <a
title="Learnable PHP course" href="https://learnable.com/courses/object-oriented-php-2734" target="_blank">Learnable course Object-oriented PHP</a> and co-author of <a
title="PHP Master: Write Cutting-edge Code" href="https://learnable.com/books/phppro1" target="_blank">PHP Master: Write Cutting-edge Code</a></p><p>The session is a 1 hour text based chat session where you are free to ask any questions that you may have. A full transcript of the session will be posted up on <a
title="http://www.sitepoint.com/" href="SitePoint" target="_blank">SitePoint</a> later in the day in case you can&#8217;t make it.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p><a
title="Forum post" href="http://www.sitepoint.com/forums/showthread.php?1012242-Talk-Object-oriented-PHP-with-the-Experts" target="_blank">You can find more info on the session in this forum post</a> or <a
title="Time zone calculator" href="http://www.timeanddate.com/worldclock/fixedtime.html?msg=Talk+Object-oriented+PHP+with+the+Experts&amp;iso=20130411T07&amp;p1=136&amp;ah=1" target="_blank">find out what time the session will take place in your part of the world here</a>.</p><p>A link to the chatroom will be posted in the above forum post on the day, as well as via our <a
title="SitePoint on Twitter" href="https://twitter.com/sitepointdotcom" target="_blank">Twitter</a> and <a
title="SitePoint on Facebook" href="https://www.facebook.com/sitepoint" target="_blank">Facebook</a> pages.</p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/how-much-do-you-really-know-about-php/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Get Loaded with the File API</title><link>http://www.sitepoint.com/get-loaded-with-the-file-api/</link> <comments>http://www.sitepoint.com/get-loaded-with-the-file-api/#comments</comments> <pubDate>Mon, 08 Apr 2013 12:43:41 +0000</pubDate> <dc:creator>Andrew Dodson</dc:creator> <category><![CDATA[APIs]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[HTML5 Dev Center]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65224</guid> <description><![CDATA[Why do avatar uploads restrict us on file size? You know, “Please select an image (maximum 50 KB).” And why haven&#8217;t photo manipulation Web apps come to fruition, since canvas has been around for a while? The answer to both these questions comes down to performance. Until now we’ve needed a slow plug-in or a [...]]]></description> <content:encoded><![CDATA[<p></p><p>Why do avatar uploads restrict us on file size? You know, “Please select an image (maximum 50 KB).” And why haven&#8217;t photo manipulation Web apps come to fruition, since <em>canvas</em> has been around for a while?</p><p>The answer to both these questions comes down to performance. Until now we’ve needed a slow plug-in or a route via a server to create and modify files in the browser. But for Internet Explorer 10, Firefox and Chrome users, developers have in their arsenal the awesome File API to make these operations possible natively in the browser.</p><p>The File API is a new JavaScript API that lets you read and write binary data objects that represent files in Web applications. In a nutshell, you can read user-selected files into Web apps and download new data objects as files from Web apps. Let’s take a deeper look.</p><h2>Breaking Down the File API</h2><p>The File API (<a
href="http://www.w3.org/TR/FileAPI/">as defined by the W3C</a>) is not one type but a collection of typed objects, functions and methods.</p><h2>FileList</h2><p>FileList is a typed object that exists in numerous places. First, as a property on a form input element whose type is &#8220;file&#8221;. Second, as part of the event dispatched on a drop file event or the Clipboard event (as a result of copying and pasting).<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p>For example, let’s say you have a form input control such as this:</p><pre>
&lt;input type=file onchange="console.log(this.files.length)" multiple /&gt;
</pre><p>Whenever the user clicks the form input and selects a file, this action dispatches the onchange event handler, and the FileList object (located at <em>this.files</em> relative to the input element) has some new entries on it. In this example, the number of files the user has selected is printed to the browser console.</p><p>Although the FileList object behaves similarly to a native Array—in that you can iterate through its contents as you can with an Array—a FileList contains only immutable instances of File objects (described next).</p><h2>File</h2><p>The File object represents an individual file of the FileList. The File object contains a hash of read-only metadata about the file, including name, last modification date, size and type. It is also used as a reference and can be passed to the FileReader to read its content.</p><h2>Blob (Binary Large Object)</h2><p>The Blob interface exposes the raw binary data of a file. Remote data can be served as a blob object via XHRRequest—if <em>xhr.responseType</em> is set to &#8220;blob&#8221;. The new blob object is an instance of the Blob API and includes native methods such as blob.slice(i,i+n), which can be used to slice a big blob object into smaller blob objects. (I&#8217;m using the phrase &#8220;Blob interface&#8221; when talking about the JavaScript object type, and &#8220;blob object&#8221; to refer to a single instance of the Blob interface.)</p><p>In addition, with the Blob interface constructor, tiny blob objects can be merged back together again with this interface.</p><pre>new Blob([blob, blob,...])</pre><p>You’ll find an example in the <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl04" href="http://ie.microsoft.com/testdrive/HTML5/BlobBuilder/">BlobBuilder</a> demo, which loads a single MP3 file and then breaks it into different audio files (tracks) that are each applied to their own &lt;audio&gt; tag for playback. In the demo, the user can reconstruct the MP3 in another order by merging the tracks, and even download the new blob object as an MP3.</p><p>Note: The W3C has deprecated the BlobBuilder in favor of Blob. Both produce the same result but in different ways. Also, WebKit&#8217;s BlobBuilder varies between Internet Explorer and Firefox, so it’s best to feature-detect for Blob first.</p><h2>FileReader</h2><p>The FileReader interface takes a File or Blob object and reads its content —File or Blob objects are just references to something stored on the local computer. FileReader can be optimized for reading files of various types—for example, Text(UTF-8), ArrayBuffer(for binary) or base64 data-uri. The following example shows how to get the text of a file using FileReader, given a blob object instance.</p><pre>	var reader = new FileReader();
	reader.onload = function(e){
	       console.log(e.target.result);
	}
	reader.readAsText(blob);</pre><p>Similarly, you can read other content using the read method that best suits the type of file: readAsArrayBuffer (great for working with large binary files) or readAsDataURL (great if you want to quickly embed content into a DOM object, like an image or an audio file).</p><p>The FileReader includes the several event listeners: onerror, onloadstart, onabort and onprogress (which is useful for creating a progress bar for large files and for catching problems).</p><h2>URI Schemes</h2><p>URI Schemes are URIs representing objects in the document. A resource can be a File or a Blob, and its corresponding URL is known as an Object URL. Given a Blob or a File reference, you can create an Object URL by using createObjectURL. For example:</p><pre>var objecturl =  window.URL.createObjectURL(blob)</pre><p>returns a URL that references the resource object, something like &#8220;blob:http%3A//test.com/666e6730-f45c-47c1-8012-ccc706f17191&#8243;.</p><p>This string can be placed anywhere a typical URI can be placed—for example, on the src of an image tag,  if the object URI is of an image that is. The object resource lasts as long as the document, so refresh the page, and it’s gone.</p><h2>FileSaver</h2><p>The FileSaver interface exposes methods to write blobs to the user’s Downloads directory. The implementation is rather neat and straightforward:</p><pre>window.saveAs(blob, "filename")</pre><p>However, none of the browsers currently have this. Only Internet Explorer 10 supports a simple alternative: <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl08" href="http://msdn.microsoft.com/en-us/library/ie/hh772332%28v=vs.85%29.aspx">navigator.msSaveOrOpenBlob</a> as well as <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl09" href="http://msdn.microsoft.com/en-us/library/windows/apps/hh441122.aspx">navigator.msSaveBlob</a>. But as you&#8217;ll see, there are shim&#8217;s that can create a similar functionality, albeit without a slick user experience.</p><p>So that&#8217;s all rather low-level nuts and bolts about the File API, and it’s a lot to digest as an abstract concept. But don’t worry. Coming up is a cooking class for how to turn those ingredients into something you can chew on.</p><h2>Join the Party and Build an Example</h2><p>I thought I’d dress up for the party (<strong>Figure 1</strong>) and create my own little photo manipulation tool at <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl10" href="http://adodson.com/graffiti">http://adodson.com/graffiti</a>. Check it out. Select an image from your file system, scribble over the screen, and then download your masterpiece—all using the File APIs (plus a few canvas methods and pointer events).</p><p><img
class="alignnone size-full wp-image-65225" alt="figure 1" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure14.png" width="467" height="276" /><br
/> <strong>Figure 1. The Graffiti File API App</strong></p><h2>Implementing the Graffiti App</h2><p>Even with the garish picture, this app has a rather simple premise:</p><ul><li>Select an image as a backdrop by using File + FileList and FileReader.</li><li>Load the image into the canvas tag and manipulate the image with the HTML5 Canvas API.</li><li>Download the new image using Blob (or BlobBuilder), saveAs (or saveBlob) or an anchor tag hack with Object URLs.</li></ul><h2>Step 1: Selecting a File</h2><p>There is more than one way a user can select an image for this app.</p><ul><li>Pick a file using form input</li><li>Drag and drop a file</li><li>Copy and paste a file from the Clipboard</li></ul><p>Each of these approaches wires up its listeners to trigger a custom function, named readFile(), which uses an instance of FileReader to extract the file data and add the user image to the canvas. Here is the function’s code.</p><pre>	// readFile, loads File Objects (which are also images) into our Canvas
	// @param File Object
	function readFile(file){
	  // Create a new FileReader Object
	  var reader = new FileReader();
	  // Set an onload handler because we load files into it asynchronously
	  reader.onload = function(e){
	    // The response contains the Data-Uri, which we can then load into the canvas
	    applyDataUrlToCanvas( reader.result );
	  };
	  reader.reaAsDataURL(file);
	}</pre><p>Here, readFile takes the File reference (shown later) and creates a new instance of the FileReader object. This function reads the data as a DataURL, but it could also read the data as binary or even as an ArrayBuffer.</p><p>To wire up the function, you use a File reference as a parameter by taking one of the approaches mentioned earlier.</p><h3>Pick a File Using Form Input</h3><p>The FileAPI doesn&#8217;t (alas) currently define a native method to trigger file selection. But the old trusted form input with type=file does the job quite well:</p><pre>&lt;input type="file" name="picture" accept="image/png, image/jpeg"/&gt;</pre><p>As ungainly as the form input element is, it does have some new additional attributes that are perfect for this app.</p><p>The accept attribute hints at which file types are acceptable. In this example, that’s PNGs and JPEGs. It’s left to the device to handle this appropriately (Windows, for instance, opens the users Pictures library by default and shows only files of these types).</p><p>The <em>multiple</em> tag lets a user select one or more files in one step.</p><p>Next, you need to bind event listeners to the change event of the form input so that a user’s selection automatically triggers readFile:</p><pre>	document.querySelector('input[name=picture]').onchange = function(e){
	     readFile(e.target.files[0]);
	}</pre><p>This code simply takes the first user-selected file (regardless of whether the multiple attribute was used) and then calls readFile, passing in the file as the first parameter.</p><h3>Input a little style</h3><p>The form input box shown here is not really in keeping with my aesthetics, or probably yours. So, position it absolutely over another element of your choice with an opacity of zero (but be prepared for it to have a fixed width, which may interfere with other elements). Or a little more complicated: dispatch a custom click event on an input box positioned off the screen. Read more on this discussion <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl14" href="http://stackoverflow.com/questions/210643/in-javascript-can-i-make-a-click-event-fire-programmatically-for-a-file-input">here</a>.</p><h3>Drag and Drop Files</h3><p>Files can be dragged in from File Explorer and use a similar event model to the form input hack. The &#8220;drop&#8221; event occurs when a user releases the image over the canvas. The event contains a property called dataTransfer, which has a child property named files. In the following code, e.dataTransfer.files is an instance of a FileList (as mentioned before, the FileList contains a list of File references), and the first File item is the parameter for readFile. This is supported in Webkit, Firefox and Internet Explorer 10. Here’s an example:</p><pre>	// stop FireFox from replacing the whole page with the file.
	canvas.ondragover = function () { return false; };
	// Add drop handler
	canvas.ondrop = function (e) {
	  e.preventDefault(); e = e || window.event;
	  var files = e.dataTransfer.files;
	  if(files){
	    readFile(files[0]);
	  }
	};</pre><h3>Copy and Paste File Data</h3><p>Clipboard data can be accessed when the user pastes content into the document. This data can be a mix of text and images and not a FileList with only File references, as in the form input control or in dragging files.</p><p>In the code below, the Clipboard data is traversed and entries corresponding to the type and kind properties, which are  &#8220;*/image&#8221; and &#8220;file&#8221; respectively, are filtered out. The item’s File instance is obtained using getAsFile(), which is passed to readFile.</p><pre>	// paste Clipboard data
	// Well not all of it just the images.
	document.onpaste = function(e){
	  e.preventDefault();
	  if(e.clipboardData&amp;&amp;e.clipboardData.items){
	    // pasted image
	    for(var i=0, items = e.clipboardData.items;i&lt;items.length;i++){
	      if( items[i].kind==='file' &amp;&amp; items[i].type.match(/^image/) ){
	        readFile(items[i].getAsFile());
	        break;
	      }
	    }
	  }
	  return false;
	};</pre><p>That concludes the first step. I’ve shown three approaches to obtaining a File reference and loading file data into the document. I&#8217;d love to know if there are other ways, so please send comments.</p><h2>Step 2: Load the Image onto the Canvas</h2><p>The readFile function in step 1 hands over a generated data-url to another custom function, applyDataUrlToCanvas. This function draws a selected image on the canvas. Here’s how it works:</p><ul><li>Find the width and height of the image.</li><li>Find the orientation of the image.</li><li>Draw the best fit of the image on the canvas.</li></ul><h3>Find the Width and Height</h3><p>Using the DOM Image function, you can easily determine the dimensions of any image. It’s a handy technique and goes something like this:</p><pre>	var img =  new Image();
	img.onload = function(){
	  // img.width
	  // img.height
	}
	img.src = dataURL;</pre><h3>Find the Orientation</h3><p>Unfortunately, there&#8217;s a gotcha with the width and height, and it’s a big one: the picture could have been taken in portrait mode and saved in landscape, or the image could have been taken upside down.</p><p>Some cameras, instead of saving an image in the correct orientation, provide an Orientation property within the image’s <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl18" href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format">EXIF data</a>. This can be read from the binary data of the image.</p><p>Converting the data-url to a binary string is easy:</p><pre>	var base64 = dataUrl.replace(/^.*?,/,'');
	var binary = atob(base64);</pre><p>And fortunately, there&#8217;s an open source <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl20" href="http://www.nihilogic.dk/labs/exif/">EXIF client-side library</a>, written by Jacob Seidelin, which will return the EXIF data as an Object. Yes, awesome!</p><pre>	&lt;script src="http://www.nihilogic.dk/labs/exif/exif.js"&gt;&lt;/script&gt;
	&lt;script src="http://www.nihilogic.dk/labs/binaryajax/binaryajax.js"&gt;&lt;/script&gt;
	&lt;script&gt;
	var exif = EXIF.readFromBinaryFile(new BinaryFile(binary));
	//exif.Orientation
	&lt;/script&gt;</pre><p>The Orientation property is an integer in the range 1–8 corresponding to four rotations and four flips (rather redundant).</p><h3>Draw the Image to Canvas</h3><p>Having discovered the Orientation value, you can rotate and draw on the canvas. If you want to see my algorithm, just dig into the source code, which you can find at <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl22" href="http://adodson.com/graffiti/">http://adodson.com/graffiti/</a> and <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl23" href="https://github.com/MrSwitch/graffiti">https://github.com/MrSwitch/graffiti</a>.</p><h2>Step 3: Download the Image</h2><p>The last step is to download the modified image. Within the FileAPI&#8217;s repertoire, you can use the Blob interface for creating files in the client. Wrap that up with the new msSaveBlob in Internet Explorer 10, or the download attribute hack (coming up) in other modern browsers, and together they enable you to download files in the client.</p><p>Try it yourself in <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl24" href="http://adodson.com/graffiti">the demo</a>. Click on the Download button.</p><p>The demo uses the canvas.toBlob method in Internet Explorer 10 to get the file reference of the image that is currently drawn within the canvas tag. For Chrome and FireFox, the <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl25" href="https://github.com/eligrey/canvas-toBlob.js/">toBlob shim</a> works great.</p><pre>	canvas.toBlob(function( file ){
	  // Create a blob file,
	&nbsp;
	  // then download with the FileSaver
	}</pre><h3>Make a copy of a Blob Object instance</h3><p>We should be able to skip this step, but because of a quirk in all the browsers, you can&#8217;t use the FileSave API directly from the Blob instance returned by canvas.toBlob. You need to copy it.</p><p>The BlobBuilder interface used for creating new Blob references is supported in Internet Explorer 10, Chrome and FireFox. But this interface has already been superseded by the Blob constructor, which has limited support right now.</p><p>First, shim away vendor prefixes of the BlobBuilder:</p><pre>	// Shim the BlobBuilder with the vendor prefixes
	window.BlobBuilder || (window.BlobBuilder = window.MSBlobBuilder||window.MozBlobBuilder||window.WebKitBlobBuilder);</pre><p>Next, future-proof your code and test for the Blob constructor. Otherwise, construct a BlobBuilder to build the blob<strong>.</strong> (It’s best to wrap the methods in a try-catch.) Blob is buggy in the current Chrome for Android browser. Here is the code.</p><pre>	var blob;
	if('Blob' in window){
	  try{
	    // The new Blob interface
	    blob = new Blob([file],{ "type" : "image\/png"});
	  catch(e){}
	}
	if(!blob){
	  try{
	    // The deprecated BlobBuilder interface
	    var bb = new BlobBuilder();
	    bb.append( file );
	    blob = bb.getBlob("image\/png");
	  }
	  catch(e){}
	}</pre><h3>Downloading the Blob with FileSaver</h3><p>The FileSaver API is also a standard yet to be adopted by any of the current crop of browsers. However, in the case of Internet Explorer 10, you can use the msSaveBlob function (which is awesome), and for Chrome and FireFox, you can at least future-proof them with vendor prefixes. So, the saveAs function needs some massive shimming:</p><pre>window.saveAs || (window.saveAs == window.navigator.msSaveBlob || window.webkitSaveAs || window.mozSaveAs || window.msSaveAs /** || URL Download Hack **/ );</pre><p>This fallback (described in full at <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl30" href="https://gist.github.com/3552985">https://gist.github.com/3552985</a>)shims up the FileSaver interface using the Object URL for our new image. For browsers that support the download attribute on the anchor tag, the shim defines the href as the Object URL and then dispatches the click event to force it to download or otherwise open in a new tab. Oh, what tangled webs we weave.</p><p>Finally, given the blob and a file name, the saveAs method initiates the download:</p><pre>	var name = 'Graffiti.png';
	if(window.saveAs){
	  // Move the builder object content to a blob and
	  window.saveAs(blob, name);
	}
	else{
	  // Fallover, open as DataURL
	  window.open(canvas.toDataURL());
	}</pre><p>Here, if the saveAs shim is incompatible, the fallover will open a new tab with a <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl32" href="http://en.wikipedia.org/wiki/Data_URI_scheme">base64 Data-URL</a>. This works in Internet Explorer 9, but Internet Explorer 8 is limited to a DataURI&#8217;s length of 32 KB.</p><h2>Wrapping Up</h2><p>If you haven&#8217;t already played around with the File API, I strongly urge you to. The FileAPI opens up a lot of potential for making desktop-like apps for the browser. You might want a little more control over where you save files and even overwrite the existing file. But for now, security airs on the side of caution, so you’re unlikely to see features like these soon. The specs are still in flux, but what I&#8217;ve highlighted in this article has seen some huge investment by browser vendors and is unlikely to change much, if at all. Please don’t quote me though.</p><p>If you need to support older browsers, take a look at my <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl33" href="https://github.com/mrswitch/dropfile">dropfile.js</a> shim for Internet Explorer, which shims the FileReader and creates a base64 Data-URI, as well as <a
id="ctl00_MTContentSelector1_mainContentContainer_ctl34" href="https://github.com/dcneiner/Downloadify">Downloadify</a> for a Flash-based shim replacement to FileSaver.</p><h2>Resources</h2><ul><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl35" href="http://hackworthy.blogspot.com.au/2012/05/savedownload-data-generated-in.html">“Save/download data generated in JavaScript”</a></li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl36" href="http://www.w3.org/TR/FileAPI/">File API drafts at W3C</a></li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl37" href="http://blogs.msdn.com/b/ie/archive/2012/07/20/new-blob-constructor-in-ie10.aspx">“New Blob Constructor in IE10”</a></li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl38" href="http://blogs.msdn.com/b/ie/archive/2012/01/27/creating-files-through-blobbuilder.aspx">“Creating Files Through BlobBuilder”</a></li><li><a
id="ctl00_MTContentSelector1_mainContentContainer_ctl39" href="http://www.nczonline.net/blog/2012/05/08/working-with-files-in-javascript-part-1/">“Working with files in JavaScript, Part 1: The Basics”</a></li></ul><p><em>This article was originally published at <a
href="http://msdn.microsoft.com/en-us/magazine/jj835793.aspx">http://msdn.microsoft.com/en-us/magazine/jj835793.aspx</a> and is reproduced here with permission.</em></p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/get-loaded-with-the-file-api/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> <item><title>Introduction to Fabric.js</title><link>http://www.sitepoint.com/introduction-to-fabric-js/</link> <comments>http://www.sitepoint.com/introduction-to-fabric-js/#comments</comments> <pubDate>Thu, 04 Apr 2013 10:31:29 +0000</pubDate> <dc:creator>Juriy Zaytsev</dc:creator> <category><![CDATA[HTML5]]></category> <category><![CDATA[JavaScript]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[HTML5 Dev Center]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65138</guid> <description><![CDATA[Juriy Zaytsev  explains how to use <a
href="http://fabricjs.com/">Fabric.js</a>—a powerful JavaScript library that makes working with the HTML5 canvas element a breeze.]]></description> <content:encoded><![CDATA[<p></p><p>In this article, I&#8217;ll introduce you to <a
href="http://fabricjs.com/">Fabric.js</a>—a powerful JavaScript library that makes working with the HTML5 canvas element a breeze. Fabric provides a missing object model for canvas, as well as an SVG parser, a layer of interactivity, and a whole suite of other indispensable tools. It is a fully open-source project, licensed under MIT, with many contributions over the years.</p><p>I started developing with Fabric three years ago after discovering the pains of working with the native canvas API. I was creating an interactive design editor for <a
href="http://printio.ru/">printio.ru</a>—my startup that allows users to design their own apparel. The kind of interactivity I wanted existed only in Flash apps in those days. Now, very few libraries come close to what is possible with Fabric, so let&#8217;s take a closer look.</p><h2>Why Fabric?</h2><p><a
href="http://www.w3.org/html/wg/drafts/html/master/embedded-content-0.html#the-canvas-element"> Canvas</a> allows you to create some <a
href="http://net.tutsplus.com/articles/web-roundups/21-ridiculously-impressive-html5-canvas-experiments/">absolutely</a> <a
href="http://speckyboy.com/2011/12/07/20-amazing-implementations-of-html5-canvas/">amazing</a> <a
href="http://artatm.com/2012/01/23-truly-amazing-and-unbelievable-html5-canvas-and-javascript-experiments/">graphics</a> on the Web these days, but the API it provides is <a
href="http://www.w3.org/html/wg/drafts/2dcontext/html5_canvas/">disappointingly low level</a>. It&#8217;s one thing if you simply want to draw a few basic shapes on a canvas and forget about them. If you need any kind of interaction, to change a picture at any point, or to draw more complex shapes, the situation changes dramatically. Fabric aims to solve this problem.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p>Native canvas methods allow you only to fire off simple graphic commands, blindly modifying the entire canvas bitmap. Do you want to draw a rectangle? Use fillRect(left, top, width, height). Want to draw a line? Use a combination of moveTo(left, top) and lineTo(x, y). It&#8217;s as if you&#8217;re painting a canvas with a brush, layering more and more oil or acrylic on top, with very little control.</p><p>Instead of operating at such a low level, Fabric provides a simple but powerful object model on top of native methods. It takes care of canvas state and rendering and lets you work with objects directly.</p><p>Here’s a simple example that demonstrates this difference. Let&#8217;s say you want to draw a red rectangle somewhere on the canvas. Here&#8217;s how you would do it with the native canvas API:</p><pre>// reference canvas element (with id="c")
var canvasEl = document.getElementById('c');
&nbsp;
// get 2d context to draw on (the "bitmap" mentioned earlier)
var ctx = canvasEl.getContext('2d');
&nbsp;
// set fill color of context
ctx.fillStyle = 'red';
&nbsp;
// create rectangle at a 100,100 point, with 20x20 dimensions
ctx.fillRect(100, 100, 20, 20);</pre><p>The code below shows how you do the same thing with Fabric. The result of both approaches is shown in Figure 1.</p><pre>// create a wrapper around native canvas element (with id="c")
var canvas = new fabric.Canvas('c');
&nbsp;
// create a rectangle object
var rect = new fabric.Rect({
    left: 100,
    top: 100,
    fill: 'red',
    width: 20,
    height: 20
});
&nbsp;
// "add" rectangle onto canvas
canvas.add(rect);</pre><p><img
class="alignnone size-full wp-image-65149" alt="Figure 1 Red Rectangle Drawn with Fabric or Native Canvas Methods " src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure1.png" width="287" height="287" /><br
/> <em><br
/> Figure 1 Red Rectangle Drawn with Fabric or Native Canvas Methods</em></p><p>At this point, there&#8217;s almost no difference in the size of the rectangle—the two examples are pretty similar. However, you can already see how different the approach to working with canvas is. With native methods, you operate on context—an object representing the entire canvas bitmap. In Fabric, you operate on objects—you instantiate them, change their properties, and add them to the canvas. You can see that these objects are first-class citizens in Fabric land.</p><p>Rendering a plain red rectangle is too simple. You can at least have some fun with it and perhaps the shape slightly. Let&#8217;s try 45 degrees, first using native canvas methods:</p><pre>var canvasEl = document.getElementById('c');
var ctx = canvasEl.getContext('2d');
ctx.fillStyle = 'red';
&nbsp;
ctx.translate(100, 100);
ctx.rotate(Math.PI / 180 * 45);
ctx.fillRect(-10, -10, 20, 20);</pre><p>And here’s how you do it in Fabric. (See Figure 2 for the results).</p><pre>var canvas = new fabric.Canvas('c');
// create a rectangle with angle=45
var rect = new fabric.Rect({
    left: 100,
    top: 100,
    fill: 'red',
    width: 20,
    height: 20,
    angle: 45
});
&nbsp;
canvas.add(rect);</pre><p><img
class="alignnone size-full wp-image-65150" alt="Figure 1 Red Rectangle Drawn with Fabric or Native Canvas Methods " src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure2.png" width="296" height="283" /></p><p><em>Figure 2 Red, Rotated Rectangle Drawn with Fabric or Native Canvas Methods<br
/> </em><br
/> What’s happening here? All you have to do in Fabric is change the object&#8217;s angle value to 45. With native methods, however, more work is required. Remember that you can&#8217;t operate on objects. Instead, you have to tweak the</p><p>positioning and angle of the entire canvas bitmap (ctx.translate, ctx.rotate) to suit your needs. You then draw the rectangle again, remembering to offset the bitmap properly (-10, -10) so that it&#8217;s still rendered at the point of 100,100. As a bonus, you have to translate degrees to radians when rotating the canvas bitmap.</p><p>I&#8217;m sure you&#8217;re starting to see why Fabric exists and how much low-level boilerplate it hides.</p><p>Let&#8217;s take a look at another example: keeping track of canvas state.</p><p>What if at some point, you want to move the rectangle to a slightly different location on the canvas? How can you do this without being able to operate on objects? Would you just call another fillRect on a canvas bitmap? Not quite. Calling another fillRect command actually draws a rectangle on top of whatever is already drawn on the canvas. To move the rectangle, you need to first erase any previously drawn content and then draw the rectangle at a new location (see Figure 3).</p><pre>var canvasEl = document.getElementById('c');
...
ctx.strokRect(100, 100, 20, 20);
...
// erase entire canvas area
ctx.clearRect(0, 0, canvasEl.width, canvasEl.height);
ctx.fillRect(20, 50, 20, 20);</pre><p>Here’s how you would accomplish this with Fabric:</p><pre>var canvas = new fabric.Canvas('c');
...
canvas.add(rect);
...
rect.set({ left: 20, top: 50 });
canvas.renderAll();</pre><p><img
class="alignnone size-full wp-image-65151" alt="Figure 3 Red Rectangle Drawn at a New Location " src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure3.png" width="302" height="290" /></p><p><em>Figure 3 Red Rectangle Drawn at a New Location</em></p><p>Notice a very important difference: with Fabric, you don’t need to erase the content before attempting to modify any content. You still work with objects simply by changing their properties and then render the canvas again to get a fresh picture.</p><h2>Objects</h2><p>You saw in the last section how to work with rectangles by instantiating the fabric.Rect constructor. Fabric, of course, covers the other basic shapes as well—circles, triangles, ellipses, and so on. The shapes are exposed under the fabric “namespace” as fabric.Circle, fabric.Triangle, fabric.Ellipse, and so on. Fabric provides seven basic shapes:</p><ul><li><a
href="http://fabricjs.com/docs/symbols/fabric.Circle.html" class="broken_link">fabric.Circle </a></li><li><a
href="http://fabricjs.com/docs/symbols/fabric.Ellipse.html" class="broken_link">fabric.Ellipse </a></li><li><a
href="http://fabricjs.com/docs/symbols/fabric.Line.html" class="broken_link">fabric.Line </a></li><li><a
href="http://fabricjs.com/docs/symbols/fabric.Polygon.html" class="broken_link">fabric.Polygon </a></li><li><a
href="http://fabricjs.com/docs/symbols/fabric.Polyline.html" class="broken_link">fabric.Polyline </a></li><li><a
href="http://fabricjs.com/docs/symbols/fabric.Rect.html" class="broken_link">fabric.Rect </a></li><li><a
href="http://fabricjs.com/docs/symbols/fabric.Triangle.html" class="broken_link">fabric.Triangle</a></li></ul><p>To draw a circle, just create a circle object and add it to canvas.</p><pre>var circle = new fabric.Circle({
    radius: 20, fill: 'green', left: 100, top: 100
});
var triangle = new fabric.Triangle({
    width: 20, height: 30, fill: 'blue', left: 50, top: 50
});
&nbsp;
canvas.add(circle, triangle);</pre><p>You do the same thing with any other basic shape. Figure 4 shows an example of a green circle drawn at location 100,100 and a blue triangle at 50,50.</p><p><img
class="alignnone size-full wp-image-65152" alt="Figure 4 A Blue Triangle and a Green Circle Drawn with Fabric " src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure4.png" width="287" height="286" /></p><p><em>Figure 4 A Blue Triangle and a Green Circle Drawn with Fabric</em></p><p>Manipulating objects</p><p>Creating graphical objects—rectangles, circles, or something else—is only the beginning. At some point, you will probably need to modify your objects. Perhaps a certain action will trigger a change of state or play an animation of some sort. Or you might want to change object properties (such as color, opacity, size, position) on certain mouse interactions.</p><p>Fabric takes care of canvas rendering and state management for you. We need only to modify the objects themselves. The example earlier demonstrated the set method and how calling set({ left: 20, top: 50 }) moved the object from its previous location. In a similar fashion, you can change any other property of an object.</p><p>As you would expect, Fabric objects have properties related to positioning (left, top), dimensions (width, height), rendering (fill, opacity, stroke, strokeWidth), scaling and rotation (scaleX, scaleY, angle), and flipping (flipX, flipY).Yes, creating flipped object in Fabric is as easy as setting the flip* property to true.</p><p>You can read any of these properties via a get method and set them via set. Here’s an example of how to change some of the red rectangle&#8217;s properties. Figure 5 shows the results.</p><pre>var canvas = new fabric.Canvas('c');
...
canvas.add(rect);
&nbsp;
rect.set('fill', 'red');
rect.set({ strokeWidth: 5, stroke: 'rgba(100,200,200,0.5)' });
rect.set('angle', 15).set('flipY', true);</pre><p><img
class="alignnone size-full wp-image-65153" alt="Figure 5 Red, Rotated, Stroked Rectangle Drawn with Fabric " src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure5.png" width="287" height="285" /></p><p><em>Figure 5 Red, Rotated, Stroked Rectangle Drawn with Fabric</em></p><p>First, the fill value is set to “red”. The next statement sets the strokeWidth and stroke values, giving the rectangle a 5 px stroke of a pale green color. Finally, the code changes the angle and flipY properties. Notice how each of the three statements uses slightly different syntax.</p><p>This demonstrates that set is a universal method. You will probably use it quite often, and it&#8217;s meant to be as convenient as possible. What about getters? There&#8217;s a generic get method and also a number of specific ones. To read the width property of an object, you use get(&#8216;width&#8217;) or getWidth(). To get the scaleX value, you would use get(&#8216;scaleX&#8217;), getScaleX() and so on. There&#8217;s a method like getWidth or getScaleX for each of the “public” object properties (stroke, strokeWidth, angle, and so on).</p><p>You might have noticed that in the earlier examples, objects were created with the same configuration hash as the one we just used in the set method. You can “configure” an object at the time of creation or use the set method later:</p><pre>var rect = new fabric.Rect({ width: 10, height: 20, fill: '#f55', opacity: 0.7 });
// or functionally identical
var rect = new fabric.Rect();
rect.set({ width: 10, height: 20, fill: '#f55', opacity: 0.7 });</pre><h2>Default Options</h2><p>At this point, you might wonder what happens when you create an object without passing any “configuration” object. Does it still have those properties?</p><p>Yes. When specific settings are omitted during creation, objects in Fabric always have a default set of properties. You can use the following code to see this for yourself:</p><pre>var rect = new fabric.Rect(); // notice no options passed in
&nbsp;
rect.getWidth(); // 0
rect.getHeight(); // 0
&nbsp;
rect.getLeft(); // 0
rect.getTop(); // 0
&nbsp;
rect.getFill(); // rgb(0,0,0)
rect.getStroke(); // null
&nbsp;
rect.getOpacity(); // 1</pre><p>This rectangle has a default set of properties. It&#8217;s positioned at 0,0, is black and fully opaque, and has no stroke and no dimensions (width and height are 0). Because no dimensions are given, you can&#8217;t see it on the canvas. Giving it any positive values for width and height would reveal a black rectangle at the top-left corner of the canvas, as shown in Figure 6.</p><p><img
class="alignnone size-full wp-image-65154" alt="Figure 6 How Default Rectangle Looks When Given Dimensions " src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure6.png" width="296" height="295" /></p><p><em>Figure 6 How Default Rectangle Looks When Given Dimensions</em></p><h2>Hierarchy and Inheritance</h2><p>Fabric objects do not exist independently of each other. They form a very precise hierarchy. Most objects inherit from the root fabric.Object. The fabric.Object root object represents (more or less) a two-dimensional shape, positioned in a two-dimensional canvas plane. It&#8217;s an entity that has left/top and width/height properties, as well as a slew of other graphical characteristics. The properties listed for objects—fill, stroke, angle, opacity, flip*, and so on—are common to all Fabric objects that inherit from fabric.Object.</p><p>This inheritance allows you to define methods on fabric.Object and share them among all child “classes”. For example, if you want to have a getAngleInRadians method on all objects, you would simply create it on fabric.Object.prototype, as follows:</p><pre>fabric.Object.prototype.getAngleInRadians = function() {
    return this.getAngle() / 180 * Math.PI;
};
&nbsp;
var rect = new fabric.Rect({ angle: 45 });
rect.getAngleInRadians(); // 0.785...
&nbsp;
var circle = new fabric.Circle({ angle: 30, radius: 10 });
circle.getAngleInRadians(); // 0.523...
&nbsp;
circle instanceof fabric.Circle; // true
circle instanceof fabric.Object; // true</pre><p>As you can see, the method immediately becomes available on all instances.</p><p>Even though child “classes” inherit from fabric.Object, they often also define their own methods and properties. For example, fabric.Circle needs a radius property, and fabric.Image—which we&#8217;ll look at in a moment—needs getElement and setElement methods for accessing and setting the HTML &lt;img&gt; element from which an image instance originates.</p><h2>Canvas</h2><p>Now that you’ve learned about objects in some detail, let&#8217;s get back to canvas.</p><p>The first thing you see in all of the Fabric examples is the creation of a canvas object— new fabric.Canvas(&#8216;&#8230;&#8217;). The fabric.Canvas object serves as a wrapper around the &lt;canvas&gt; element and is responsible for managing all the Fabric objects on that particular canvas. It takes an ID of an element and returns an instance of fabric.Canvas.</p><p>You can add objects to it, reference them from it, or remove them, as shown here:</p><pre>var canvas = new fabric.Canvas('c');
var rect = new fabric.Rect();
canvas.add(rect); // add object
&nbsp;
canvas.item(0); // reference fabric.Rect added earlier (first object)
canvas.getObjects(); // get all objects on canvas (rect will be first and only)
&nbsp;
canvas.remove(rect); // remove previously-added fabric.Rect</pre><p>Managing objects is the main purpose of fabric.Canvas, but it also serves as a configuration host. Do you need to set the background color or image for an entire canvas, clip all contents to a certain area, set a different width and height, or specify whether a canvas is interactive or not? All these options (and others) can be set on fabric.Canvas, either at the time of creation or later.</p><pre>var canvas = new fabric.Canvas('c', {
    backgroundColor: 'rgb(100,100,200)',
    selectionColor: 'blue',
    selectionLineWidth: 2
    // ...
});
&nbsp;
// or
&nbsp;
var canvas = new fabric.Canvas('c');
canvas.backgroundImage = 'http://...';
canvas.onFpsUpdate = function(){ /* ... */ };
// ...</pre><h2>Interactivity</h2><p>One of the unique built-in features of Fabric is a layer of interactivity on top of the object model. The object model exists to allow programmatic access and manipulation of objects on the canvas, but on the outside—on a user level—there&#8217;s a way to manipulate those objects via the mouse (or via touch on touch devices). As soon as you initialize a canvas via the new fabric.Canvas(&#8216;&#8230;&#8217;) call, it&#8217;s possible to select objects (see Figure 7), drag them around, scale or rotate them, and even group them (see Figure 8) to manipulate them in one chunk!</p><p><img
class="alignnone size-full wp-image-65155" alt="Figure 7 Red, Rotated Rectangle in Selected State (Controls Visible) " src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure7.png" width="293" height="290" /></p><p><em>Figure 7 Red, Rotated Rectangle in Selected State (Controls Visible)</em></p><p><img
class="alignnone size-full wp-image-65156" alt="Figure 8 Rectangle and Circle Grouped (Controls Visible)" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure8.png" width="291" height="292" /></p><p><em>Figure 8 Rectangle and Circle Grouped (Controls Visible)</em></p><p>If you want to allow users to drag something on the canvas—let&#8217;s say an image—all you need to do is initialize the canvas and add an object to it. No additional configuration or setup is required.</p><p>To control this interactivity, you can use Fabric&#8217;s selection Boolean property on the canvas object in combination with the selectable Boolean property of individual objects:</p><pre>var canvas = new fabric.Canvas('c');
...
canvas.selection = false; // disable group selection
rect.set('selectable', false); // make object unselectable</pre><p>But what if you don&#8217;t want an interactivity layer at all? If that&#8217;s the case, you can always replace fabric.Canvas with fabric.StaticCanvas. The syntax for initialization is absolutely the same:</p><pre>var staticCanvas = new fabric.StaticCanvas('c');
&nbsp;
staticCanvas.add(
    new fabric.Rect({
        width: 10, height: 20,
        left: 100, top: 100,
        fill: 'yellow',
        angle: 30
    }));</pre><p>This creates a “lighter” version of canvas, without any event-handling logic. You still have the entire object model to work with—adding, removing or modifying objects, as well as changing any canvas configuration. All of this still works, it&#8217;s only event handling that&#8217;s gone.</p><p>Later in this article, when I go over the custom build option, you&#8217;ll see that if StaticCanvas is all you need, you can even create a lighter version of Fabric. This could be a nice option if you need something like non-interactive charts or non-interactive images with filters in your application.</p><h2>Images</h2><p>Adding rectangles and circles to a canvas is fun, but as you can imagine by now, Fabric also makes working with images very easy. Here’s how you instantiate the fabric.Image object and add it to a canvas, first in HTML and then in JavaScript:</p><h3>HTML</h3><pre>&lt;canvas id="c"&gt;&lt;/canvas&gt;
&lt;img src="my_image.png" id="my-image"&gt;</pre><h3>JavaScript</h3><pre>var canvas = new fabric.Canvas('c');
var imgElement = document.getElementById('my-img');
var imgInstance = new fabric.Image(imgElement, {
    left: 100,
    top: 100,
    angle: 30,
    opacity: 0.85
});
canvas.add(imgInstance);</pre><p>Notice that you pass an image element to the fabric.Image constructor. This creates an instance of fabric.Image that looks just like the image from the document. Moreover, you immediately set left/top values to 100/100, angle to 30, and opacity to 0.85. Once an image is added to a canvas, it is rendered at location 100,100 at a 30-degree angle and is slightly transparent (see Figure 9). Not bad!</p><p><img
class="alignnone size-full wp-image-65157" alt="Figure 9 Slightly Transparent and Rotated Image, Rendered with Fabric" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure9.png" width="356" height="350" /></p><p><em>Figure 9 Slightly Transparent and Rotated Image, Rendered with Fabric</em></p><p>If you don&#8217;t really have an image in a document but only a URL for an image, you can use fabric.Image.fromURL:</p><pre>fabric.Image.fromURL('my_image.png', function(oImg) {
    canvas.add(oImg);
});</pre><p>Looks pretty straightforward, doesn&#8217;t it? Just call fabric.Image.fromURL, with a URL of an image, and give it a callback to invoke once the image is loaded and created. The callback function receives the already created fabric.Image object as its first argument. At that point, you can add it to your canvas or perhaps change it first and then add it, as shown here:</p><pre>fabric.Image.fromURL('my_image.png', function(oImg) {
    // scale image down, and flip it, before adding it onto canvas
    oImg.scale(0.5).setFlipX(true);
    canvas.add(oImg);
});</pre><h2>Path and PathGroup</h2><p>We&#8217;ve looked at simple shapes and images. What about more complex, richer shapes and content? Meet Path and PathGroup, the power couple.</p><p>Paths in Fabric represent an outline of a shape, which can be filled, stroked and modified in other ways. Paths consist of a series of commands that essentially mimic a pen going from one point to another. With the help of such commands as move, line, curve, and arc, Paths can form incredibly complex shapes. And with the help of groups of Paths (PathGroup), the possibilities open up even more. Paths in Fabric closely resemble SVG &lt;path&gt; elements. They use the same set of commands, can be created from &lt;path&gt; elements, and can be serialized into them. I’ll describe more about serialization and SVG parsing later, but for now it&#8217;s worth mentioning that you will probably only rarely create Path instances by hand. Instead, you&#8217;ll use Fabric&#8217;s built-in SVG parser. But to understand what Path objects are, let&#8217;s create a simple one by hand (see Figure 10 for the results):</p><pre>var canvas = new fabric.Canvas('c');
var path = new fabric.Path('M 0 0 L 200 100 L 170 200 z');
path.set({ left: 120, top: 120 });
canvas.add(path);</pre><p><img
class="alignnone size-full wp-image-65158" alt="Figure 10 Simple Path Rendered with Fabric" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure10.png" width="422" height="419" /></p><p><em>Figure 10 Simple Path Rendered with Fabric</em></p><p>Here you instantiate the fabric.Path object and pass it a string of path instructions. It might look cryptic, but it&#8217;s actually easy to understand. M represents the move command and tells the invisible pen to move to point 0, 0. L stands for line and makes the pen draw a line to point 200, 100. Then, another L creates a line to 170, 200. Lastly, z forces the drawing pen to close the current path and finalize the shape.</p><p>Since fabric.Path is just like any other object in Fabric, you can also change some of its properties, or modify it even more, as shown here and in Figure 11:</p><pre>...
var path = new fabric.Path('M 0 0 L 300 100 L 200 300 z');
...
path.set({ fill: 'red', stroke: 'green', opacity: 0.5 });
canvas.add(path);</pre><p><img
class="alignnone size-full wp-image-65160" alt="Figure 11 A Simple, Modified Path" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure11.png" width="427" height="425" /></p><p><em>Figure 11 A Simple, Modified Path</em></p><p>Out of curiosity, let&#8217;s take a look at a slightly more complex path syntax. You&#8217;ll see why creating paths by hand might not be the best idea:</p><pre>...
var path = new fabric.Path('M121.32,0L44.58,0C36.67,0,29.5,3.22,24.31,8.41\
c-5.19,5.19-8.41,12.37-8.41,20.28c0,15.82,12.87,28.69,28.69,28.69c0,0,4.4,\
0,7.48,0C36.66,72.78,8.4,101.04,8.4,101.04C2.98,106.45,0,113.66,0,121.32\
c0,7.66,2.98,14.87,8.4,20.29l0,0c5.42,5.42,12.62,8.4,20.28,8.4c7.66,0,14.87\
-2.98,20.29-8.4c0,0,28.26-28.25,43.66-43.66c0,3.08,0,7.48,0,7.48c0,15.82,\
12.87,28.69,28.69,28.69c7.66,0,14.87-2.99,20.29-8.4c5.42-5.42,8.4-12.62,8.4\
-20.28l0-76.74c0-7.66-2.98-14.87-8.4-20.29C136.19,2.98,128.98,0,121.32,0z');
canvas.add(path.set({ left: 100, top: 200 }));</pre><p>Here, M still stands for the move command, so the pen starts its drawing journey at point 121.32, 0. Then there&#8217;s an L (line) command that brings the pen to 44.58, 0. So far so good. Now comes the C command, which stands for “cubic bezier.” This command makes the pen draw a bezier curve from the current point to 36.67, 0. It uses 29.5, 3.22 as a control point at the beginning of a line, and 24.31, 8.41 as the control point at the end of the line. This</p><p>whole operation is then followed by a dozen other cubic bezier commands, which finally create a nice-looking shape of an arrow, as shown in Figure 12.</p><p><img
class="alignnone size-full wp-image-65159" alt="Figure 12 Complex Path Rendered with Fabric" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/figure12.png" width="424" height="418" /></p><p><em>Figure 12 Complex Path Rendered with Fabric</em></p><p>Chances are, you won&#8217;t work with such beasts directly. Instead, you can use something like the fabric.loadSVGFromString or fabric.loadSVGFromURL method to load an entire SVG file and let Fabric&#8217;s SVG parser do its job of walking over all SVG elements and creating corresponding Path objects.</p><p>In this context, while Fabric&#8217;s Path object usually represents a SVG &lt;path&gt; element, a collection of paths, often present in SVG documents, is represented as a PathGroup instance (fabric.PathGroup). PathGroup is nothing but a group of Path objects, and because fabric.PathGroup inherits from fabric.Object, it can be added to a canvas just like any other object and manipulated the same way.</p><p>Just like with Paths, you probably won&#8217;t be working with a PathGroup directly. But if you stumble on one after parsing a SVG document, you&#8217;ll know exactly what it is and what purpose it serves.</p><h2>Wrapping Up For Now</h2><p>I’ve only scratched the surface of what&#8217;s possible with Fabric. You can now easily create any of the simple shapes, complex shapes, or images; add them to a canvas and modify them any way you want—their positions, dimensions, angles, colors, strokes, opacity—you name it.</p><p>In the next article in this series, I’ll look at working with groups; animation; text; SVG parsing, rendering and serialization; events; image filters and more. Meanwhile, feel free to take a look at the <a
href="http://fabricjs.com/demos/">annotated demos</a> or <a
href="http://fabricjs.com/benchmarks/">benchmarks</a>, join the discussion at <a
href="http://stackoverflow.com/questions/tagged/fabricjs">Stack Overflow</a> or go straight for the <a
href="http://fabricjs.com/docs/">docs</a>, <a
href="https://github.com/kangax/fabric.js/wiki">wiki</a>, and <a
href="https://github.com/kangax/fabric.js">source</a>. You can also learn more about HTML5 Canvas at the <a
href="http://msdn.microsoft.com/en-us/library/ie/hh771733%28v=vs.85%29.aspx">MSDN IE Developer Center</a>, or check out Rey Bango’s <a
href="http://msdn.microsoft.com/en-us/magazine/ff961912.aspx">An Introduction to the HTML 5 Canvas Element</a> on Script Junkie.</p><p>Have fun experimenting with Fabric! I hope you enjoy the ride.</p><p><em> This article was originally published at <a
href="http://msdn.microsoft.com/en-us/magazine/jj856929.aspx">http://msdn.microsoft.com/en-us/magazine/jj856929.aspx</a> and is reproduced here with permission.</em></p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/introduction-to-fabric-js/feed/</wfw:commentRss> <slash:comments>11</slash:comments> </item> <item><title>Selective Content Loading</title><link>http://www.sitepoint.com/selective-content-loading/</link> <comments>http://www.sitepoint.com/selective-content-loading/#comments</comments> <pubDate>Wed, 03 Apr 2013 13:32:22 +0000</pubDate> <dc:creator>Andrew Fisher</dc:creator> <category><![CDATA[JavaScript]]></category> <category><![CDATA[jQuery]]></category> <category><![CDATA[Programming]]></category> <category><![CDATA[Responsive Web Design]]></category> <category><![CDATA[Tools and Libraries]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65082</guid> <description><![CDATA[Andrew Fisher, co-author of <em>Jump Start Responsive Web Design</em>, expands on the technique called selective content loading, referred to in the book.]]></description> <content:encoded><![CDATA[<p></p><p>One of the techniques we talk about in <a
href="http://www.sitepoint.com/books/responsive1/">Jump Start Responsive Web Design</a> is called Selective Content Loading (SCL). This technique is really useful in situations where you want to load small pieces of data into an already loaded page in a structured way. When would this be useful?</p><ul><li> When you have serious bandwidth issues between your server and the end user’s device (for example, on a mobile connection that is moving on a poor network with lots of errors and having to deal with cell handoff).</li><li> When your pages are largely the same structurally from page to page and simply reloading the content saves many requests.</li><li> If you have chunked your content nicely and want to simply load in the next piece in the sequence (for example, infinite scrolling on a Twitter feed)</li></ul><p>Some of these issues can be dealt with by good caching and using local storage and these should definitely be explored as good practices generally. However, even with smart asset caching you still require server round trips to retrieve a document, all the page HTML still has to be sent to the browser and then the browser still has to render the page.<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><p>If your page has only added a couple of additional bits of data (for example, a tweet) or is only changing a small amount of content (for example, the details for a product) then SCL may be a good option for you. This doesn’t work in every circumstance and it also causes a number of possible issues with URLs, browser history and what content gets spidered on a “page” by search engines (if this important to you).</p><p>Recapping our approach from Jump Start RWD, this is what we’re going to do conceptually:</p><ul><li> On the first page request we’ll load up all of the page content including the site navigation, content layout, CSS and JS files as normal.</li><li> After the page has loaded we’ll override all of the links in our page to make them XHRs rather than a standard request for a document.</li><li> We’ll then process the response (the XHR response will only be the internal page content in JSON rather than the entire page) and overwrite the content that was in the page.</li><li> We can then use <code>pushState()</code> to modify our browser history (so the URL updates to something shareable and we can go backwards if needs be).</li></ul><p>Here’s an example that should illustrate the point simply. The content has been truncated purposefully in order to keep this concise.</p><p>We’re going to set up a page that can load content about books without having to reload the entire page, just the pertinent content. We’ll also use <code>pushState()</code> from the History API to ensure that if the user wants to share or come back to the URL they&#8217;ll be able to do so.</p><p>To make things simple to express, we’re going to use jQuery for the DOM manipulation and a JavaScript templating library called <a
href="http://handlebarsjs.com/">Handlebars.js</a>. If you haven’t checked out JavaScript templating options and what they can do, Handlebars is an excellent choice to get your feet wet.</p><p>The core of our solution relies on the fact that URLs can respond differently depending on whether they are an XHR or a normal HTTP request. If the server gets a normal request then the view will deliver the full HTTP response (containing all the document and then the JS, CSS etc). If the server gets an XHR, it will respond with JSON which only contains data about the book requested.</p><p>So, as an example, the standard HTTP response for the “Frankenstein” page looks like this:</p><pre>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;script type="text/javascript" src="<a href="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js">https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js</a>"&gt;&lt;/script&gt;
&nbsp;
var original = null;
var backtostart = true;
&nbsp;
  &lt;script type="text/javascript"&gt;
      ($(document).ready(function() {
          var source = $("#story-template").html();
          var template = Handlebars.compile(source);
&nbsp;
          var story_link_handler = (function(evt) {
              evt.preventDefault();
              $.get(this.href, function(data) {
                  $("#contentarea").html("");
                  $("#contentarea").html(template(data));
                  history.pushState({url:data.location}, data.title, data.location);
              }, "json");
          });
&nbsp;
          $("ul#storylist li a").bind("click", story_link_handler);
&nbsp;
          $(window).bind("popstate", function(evt) {
              if (event.state) {
                  url = event.state.url;
                  $.get(url, function(data) {
                      $("#contentarea").html("");
                      $("#contentarea").html(template(data));
                  }, "json");
               backtostart = false;
              } else {
               if (! backtostart) {
                  backtostart = true;
                      $("#contentarea").html("");
                      $("#contentarea").html(original);
               } else {
                 original = $("#contentarea").html();
                    backtostart = false;
               }
            }
          });
&nbsp;
      }));
  &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;ul id="storylist"&gt;
      &lt;li&gt;&lt;a href="mobydick"&gt;Moby Dick&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="gulliverstravels"&gt;Gulliver's Travels&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href="frankenstein"&gt;Frankenstein&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;div id="contentarea"&gt;
      &lt;article id="story"&gt;
          &lt;h1&gt;Frankenstein&lt;/h1&gt;
              &lt;h2&gt;Mary Shelley&lt;/h2&gt;
              &lt;p&gt;Doctor creates artificial life&lt;/p&gt;
          &lt;/article&gt;
      &lt;/div&gt;
&lt;script type="text/javascript" src="handlebars.js"&gt;&lt;/script&gt;
      &lt;script id="story-template" type="text/x-handlebars-template"&gt;
      &lt;article&gt;
          &lt;h1&gt;{{title}}&lt;/h1&gt;
          &lt;h2&gt;{{author}}&lt;/h2&gt;
          &lt;p&gt;{{synopsis}}&lt;/p&gt;
      &lt;/article&gt;
      &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p><em>NB you can download code used in this article in a zip file linked at the end of this article</em></p><p>However, the equivalent JSON response for an XHR will look like this instead:</p><pre>{
  "location": "/frankenstein",
  "title": "Frankenstein",
  "author": "Mary Shelley",
  "synopsis": "Mad doctor creates artificial life"
}</pre><p>All the code required to make the selective loading work is requested and loaded in the first request. After that, we only get the data and then load it into the template. Let’s take a look at how the code works.</p><pre>  &lt;script id="story-template" type="text/x-handlebars-template"&gt;
      &lt;article&gt;
          &lt;h1&gt;{{title}}&lt;/h1&gt;
          &lt;h2&gt;{{author}}&lt;/h2&gt;
          &lt;p&gt;{{synopsis}}&lt;/p&gt;
      &lt;/article&gt;
  &lt;/script&gt;</pre><p><em>NB you can download code used in this article in a zip file linked at the end of this article</em></p><p>Handlebars uses a script element to create a template for what an article looks like (this content won’t be rendered by the browser as it won’t take an action on its type). Variable locations are defined using <code>{{variable}}</code> syntax. You can do a lot more with Handlebars (conditionals, loops, block execution etc) that we aren’t using in this instance though. Note the ID for the script, we need this so we can pass it into the Handlebars template compiler.</p><p>In our document ready function, we grab the HTML from the template script tag we defined above and then we compile it into a template object we can use with new data later.</p><pre>  var source = $("#story-template").html();
  var template = Handlebars.compile(source);</pre><p>Next, we define a function we can use for our link <code>onclick</code> event handler. Here we’re simply stopping the actual request to the file by preventing its default behaviour. From there we make a jQuery XHR that returns JSON to the URL that was defined in the link’s <code>HREF</code> attribute.</p><pre>  var story_link_handler = (function(evt) {
      evt.preventDefault();
      $.get(this.href, function(data) {
          $("#contentarea").html("");
          $("#contentarea").html(template(data));
          history.pushState({url:data.location}, data.title, data.location);
      }, "json");
  });</pre><p>When the response comes back, we simply overwrite the <code>div</code> content area that holds all our book data.</p><pre>$("#contentarea").html(template(data));</pre><p>We also use <code>pushState()</code> to push the URL we just requested onto the browser history so we can go backwards using the back button.</p><pre>history.pushState({url:data.location}, data.title, data.location);</pre><p>That’s not quite the whole picture with <code>pushState()</code>, though, in order for it to “just work” for the user. We next create a <code>popstate</code> event handler on the window so that when the user hits the back button we can update the content with the appropriate data for the book. In this case we’re going and getting the data again using an XHR. With pushstate, it’s possible to store data in a <code>state</code> object. In our case the amount of data is small and it’s bad practice to load up the user’s browser with additional data (especially on mobile) so only do it if you can guarantee it’s a tiny amount.</p><pre>  $(window).bind("popstate", function(evt) {
      if (event.state) {
          url = event.state.url;
          $.get(url, function(data) {
              $("#contentarea").html("");
              $("#contentarea").html(template(data));
          }, "json");
      }
  });</pre><p>One of the things we need to consider with this technique is what happens when the browser gets back to the start of the list. That is, you’ve popped all of your XHRs off the stack and you’re back to where you started.</p><p>To remedy this, we use a flag to determine if we’re back to the start or not and we save the content that was in <code>#contentarea</code> so we can replace it. You can use other techniques such as simply hiding the original content area or storing the original document’s JSON.</p><p>We then update the <code>popstate</code> event to check if there’s no <code>event.state</code>. If so, we revert to our original form.</p><pre>$(window).bind("popstate", function(evt) {
              if (event.state) {
                  url = event.state.url;
                  $.get(url, function(data) {
                      $("#contentarea").html("");
                      $("#contentarea").html(template(data));
                  }, "json");
               backtostart = false;
              } else {
               if (! backtostart) {
                  // revert the content to the original
                  backtostart = true;
                      $("#contentarea").html("");
                      $("#contentarea").html(original);
               } else {
                 // store original content to retrieve later
                 original = $("#contentarea").html();
                    backtostart = false;
               }
            }
          });</pre><p>Finally, we add our <code>click</code> event handler to all the relevant links. In our instance, we’re just using the links in the list, but in practice you could do this to a whole range of links based on <code>class</code> or <code>HREF</code> attributes.</p><pre>$("ul#storylist li a").bind("click", story_link_handler);</pre><p>The rest of the page is the page structure and the actual content that was requested &#8211; in this case the <code>/frankenstein</code> URL.</p><p>As can be seen, this approach gives us a nice, responsive setup. The initial page request is a little heavier (in this case about 1Kb) but provides all of the scaffolding needed to layout the page and provide the interactions. Subsequent requests get the benefit of only having to return very small snippets of data, which are then loaded into the template.</p><p>The URL is updated using <code>pushState()</code> which means the user can still share the URL using intents or copy and paste and that URL will work properly for whomever it is shared with. You also get the benefit that each document still exists properly &#8211; this means search engines can still correctly index your site, if that’s needed.</p><p>One of the things we need to be careful of with this technique is that if we have content that exists in many different templates, the benefits from only loading the snippets of data via XHR will be destroyed by having to load all of the different content templates into the first page request and masking it from the user until it&#8217;s used. Don’t forget, all of the HTML still has to be loaded, regardless of whether it’s used or not.</p><p>Where this technique works particularly well is in an “infinite scroll” scenario such as a stream of content or very long article. The content type doesn’t change almost at all (or only within a very defined way)—this technique does for “page content” as a whole what the lazy loading technique does for images within a page. If you’ve taken the time to chunk your content, this can be especially effective as it means you can avoid the user hitting “goto page 2” even though search engines will follow happily.</p><p><a
href="http://blogs.sitepointstatic.com/examples/selective-content-loading/scl_files.zip">Download code files used in this article</a></p><p><em>Delve further into the world of responsive web design in Andrew&#8217;s new book with Craig Sharkie: <a
href="http://www.sitepoint.com/books/responsive1/">Jump Start Responsive Web Design</a>.</em></p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/selective-content-loading/feed/</wfw:commentRss> <slash:comments>7</slash:comments> </item> <item><title>Advanced Custom Menus in Drupal</title><link>http://www.sitepoint.com/advanced-custom-menus-in-drupal/</link> <comments>http://www.sitepoint.com/advanced-custom-menus-in-drupal/#comments</comments> <pubDate>Tue, 02 Apr 2013 11:05:35 +0000</pubDate> <dc:creator>Abbas Suterwala</dc:creator> <category><![CDATA[Drupal]]></category> <category><![CDATA[Programming]]></category> <guid
isPermaLink="false">http://www.sitepoint.com/?p=65032</guid> <description><![CDATA[Abbas Suterwala follows up on his previous article to take creating custom menus in Drupal a step further.]]></description> <content:encoded><![CDATA[<p></p><p>In the last article <a
href="http://www.sitepoint.com/creating-custom-menus-in-drupal/">Creating Custom Menus in Drupal</a> we saw how to respond to URLs,  how to create menus and sub-menus in Drupal and how to pass parameters that can be used to alter the output of the menu callback functions.</p><p>These features might meet your needs for the most of the modules you want to build on top of Drupal, but in addition to these, the Drupal menu system also provides us with more functionality such as passing default arguments to your callback function, using wild cards in menu urls, creating tabbed menus etc&#8230;</p><p>These features can be very useful and can help you structure and design  your module in an easier and more efficient way. In this article we are going to see some of these functionalities and learn how you could use them in your Drupal module.</p><h2>Creating the module</h2><p>Let&#8217;s start by creating a separate module called <em>advancemenudemo</em>. To do this create a folder <em>advancemenudemo sites\all\modules\custom</em> and add two files called as <em>advancemenudemo.module</em> and <em>advancemenudemo.info</em> in it. Add the following code to the <em>advancemenudemo.info</em> file:<div
id='div-gpt-ad-1328644474660-10' style='width:728px; height:90px;'> <script type='text/javascript'>googletag.cmd.push(function() { googletag.display('div-gpt-ad-1328644474660-10'); });</script> </div></p><pre>;$Id$
name = advancemenudemo
description = A module to demo drupals menu system Part 2
package = Menu Demo Package
core = 7.x
files[] = advancemenudemo.module</pre><p>If everything has gone correctly you should now see your module in the Drupal module list as seen below.</p><p><b><img
class="alignnone size-full wp-image-65033" alt="1" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/1.png" width="600" height="123" /> </b><b></b><b></b></p><h2>Passing Default Arguments in your Menu</h2><p>In the last article we saw that the Drupal menu system passes any additional parameters in the URL as arguments. In many modules there is one common generic menu callback function, which responds to multiple menu items.</p><p>Some menu items might have an extra parameter and some might not. In order to use the same callback function the menu item in Drupal can define default arguments that will be passed to the callback function. And the callback can have its normal code which would expect certain arguments to process the output.</p><p>We add default arguments for our menu items as follows:</p><pre>/**
* Implementation of hook_menu().
*/
function advancemenudemo_menu() {
  $menuitems['menudemo'] = array(
  'title' =&gt; 'My Menu',
  'page callback' =&gt; 'advancemenudemo_mymenu_page_callback',
  'page arguments' =&gt; array('Product', 'view'),
  'access callback' =&gt; TRUE,
  'type' =&gt; MENU_NORMAL_ITEM,
  );
return $menuitems;
}
function advancemenudemo_mymenu_page_callback($firstparameter = '', $secondparameter ='') {
  $result = 'My Menu URL was hit';
  $result.='&lt;br&gt; The first parameter passed to the url is :&lt;b&gt;'.$firstparameter.'&lt;/b&gt;';
  $result.='&lt;br&gt; The second parameter passed to the url is :&lt;b&gt;'.$secondparameter.'&lt;/b&gt;';
  return $result;
}</pre><p>In the above code we have specified the menu item parameter</p><pre>'page arguments' =&gt; array('Product', 'view')</pre><p>Two default arguments that are the product and view respectively will be passed to the callback function.</p><p>Now if you click on the menu item the output will be as follows</p><p><img
class="alignnone size-full wp-image-65034" alt="2" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/2.png" width="600" height="186" /></p><p>If you want to specify that the first argument passed to the callback function is a product and the second argument to the callback function should be fetched from the URL, you can update the menu item definition as follows:</p><pre>$menuitems['menudemo'] = array(
  'title' =&gt; 'My Menu',
  'page callback' =&gt; 'advancemenudemo_mymenu_page_callback',
  'page arguments' =&gt; array('Product', 1),
  'access callback' =&gt; TRUE,
  'type' =&gt; MENU_NORMAL_ITEM,
  );</pre><p>Here you are specifying to the Drupal menu system that the first argument sent to the function <em>advancemenudemo_mymenu_page_callback</em> should be ‘Product’ and the second should be the first parameter in the URL after <em>menudemo</em>.</p><p>Now, if you go to the URL <em>&lt;your dupal installation path&gt;/menudemo/edit</em> the output will be as follows:</p><p><img
class="alignnone size-full wp-image-65035" alt="3" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/3.png" width="600" height="279" /></p><p>Note: – Drupal caches the hooks that a module implements, so you might have to go to Administration » Configuration » Development » Performance and do a <i>clear cache</i> to take into consideration the new changes in the hooks implemented by your module in Drupal 7.</p><h2>Using Wild Cards in Menu</h2><p>Sometimes you might want to respond to the URL in that you might not want to hardcode some parts of the URL, and that could be anything that then would be passed to your callback function.</p><p>Drupal lets you specify such wild cards in your URL. You have to use the <code>%</code> sign to signify a wild card. To define a URL with any word after <em>menudemo</em> in the URL you will have to specify the following menu item in your <em>advancemenudemo_menu</em> function:</p><pre>$menuitems['menudemo/%'] = array(
  'title' =&gt; 'Wild Card Menu',
  'page callback' =&gt; 'advancemenudemo_mymenu_page_callback2',
  'page arguments' =&gt; array(1),
  'access callback' =&gt; TRUE,
);
function advancemenudemo_mymenu_page_callback2($firstparameter = '') {
  $result = 'My Menu URL with wildcard was hit';
  $result.='&lt;br&gt; The wildcard value parameter passed to the url is :&lt;b&gt;'.$firstparameter.'&lt;/b&gt;';
  return $result;
}</pre><p>In the above code we are specifying the menu item with a wildcard and the callback function is <em>advancemenudemo_mymenu_page_callback2</em>.The element at position 1, which is the wildcard string, will be passed as the argument to the callback function.</p><p>The function <em>advancemenudemo_mymenu_page_callback2</em> just prints the value of the wildcard argument.</p><p>Now if you go to the URL <em>&lt;drual installation&gt;/menudemo/view</em> you will see the output as follows:</p><p><img
class="alignnone size-full wp-image-65036" alt="4" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/4.png" width="600" height="189" /></p><h2>Loading objects with wild card</h2><p>Sometimes you might not just want the wildcard value passed directly to the callback function, but might want to take that value and then do some processing or fetch some other information based on that argument, and <em>then</em> pass that information to the callback function.</p><p>The Drupal framework allows you to do that by specifying a load function that will be written after the wildcard in the <code>menuitem</code> definition. The value you specify in the definition an function with <code>_load</code> appended to it will be called with the value of the wildcard and the output of that function will be used as argument to the callback function.</p><p>To specify a load function with the wildcard the menu definition will be as follows:</p><pre>$menuitems['menudemo/%/product/%product_id'] = array(
  'title' =&gt; 'Wild Card Menu With Load',
  'page callback' =&gt; 'advancemenudemo_mymenu_page_callback_with_load',
  'page arguments' =&gt; array(1,3),
  'access callback' =&gt; TRUE,
  );
function product_id_load($id)
{
  //Here one can load a product from the database
  //or a file etc..
  $product = array();
  if($id=='1')
  {
    $product['name'] = 'Shirt';
    $product['quantity'] = '5';
  }
  else if($id=='2')
  {
    $product['name'] = 'Jeans';
    $product['quantity'] = '3';
  }
  return $product;
}
function advancemenudemo_mymenu_page_callback_with_load($action, $product)
{
  $result = 'My Wild Card Menu With Load URL was hit';
  $result.='&lt;br&gt; The action parameter passed to the url is :&lt;b&gt;'.$action.'&lt;/b&gt;';
  $result.='&lt;br&gt; The product parameter passed to the url is :&lt;b&gt;'.implode(" : ",$product).'&lt;/b&gt;';
  return $result;
}</pre><p>As the value in the second wildcard we have specified as <em>%product_id</em> the load function <em>product_id_load</em> will be called. In this argument we have just returned an array defining the product with that id. You could fetch the details in the load function from a database or from some file.</p><p>Now if you visit the url <em>&lt;drupal installation&gt;/menudemo/view/product/2</em> you will see the output as follows:</p><p><img
class="alignnone size-full wp-image-65037" alt="5" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/5.png" width="600" height="192" /></p><h2>Creating a Tabbed menu</h2><p>The Drupal framework also lets you create tabbed menus. To define a tabbed menu first we have to define a normal menu item, then define a local default task, and then define different local tasks depending on the number of tabs you want. The menu definition to create three tabs is as follows:</p><pre>$menuitems['menudemo/producttab'] = array(
  'type' =&gt; MENU_NORMAL_ITEM,
  'title' =&gt; 'Product Tab',
  'page callback' =&gt; 'advancemenudemo_mymenu_tabbed_callback',
  'page arguments' =&gt; array('Main Product Tab'),
  'access callback' =&gt; TRUE,
  );
  $menuitems['menudemo/producttab/default'] = array(
  'type' =&gt; MENU_DEFAULT_LOCAL_TASK,
  'title' =&gt; 'Default primary tab',
  'weight' =&gt; 1,
);
  $menuitems["menudemo/producttab/viewall"] = array(
  'type' =&gt; MENU_LOCAL_TASK,
  'title' =&gt; 'View All',
  'page callback' =&gt; 'advancemenudemo_mymenu_tabbed_callback',
  'page arguments' =&gt; array('View all Product Tab'),
  'access callback' =&gt; TRUE,
  'weight' =&gt; 2,
);
$menuitems["menudemo/producttab/editall"] = array(
  'type' =&gt; MENU_LOCAL_TASK,
  'title' =&gt; 'Edit All',
  'page callback' =&gt; 'advancemenudemo_mymenu_tabbed_callback',
  'page arguments' =&gt; array('Edit all Product Tab'),
  'access callback' =&gt; TRUE,
  'weight' =&gt; 3,
);
function advancemenudemo_mymenu_tabbed_callback($firstparameter = '') {
  $result = 'Tabbed menu';
  $result.='&lt;br&gt; The menu clicked is :&lt;b&gt;'.$firstparameter.'&lt;/b&gt;';
  return $result;
}</pre><p>In the above code we have created a Product Tab and two sub tabs: View all Product tab and Edit all Products tab. The callback function just displays whichever tab is clicked.</p><p>If we click on one of the tabs you should see the output as follows:</p><p><img
class="alignnone size-full wp-image-65038" alt="6" src="http://www.sitepoint.com/wp-content/uploads/1/files/2013/04/6.png" width="600" height="188" /> </p><h2>Conclusion<b> </b></h2><p>Drupal has a very strong and flexible menu system. It provides a rich set of features and does all the complex work behind the scenes to provide to  the module an easy interface to work with URLs and produce the content for a particular URL.</p><p>Drupal gives you ways with minimal code to create simple menu items through to more complex tabbed menus by adding a few lines of code to your Drupal module. Drupal does the complex work of parsing the URL and converts  it to a function call in your code by even fetching the arguments of passing default arguments in case the arguments are not passed.</p><p>Based on this infrastructure, your module can provide easy navigation to the user with minimum code.</p><p>Have fun adding amazing menus to your next Drupal module.</p><div
class='after-content-widget-1'><div
id="sitepointcontextualcontentmanagerwidget-5" class="widget widget_sitepointcontextualcontentmanagerwidget"><div
class="dfp-ad show-desktop"><div
id="div-gpt-ad-1340873946991-4" style="width: 728px; height: 90px;"> <script type="text/javascript">googletag.cmd.push(function() { googletag.display("div-gpt-ad-1340873946991-4"); });</script> </div></div></div></div>]]></content:encoded> <wfw:commentRss>http://www.sitepoint.com/advanced-custom-menus-in-drupal/feed/</wfw:commentRss> <slash:comments>1</slash:comments> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using memcached
Database Caching 42/89 queries in 0.308 seconds using memcached
Object Caching 1868/2098 objects using memcached

Served from: www.sitepoint.com @ 2013-05-13 15:11:39 --