<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.0.2" -->
<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/"
	>

<channel>
	<title>julian.dreissig.net</title>
	<link>http://julian.dreissig.net</link>
	<description>Fine Software, Berlin Style</description>
	<pubDate>Thu, 29 Nov 2007 08:46:31 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.0.2</generator>
	<language>en</language>
			<item>
		<title>Another Reflector &#8211; blazingly fast</title>
		<link>http://julian.dreissig.net/blog/another-reflector</link>
		<comments>http://julian.dreissig.net/blog/another-reflector#comments</comments>
		<pubDate>Sun, 21 May 2006 19:50:50 +0000</pubDate>
		<dc:creator>Green</dc:creator>
		
	<category>Javascript</category>
		<guid isPermaLink="false">http://julian.dreissig.net/blog/another-reflector</guid>
		<description><![CDATA[As you may have noticed, even the improved version of the scriptaculous Reflector is too slow to be used on pages with more than just a few small images.
So I took the opportunity to look at a Javascript subject that so far had escaped my studies, that is, the Safari/Gecko canvas tag. The canvas tag [...]]]></description>
			<content:encoded><![CDATA[<p>As you may have noticed, even the <a title="Faster reflections" href="http://julian.dreissig.net/blog/faster-reflecions">improved version</a> of the <a title="&ldquo;Like reflections? Try the Reflector&rdquo;" href="http://mir.aculo.us/articles/2006/04/27/like-reflections-try-the-reflector">scriptaculous Reflector</a> is too slow to be used on pages with more than just a few small images.</p>
<p>So I took the opportunity to look at a Javascript subject that so far had escaped my studies, that is, the Safari/Gecko <a title="Safari Javascript Canvas Class" href="http://developer.apple.com/documentation/AppleApplications/Reference/SafariJSRef/Classes/Canvas.html"><code>canvas</code></a> tag. The <code>canvas</code> tag offers powerful drawing capabilities which are performed right in the browser, have a look at <a title="Drawing Graphics with Canvas" href="http://developer.mozilla.org/en/docs/Drawing_Graphics_with_Canvas">some of it&#8217;s capabilities</a>.<br />
Of course, IE goes a different way and does not support <code>canvas</code>. Still, by applying its <a title="Internet Explorer: Filters" href="http://msdn.microsoft.com/workshop/author/filter/reference/reference.asp">CSS filter attribute</a> one can get a similar reflection effect.<a id="more-5"></a></p>
<p>While I was working on the new version and already had a first working version I came across the nice <a title="reflection.js" href="http://cow.neondragon.net/stuff/reflection/"><code>reflection.js</code></a> by <a title="Cow's blog" href="http://cow.neondragon.net/">Cow</a>, which does exactly what I was trying to get. Exactly the same way I was trying to do it. And it worked. I was too late.<br />
I thus scrapped my code and took <code>reflection.js</code>, modified it a bit and fixed some bugs. Here it is, have a look at the <a title="Another Reflector &ndash; demo page" href="http://dreissig.net/Reflector/another_reflector.html">demo page</a>.<br />
Compared to the scriptaculous version, this code seems longer and of course less elegant. But it is still pretty straightforward, possibly except for the scalings and offsets. You also have to keep in mind that there are actually two routines in it, for both Safari/Gecko and IE.<br />
Since both the <code>canvas</code> tag and the IE CSS filter only support linear gradients, the <code>fade</code> option introduced in my &#8220;faster reflections&#8221; version had to be dropped, sorry.</p>
<pre>
var Reflector = {

  reflect: function(element) {
    element = $(element);
    options = $H({
      amount: 1/3,
      opacity: 1/3
    }).merge(arguments[1] || {});

    // ******************************************************
    // the following code is based on "reflection.js" v1.0 by
    //           Cow http://cow.neondragon.net
    //           Gfx http://www.jroller.com/page/gfx/
    //           Sitharus http://www.sitharus.com
    //           Andreas Linde http://www.andreaslinde.de/
    //
    // modifications &#038; fixes by Julian Dreissig
    // ******************************************************

    // compute size of reflected and total image size

    var reflectionWidth = element.width;
    var reflectionHeight = options.amount * element.height;
    var divHeight = (options.amount) * element.height;

    // replace image element by div containing the original image plus the reflection

    var d = Builder.node('div', {
      style: 'width:'+reflectionWidth+'px;'
           + 'height:'+divHeight+'px;'
    });
    element.parentNode.replaceChild(d, element);
    d.appendChild(element);

    // create the reflection

    if (document.all &#038;&#038; !window.opera) {

      // Internet Exploder: apply MS filter via CSS

      var reflection = Builder.node('div', {
        style: 'width:'+reflectionWidth+'px; '
             + 'height:'+reflectionHeight+'px; '
             + 'background:url('+element.src+') 0 -'+(element.height-reflectionHeight)+'px; '
             + 'filter:flipv progid:DXImageTransform.Microsoft.Alpha(opacity='+(options.opacity*100)+', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+element.height+');'
      });
      d.appendChild(reflection);

    } else {

      // Intelligent browsers (FF, Safari...): create canvas element

      var canvas = Builder.node('canvas', {
        style: 'width:'+reflectionWidth+'px; '
             + 'height:'+reflectionHeight+'px;',
        width: reflectionWidth,
        height: reflectionHeight
      });
      d.appendChild(canvas);

      var context = canvas.getContext("2d");
      context.save();

      // Firefox needs some offset tweaking
      var ffOffset = /WebKit/.test(navigator.appVersion) ? 0 : -1;

      // mirror and draw image
      context.translate(0,reflectionHeight*2+ffOffset);
      context.scale(1,-1);  // mirroring along x-axis
      context.drawImage(element, 0, element.height-reflectionHeight, reflectionWidth, reflectionHeight, 0, reflectionHeight, reflectionWidth, reflectionHeight);

      // create fading gradient
      var gradient = context.createLinearGradient(0, reflectionHeight, 0, 2*reflectionHeight);
      gradient.addColorStop(0, "rgba(255, 255, 255, 1)"); // black
      gradient.addColorStop(1, "rgba(255, 255, 255, "+(1-options.opacity)+")");
      context.globalCompositeOperation = "destination-out";
      context.fillStyle = gradient;

      if (/WebKit/.test(navigator.appVersion))
        context.fill();
      else
        context.fillRect(0, reflectionHeight+ffOffset, reflectionWidth, 2*reflectionHeight);

      context.restore();
    }
  }
}
</pre>
<p>Again, feel free to use the code as you like and/or drop me a comment. Please note that <code>reflection.js</code> is published under a <a title="Wikipedia: MIT License" href="http://en.wikipedia.org/wiki/MIT_License">MIT-style license</a>, which I thereby adopt for my code: MIT-licensed it is.</p>
<p>Yes, in the meantime <code>reflection.js</code> has evolved to version 1.5, fixing the bugs I also had fixed and more. So my code is not even worth a bug report. I really have some bad timing&hellip;
</p>
]]></content:encoded>
			<wfw:commentRSS>http://julian.dreissig.net/blog/another-reflector/feed/</wfw:commentRSS>
		</item>
		<item>
		<title>Faster reflecions</title>
		<link>http://julian.dreissig.net/blog/faster-reflecions</link>
		<comments>http://julian.dreissig.net/blog/faster-reflecions#comments</comments>
		<pubDate>Wed, 17 May 2006 01:06:12 +0000</pubDate>
		<dc:creator>Green</dc:creator>
		
	<category>Javascript</category>
		<guid isPermaLink="false">http://julian.dreissig.net/?p=4</guid>
		<description><![CDATA[Recently, Thomas Fuchs came up with a nice prototype/scriptaculous-based piece of code, the Reflector, which renders shiny image reflections in the browser.
However, it&#8217;s performance so far is a bit weak. It is a proof of concept and Thomas himself calls it &#8220;not really meant for production use yet&#8221;. In the following you find an (speedwise) [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, <a title="Thomas Fuchs' Blog" href="http://mir.aculo.us">Thomas Fuchs</a> <a title="&ldquo;Like reflections? Try the Reflector&rdquo;" href="http://mir.aculo.us/articles/2006/04/27/like-reflections-try-the-reflector">came up</a> with a nice prototype/scriptaculous-based <a title="scriptaculous Reflector demo" href="http://mir.aculo.us/stuff/reflector/reflector.html">piece of code, the <em>Reflector</em></a>, which renders shiny image reflections in the browser.</p>
<p>However, it&#8217;s performance so far is a bit weak. It is a proof of concept and Thomas himself calls it &ldquo;not really meant for production use yet&rdquo;. In the following you find an (speedwise) improved version, which boosts rendering time by a factor of 2&ndash;3.<br />
<a title="Reflector boosted demo page" href="http://dreissig.net/Reflector/reflector_boosted.html">Demo and comparison page</a><a id="more-4"></a></p>
<p>In Thomas&#8217; original code the reflected image consists of a stack of <code>div</code>s, each of one pixel height and containing a shifted copy of the original image. The code loops over the rows of the image, creating and attaching one corresponding reflection row <code>div</code> at each cycle.</p>
<p>So, changes have been made as follows:</p>
<ul>
<li>the reflected image is constructed out of <code>div</code>s with (shifted) background images, reducing DOM complexity</li>
<li>the constructed <code>div</code>s are attached to the DOM only after all <code>div</code>s have been created, thus avoiding unnecessary updates of the browser view</li>
<li>added a <code>fade</code> option, which determines the fading behaviour. By default it&#8217;s set to <code>1</code>, that is, a linear fade. A quadratic behaviour (<code>fade:2</code>) seems to look more natural (idea by jakdak), try it out and judge yourself.<br />
Setting <code>fade</code> to zero disables the fading.</li>
</ul>
<p>Tested with Safari, Firefox and IE (6.0). The scriptaculous setOpacity()-function seems not to work in Opera, the reflected image is not fading.</p>
<p>Feel free to use this code as you like, comments are very much appreciated.</p>
<pre>
var Reflector = {
  reflect: function(element) {
    element = $(element);
    options = $H({
      amount: 1/3,
      opacity: 1/3,
      fade: 1
    }).merge(arguments[1] || {});

    var p = element.parentNode, n = element.nextSibling;
    var d = 1.0/(element.height*options.amount);
    var f = document.createDocumentFragment();

    (element.height*options.amount).times( function(line) {
      var h = Builder.node('div',{
        style: 'height:1px; width:'+element.width+'px;'
              +'background-image:url('+element.src+');'
              +'background-position:0 '+(line+1)+'px;'
              +'overflow:hidden;'
      });
      $(h).setOpacity(Math.pow(1-d*line,options.fade)*options.opacity); // IE needs the $()
      f.appendChild(h);
    });

    // update the view now
    p.insertBefore(f,n);
  }
}
</pre>
<p>To use the Reflector you could insert something like this into your page:<br />
<code>Event.observe(window,'load', function(){Reflector.reflect('myImage');});</code>.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://julian.dreissig.net/blog/faster-reflecions/feed/</wfw:commentRSS>
		</item>
	</channel>
</rss>
