HTML 5 & Silverlight 5 - Eternal Coding - HTML5 / JavaScript / 3D development - Site Home - MSDN Blogs

HTML 5 & Silverlight 5


 

HTML 5 & Silverlight 5

  • Comments 27

This post is a translation of http://blogs.msdn.com/b/eternalcoding/archive/2011/06/06/fr-html-5-vs-silverlight-5.aspx.

SVSH

Philosophy

The goal of this paper is to present an objective comparison between Silverlight 5 and HTML 5 (with: JavaScript / ECMAScript 5 + CSS3 + any required additional frameworks and APIs). We will only focus on some features: covering these technologies entirely would require a whole book.
The main idea is to provide a guide to help you choose a technology as part of a planned project.
All decisions elements could not be presented here of course. You should take this document as a help to decide rather than as an absolute truth.

In each chapter we will focus on functionalities but also on ease of implementation and performance. The goal here is not to study in detail the features of HTML 5 or Silverlight 5.

Sample source code is available here.

To install Silverlight 5 beta you can go here.

HTML vs XAML

The two competitors are tied on the philosophy as they are both based on a markup language (HTML and XAML). They also both make extensive use of attributes.

Extensibility

Silverlight 5 allows you to add custom attributes to existing tags via attached properties. It is also feasible in HTML 5, but through the use of an inelegant hack (if HTML 5 does not recognize a tag or an attribute, it will just ignore it. Javascript can then process this information to add the required behavior). An implementation example of this usage is the project KnockOut.

On top of that, Silverlight has the Markup Extensions that add behavior to existing attributes (including Binding or even custom behaviors). Moreover, the list of tags is not fixed since it is possible to develop ones own controls providing a real advantage in the industrialization of a Silverlight solution.

DOM access

In Silverlight, each tag can be accessed directly from the code behind using association by name (x: Name). In HTML 5, it is possible to do the same with the attribute 'id' but only in certain browsers. We must therefore go through Javascript’s location services by id, which slightly penalizes ease of development:

  1. var toto = document.getElementById('toto');
  2. toto.style.visibility = 'hidden';

Regarding the traversing of logic trees, Silverlight and HTML provide equivalent related services.
It is however worth noting that HTML 5 offers a query tool for its DOM named Selectors API. This enables very efficient search across the objects on the page using selection queries:

  1. var alerts = document.querySelectorAll("p.warning, p.error");

In this example, we ask the API to return the list of paragraphs whose class is "warning" or "error". You can also query for IDs, types and many other criteria.

Code/Tags Separation

Silverlight offers a clear separation between markup and code enabled by Visual Studio and partial classes.

In Javascript, it is possible to leave the code in the html page or use the script tag to outsource the code:

  1. <script type="text/javascript" src="canvas.js"></script>

Both competitors thus allow for separation of the design part and the development part, helping worth integration of designers in the project.

Tools

The tooling is an easy fight for Silverlight because Notepad is no match for Visual Studio. Silverlight will indeed benefit from the full power of Microsoft Visual Studio and Microsoft Blend where HTML 5 (for now) virtually has no business tool.

With Blend it is easy to design XAML for Silverlight. It is also easy to debug and to have access to all services (syntax highlights, Intellisense, etc.) with Visual Studio. Not to mention profilers and simple solutions development with drag and drop.

The main tools available today for HTML 5 are browsers development toolbars (F12). They will allow debugging or profiling of your code inside the browser. The result is quite good, but far from the integration and the comfort of Visual Studio.

That will obviously change but for now the productivity champion is Silverlight.

Languages

Development

Silverlight is based on C # or Visual Basic which are strongly typed languages with JIT (Just in Time) compilation. Javascript is an interpreted dynamic language (although it can be compiled on the fly in some browsers). Those are definitely two different approaches.

The absence of compilation can results in late discovery of syntax errors, for example.

Moreover it is more difficult to debug a dynamic language which accepts everything (especially errors). With a strongly typed language, it is not possible (at least, it is hard) to mess up an assignment. With Javascript on the contrary, it is possible to put a table in a variable and two lines below assign an integer to it. Similarly if you make a mistake in an assignment writing for example myobject.prop = 1 and if the property ‘prop’ does not exists, Javascript as a dynamic language will create the property instead of raising an error. This greatly complicates debugging. But it also greatly increases the power of the language and its capabilities. Besides, the new versions of C # have made a step towards the dynamic world with lambdas expressions and other dynamic objects (dynamic).

We don’t want here to criticize the dynamic languages ​​or static languages. It is just important to understand the implications of both.

Performances

The main question though is of course in performance.

So let's take a simple example: we will calculate a million times a transaction involving the manipulation of strings and mathematical calculation.

We look then the time spent executing our code:

Javascript

Silverlight 5

Get Microsoft Silverlight

For Javascript:

  1. <p id='result'>
  2. </p>
  3. <script language="javascript">
  4.     var start = (new Date).getTime();
  5.  
  6.     var sum = 0;
  7.  
  8.     for (var index = 0; index < 1000000; index++) {
  9.         sum += Math.sqrt(("coucou" + index).toLowerCase().length);
  10.     }
  11.  
  12.     var diff = (new Date).getTime() - start;
  13.  
  14.     var result = document.getElementById('result');
  15.  
  16.     result.innerText = sum + ' ' + diff + ' ms';
  17. </script>

For Silverlight 5:

  1. DateTime start = DateTime.Now;
  2.  
  3. double sum = 0;
  4.  
  5. for (var index = 0; index < 1000000; index++)
  6. {
  7.     sum += Math.Sqrt(("coucou" + index).ToLower().Length);
  8. }
  9.  
  10. DateTime end = DateTime.Now;
  11.  
  12. result.Text = string.Format("{0} : {1} ms", sum, end.Subtract(start).TotalMilliseconds);

The result on my computer is:

System

Time spent

Silverlight 5

540 ms

Chrome 12

230 ms

IE 10 PP1

402 ms

IE 9

402 ms

Firefox 4

712 ms

Opera 11

290 ms

Safari 5

505 ms


We can see that HTML 5 performance is comparable to Silverlight. Obviously, based on your browser, your mileage may vary and it is obvious that the JavaScript runtime performance will improve in the future. However, we can already see that some browsers are able to do better than Silverlight. I already know that this result will cause an outcry but think about it : the modern Javascript runtimes can compile the code in the same way as the .Net JIT do. And if you don’t want to be convinced that managed code and Javascript can run as fast, you should consider that benchmarks (and especially this one) are not reliable Sourire.

SVG vs Shapes

Silverlight 5 and HTML 5 both offer the possibility of using vector graphics. A vector drawing is composed of geometric shapes unlike bitmaps whhich work with pixels.
SVG (Scalable Vector Graphics) is the technology for vector graphics in HTML 5. It has the following basic items:

  • Rectangle
  • Circle
  • Ellipse
  • Line
  • Polyline
  • Polygon
  • Path (with control system: MoveTo, LineTo, …)

Silverlight uses the classes inherited from the base class Shape to define the basic geometric shapes:

  • Rectangle
  • Ellipse
  • Line
  • Polyline
  • Polygon
  • Path (with control system: MoveTo, LineTo, …)

As we can see, in terms of options it is a draw. The two systems provide a very similar transformation system based on matrices. We will look at performance to try to differentiate our competitors. To do this we will develop a small application that will handle circles (or rounded ellipses) and paths (which we will build out of two Bezier curves).

HTML 5

Silverlight 5

 

Launch

Get Microsoft Silverlight

For HTML 5:

HTML 5
  1. <!DOCTYPE html>
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. </head>
  5. <body>
  6.     <p id="svgPerf">
  7.     </p>
  8.     <p>
  9.         <p id='launchSVG'
  10.         style="width: 70px; height: 30px; cursor: pointer; text-decoration: underline;">
  11.             Launch
  12.         </p>
  13.     </p>
  14.     <svg width="400" height="400" id="svgRoot" xmlns="http://www.w3.org/2000/svg">
  15.         <defs>
  16.             <clippath id="c1_1">         
  17.                 <rect x="0" y="0" width="400" height="400"/>
  18.             </clippath>
  19.         </defs>   
  20.         <g id="group" clip-path="url(#c1_1)">
  21.             <path id="svgPath" d="M0 0 L400 0 L400 200 C 350 150 250 150 200 200 C 150 250 50 250 0 200 Z" style="fill:#4444FF;stroke:#4444FF;stroke-width:2" />
  22.         </g>
  23.     </svg>    
  24.     <script type="text/javascript" src="svg.js"></script>
  25.   </body>
  26. </html>
Javascript
  1. var alpha = 0;
  2. var particles = [];
  3. var radius = 20;
  4.  
  5. function Particle() {
  6.     var x = 400 * Math.random();
  7.     var y = 400 + radius;
  8.     var velocity = 4 * Math.random() + 0.5;
  9.     var opacity = 1.0;
  10.  
  11.     // Create visual element for the particle
  12.     var domNode = document.createElementNS("http://www.w3.org/2000/svg", "circle");
  13.     var group = document.getElementById('group');
  14.     group.appendChild(domNode);
  15.  
  16.     // Set initial position to middle of screen
  17.     domNode.setAttribute("cx", x + radius);
  18.     domNode.setAttribute("cy", y);
  19.     domNode.setAttribute("r", radius);
  20.  
  21.     // Set colour of element
  22.     var chars = "0123456789abcdef";
  23.     var color = "#";
  24.     for (var i = 0; i < 2; i++) {
  25.         var rnd = Math.floor(16 * Math.random());
  26.         color += chars.charAt(rnd);
  27.     }
  28.  
  29.     color += "0000";
  30.  
  31.     domNode.setAttribute("fill", color);
  32.  
  33.     function draw() {
  34.         y -= velocity;
  35.  
  36.         if (y < -radius) {
  37.             x = 400 * Math.random();
  38.             y = 400 + radius;
  39.             velocity = 4 * Math.random() + 0.5;
  40.             domNode.setAttribute("cx", x + radius);
  41.         }
  42.  
  43.         opacity = y / 400.0;
  44.  
  45.         domNode.setAttribute("opacity", opacity);
  46.         domNode.setAttribute("cy", y);
  47.     }
  48.  
  49.     return {
  50.         draw: draw
  51.     }
  52. }
  53.  
  54. var previous = [];
  55.  
  56. function computeFPS() {
  57.     // FPS
  58.     if (previous.length > 60) {
  59.         previous.splice(0, 1);
  60.     }
  61.     var start = (new Date).getTime();
  62.     previous.push(start);
  63.     var sum = 0;
  64.  
  65.     for (var index = 0; index < previous.length - 1; index++) {
  66.         sum += previous[index + 1] - previous[index];
  67.     }
  68.  
  69.     var diff = 1000.0 / (sum / previous.length);
  70.  
  71.     var result = document.querySelector('#svgPerf');
  72.  
  73.     result.innerHTML = diff.toFixed() + ' fps';
  74. }
  75.  
  76. function animateSVG() {
  77.     computeFPS();
  78.  
  79.     // SVG
  80.     var h1 = (200 + 20 * Math.cos(alpha)).toFixed();
  81.     var h2 = (200 - 20 * Math.cos(alpha)).toFixed();
  82.  
  83.     svgPath.setAttribute("d", "M0 0 L400 0 L400 200 C 350 " + h2 + " 250 " + h2 + " 200 200 C 150 " + h1 + " 50 " + h1 + " 0 200 Z");
  84.  
  85.     for (var particle in particles) {
  86.         particles[particle].draw();
  87.     }
  88.  
  89.     alpha += 0.05;
  90. }
  91.  
  92. var intervalID;
  93.  
  94. function stopSVG() {
  95.     launchSVG.innerHTML = "Launch";
  96.     window.clearInterval(intervalID);
  97.     launchSVG.onclick = startSVG;
  98.     previous = [];
  99. }
  100.  
  101. function startSVG() {
  102.     launchSVG.innerHTML = "Stop";
  103.     launchSVG.onclick = stopSVG;
  104.     for (var i = 0; i < 100; i++) {
  105.         particles.push(new Particle());
  106.     }
  107.  
  108.     intervalID = window.setInterval("animateSVG()", 17);
  109. }
  110.  
  111. var launchSVG = document.getElementById('launchSVG');
  112. var svgPath = document.getElementById('svgPath');
  113. launchSVG.onclick = startSVG;

For Silverlight 5 :

XAML
  1. <Grid>
  2.      <Grid.RowDefinitions>
  3.          <RowDefinition Height="60"/>
  4.          <RowDefinition/>
  5.      </Grid.RowDefinitions>
  6.      <StackPanel>
  7.          <TextBlock x:Name="fps"/>
  8.         <Button Content="Launch" x:Name="launchButton" Click="launchButton_Click" Width="70" Height="30" HorizontalAlignment="Left"/>
  9.     </StackPanel>
  10.     <Grid x:Name="LayoutRoot" Grid.Row="1">
  11.         <Grid.Clip>
  12.             <RectangleGeometry Rect="0 0 400 400">
  13.             </RectangleGeometry>
  14.         </Grid.Clip>
  15.         <Path x:Name="path" Data="M0 0 L400 0 L400 200 C 350 150 250 150 200 200 C 150 250 50 250 0 200 Z" Fill="#4444FF" Stroke="#4444FF" StrokeThickness="2"/>
  16.     </Grid>
  17. </Grid>
MainPage.xaml.cs
  1. readonly List<Particle> particules = new List<Particle>();
  2. DispatcherTimer timer;
  3. double alpha;
  4. readonly List<DateTime> previous = new List<DateTime>();
  5.  
  6. private void Page_Loaded(object sender, RoutedEventArgs e)
  7. {
  8.     for (int index = 0; index < 100; index++)
  9.     {
  10.         particules.Add(new Particle(LayoutRoot));
  11.     }
  12.  
  13.     timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(10) };
  14.     timer.Tick += (s, evt) =>
  15.                       {
  16.                           previous.Add(DateTime.Now);
  17.  
  18.                           double sum = 0;
  19.  
  20.                           for (int index = 0; index < previous.Count - 1; index++)
  21.                           {
  22.                               sum += previous[index + 1].Subtract(previous[index]).TotalMilliseconds;
  23.                           }
  24.  
  25.                           sum /= previous.Count;
  26.  
  27.                           fps.Text = string.Format("{0:0} fps", 1000.0 / sum);
  28.  
  29.                           var h1 = (int)(200 + 20 * Math.Cos(alpha));
  30.                           var h2 = (int)(200 - 20 * Math.Cos(alpha));
  31.  
  32.                           PathFigure pathFigure = new PathFigure { StartPoint = new Point(0, 0) };
  33.                           pathFigure.Segments.Add(new LineSegment { Point = new Point(400, 0) });
  34.                           pathFigure.Segments.Add(new LineSegment { Point = new Point(400, 200) });
  35.                           pathFigure.Segments.Add(new BezierSegment { Point1 = new Point(350, h2), Point2 = new Point(250, h2), Point3 = new Point(200, 200) });
  36.                           pathFigure.Segments.Add(new BezierSegment { Point1 = new Point(150, h1), Point2 = new Point(50, h1), Point3 = new Point(0, 200) });
  37.                           pathFigure.IsClosed = true;
  38.  
  39.                           PathGeometry pathGeometry = new PathGeometry();
  40.                           pathGeometry.Figures.Add(pathFigure);
  41.  
  42.                           path.Data = pathGeometry;
  43.  
  44.                           foreach (var part in particules)
  45.                           {
  46.                               part.Update();
  47.                           }
  48.  
  49.                           alpha += 0.05;
  50.                       };
  51. }
Particle.cs
  1. public class Particle
  2. {
  3.     public double Velocity { get; set; }
  4.     public Ellipse Ellipse { get; set; }
  5.     readonly TranslateTransform translate;
  6.     static readonly Random random = new Random();
  7.  
  8.     const double Radius = 20;
  9.  
  10.     public Particle(Grid parent)
  11.     {
  12.         byte red = (byte)random.Next(256);
  13.         Ellipse = new Ellipse
  14.                       {
  15.                           Width = Radius * 2,
  16.                           Height = Radius * 2,
  17.                           Fill = new SolidColorBrush(new Color{A= 255, B = 0, G = 0, R = red})
  18.                       };
  19.  
  20.         translate = new TranslateTransform();
  21.  
  22.         Ellipse.RenderTransformOrigin = new Point(0.5, 0.5);
  23.         Ellipse.HorizontalAlignment = HorizontalAlignment.Left;
  24.         Ellipse.VerticalAlignment = VerticalAlignment.Top;
  25.  
  26.         Spawn();
  27.  
  28.         Ellipse.RenderTransform = translate;
  29.  
  30.         parent.Children.Add(Ellipse);
  31.     }
  32.  
  33.     void Spawn()
  34.     {
  35.         translate.X = 400 * random.NextDouble();
  36.         translate.Y = 400 + Radius;
  37.         Velocity = 4 * random.NextDouble() + 0.5;
  38.     }
  39.  
  40.     internal void Update()
  41.     {
  42.         translate.Y -= Velocity;
  43.  
  44.         if (translate.Y < -Radius)
  45.         {
  46.             Spawn();
  47.         }
  48.  
  49.         Ellipse.Opacity = translate.Y / 400.0;
  50.     }
  51. }

The result on my computer is:

System

FPS

Silverlight 5

63

Chrome 12

60

IE 10 PP1

50

IE 9

50

Firefox 4

50

Opera 11

Do not work

Safari 5

Do not work

This time it is impossible to differentiate the opponents. The Silverlight code may be cleaner and more pleasant to read but it is a very personal opinion that should not go in. So it's a draw.

Canvas vs WriteableBitmap

Silverlight 5 and HTML 5 both offer the opportunity to work on 2D surfaces at the pixel level directly. In HTML 5 this surface is called a canvas and we talk about WriteableBitmap in Silverlight 5.

Access to the pixels

The two surfaces are both capable of drawing basic shapes (like SVG / Shape) but mostly they allow direct access to their contents as RGBA (in HTML 5 we handle 4 integers per color) or ARGB (Silverlight handle 1 integer for each color with each element occupying 8 bits).
One can already note that the way to manipulate the pixels of Silverlight is more efficient since it only uses a single integer against four for HTML 5.
Again, the features are similar, we will again compare performance to name a winner. For this we will develop an effect that has been around since early technological demos on Amiga or Atari ST computers: the fire effect! It is achieved by applying a vertical blur (upward) while generating red color dots on the bottom of the image. In addition we generated flame under the mouse:

HTML 5

Silverlight 5

 

Launch

Canvas not supported :(
Get Microsoft Silverlight

For HTML 5:

HTML 5
  1. <p id="fpsCanvas">
  2. </p>
  3. <p>
  4.     <p id='launchCanvas' style="width: 70px; height: 30px; cursor: pointer; text-decoration: underline;">
  5.         Launch
  6.     </p>
  7. </p>
  8. <canvas id="canvas" width="300" height="200">
  9.     Canvas not supported :(
  10. </canvas>
Javascript
  1. var context;
  2. var canvasWidth;
  3. var canvasHeight;
  4. var blurSpeed = 0.04;
  5. var flamesCount = 50;
  6. var flamesWidth = 10;
  7. var launchCanvas;
  8.  
  9. function putPixel(x, y) {
  10.     var clipX = Math.max(0, x - 4);
  11.     var clipY = Math.max(0, y - 4);
  12.  
  13.     var imageData = context.getImageData(clipX, clipY, 8, 8);
  14.  
  15.     var pixels = imageData.data;
  16.  
  17.     for (var index = 0; index < pixels.length; index += 4) {
  18.         pixels[index] = 255;
  19.         pixels[index + 1] = 0;
  20.         pixels[index + 2] = 0;
  21.         pixels[index + 3] = 255;
  22.     }
  23.  
  24.     context.putImageData(imageData, x, y);
  25. }
  26.  
  27. var previous = [];
  28.  
  29. function computeFPSCanvas() {
  30.     // FPS
  31.     if (previous.length > 60) {
  32.         previous.splice(0, 1);
  33.     }
  34.     var start = (new Date).getTime();
  35.     previous.push(start);
  36.     var sum = 0;
  37.  
  38.     for (var index = 0; index < previous.length - 1; index++) {
  39.         sum += previous[index + 1] - previous[index];
  40.     }
  41.  
  42.     var diff = 1000.0 / (sum / previous.length);
  43.  
  44.     var fpsCanvas = document.getElementById('fpsCanvas');
  45.     fpsCanvas.innerHTML = diff.toFixed() + ' fps';
  46. }
  47.  
  48. function blur() {
  49.     computeFPSCanvas();
  50.  
  51.     var imageData = context.getImageData(0, 0, canvasWidth, canvasHeight);
  52.     var pixels = imageData.data;
  53.  
  54.     // Generate root flames
  55.     var line = (canvasHeight - 1) * canvasWidth;
  56.     for (var flameID = 0; flameID < flamesCount; flameID++) {
  57.  
  58.         var red = 150 + 95 * Math.random();
  59.         var green = 50 * Math.random();
  60.  
  61.         var x = Math.min(canvasWidth - flamesWidth, Math.random() * canvasWidth) | 0;
  62.  
  63.         for (var index = 0; index < flamesWidth; index++) {
  64.             var base = (x + index + line) * 4;
  65.             pixels[base] = red;
  66.             pixels[base + 1] = green;
  67.         }
  68.     }
  69.  
  70.     // Vertical blur
  71.     for (var x = 0; x < canvasWidth; x++) {
  72.         for (var y = 0; y < canvasHeight; y++) {
  73.  
  74.             var medR = 0;
  75.             var medG = 0;
  76.  
  77.             var samplesCount = 0;
  78.             for (var index = 0; index < 4; index++) {
  79.                 var scanY = y + index;
  80.  
  81.                 if (scanY >= canvasHeight)
  82.                     continue;
  83.  
  84.                 var linearPosition = (x + scanY * canvasWidth) * 4;
  85.                 medR += pixels[linearPosition];
  86.                 medG += pixels[linearPosition + 1];
  87.                 samplesCount += 1 + (1 - index / 4) * blurSpeed;
  88.             }
  89.  
  90.             medR /= samplesCount;
  91.             medG /= samplesCount;
  92.  
  93.             var base = (x + y * canvasWidth) * 4;
  94.             pixels[base] = medR;
  95.             pixels[base + 1] = medG;
  96.         }
  97.     }
  98.  
  99.     context.putImageData(imageData, 0, 0);
  100. }
  101.  
  102. function onMouseMove(e) {
  103.     putPixel(e.offsetX, e.offsetY);
  104. }
  105.  
  106. var intervalCanvasID;
  107.  
  108. function stopCanvas() {
  109.     launchCanvas.innerHTML = "Launch";
  110.     window.clearInterval(intervalCanvasID);
  111.     launchCanvas.onclick = startCanvas;
  112.     previous = [];
  113. }
  114.  
  115. function startCanvas() {
  116.     launchCanvas.innerHTML = "Stop";
  117.     launchCanvas.onclick = stopCanvas;
  118.  
  119.     intervalCanvasID = window.setInterval("blur()", 17);
  120. }
  121.  
  122. var canvas = document.getElementById('canvas');
  123.  
  124. context = canvas.getContext('2d');
  125.  
  126. canvas.onmousemove = onMouseMove;
  127. canvasWidth = canvas.width;
  128. canvasHeight = canvas.height;
  129.  
  130. context.fillStyle = "rgb(0,0,0)";
  131. context.fillRect(0, 0, canvasWidth, canvasHeight);
  132.  
  133. launchCanvas = document.getElementById('launchCanvas');
  134. launchCanvas.onclick = startCanvas;

For Silverlight 5:

XAML
  1. <Grid>
  2.     <Grid.RowDefinitions>
  3.         <RowDefinition Height="60"/>
  4.         <RowDefinition/>
  5.     </Grid.RowDefinitions>
  6.     <StackPanel>
  7.         <TextBlock x:Name="fps"/>
  8.         <Button Content="Launch" x:Name="launchButton" Click="launchButton_Click" Width="70" Height="30" HorizontalAlignment="Left"/>
  9.     </StackPanel>
  10.     <Image x:Name="renderImage" MouseMove="renderImage_MouseMove" Grid.Row="1" Stretch="Fill"/>
  11. </Grid>
MainPage.xaml.cs
  1. DispatcherTimer timer;
  2. readonly List<DateTime> previous = new List<DateTime>();
  3. WriteableBitmap writeableBitmap;
  4. const float blurSpeed = 0.04f;
  5. const int flamesWidth = 10;
  6. const int flamesCount = 50;
  7. readonly Random random = new Random();
  8.  
  9. public MainPage()
  10. {
  11.     InitializeComponent();
  12. }
  13.  
  14. private void UserControl_Loaded(object sender, RoutedEventArgs e)
  15. {
  16.     writeableBitmap = new WriteableBitmap(300, 200);
  17.  
  18.     writeableBitmap.Render(new Rectangle { Width = 300, Height = 200, Fill = new SolidColorBrush(Colors.Black) }, null);
  19.  
  20.     renderImage.Source = writeableBitmap;
  21.  
  22.     writeableBitmap.Invalidate();
  23.  
  24.  
  25.     timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(10) };
  26.     timer.Tick += (s, evt) =>
  27.     {
  28.         // FPS
  29.         previous.Add(DateTime.Now);
  30.  
  31.         double sum = 0;
  32.  
  33.         for (int index = 0; index < previous.Count - 1; index++)
  34.         {
  35.             sum += previous[index + 1].Subtract(previous[index]).TotalMilliseconds;
  36.         }
  37.  
  38.         sum /= previous.Count;
  39.  
  40.         fps.Text = string.Format("{0:0} fps", 1000.0 / sum);
  41.  
  42.         // Flames
  43.         var line = (writeableBitmap.PixelHeight - 1) * writeableBitmap.PixelWidth;
  44.         for (var flameID = 0; flameID < flamesCount; flameID++)
  45.         {
  46.             var red = 150 + random.Next(96);
  47.             var green = random.Next(51);
  48.  
  49.             var x = Math.Min(writeableBitmap.PixelWidth - flamesWidth, random.Next(writeableBitmap.PixelWidth));
  50.  
  51.             for (var index = 0; index < flamesWidth; index++)
  52.             {
  53.                 var basePosition = (x + index + line);
  54.                 writeableBitmap.Pixels[basePosition] = GetColor(red, green, 0);
  55.             }
  56.         }
  57.  
  58.         // Vertical blur
  59.         for (var x = 0; x < writeableBitmap.PixelWidth; x++)
  60.         {
  61.             for (var y = 0; y < writeableBitmap.PixelHeight; y++)
  62.             {
  63.                 var medR = 0;
  64.                 var medG = 0;
  65.  
  66.                 float samplesCount = 0;
  67.                 for (var index = 0; index < 4; index++)
  68.                 {
  69.                     var scanY = y + index;
  70.  
  71.                     if (scanY >= writeableBitmap.PixelHeight)
  72.                         continue;
  73.  
  74.                     var linearPosition = (x + scanY * writeableBitmap.PixelWidth);
  75.                     int red, green;
  76.  
  77.                     ExtractColor(writeableBitmap.Pixels[linearPosition], out red, out green);
  78.  
  79.                     medR += red;
  80.                     medG += green;
  81.                     samplesCount += 1 + (1 - index / 4) * blurSpeed;
  82.                 }
  83.  
  84.                 medR = (int)(medR / samplesCount);
  85.                 medG = (int)(medG / samplesCount);
  86.  
  87.                 var basePosition = (x + y * writeableBitmap.PixelWidth);
  88.                 writeableBitmap.Pixels[basePosition] = GetColor(medR, medG, 0);
  89.             }
  90.         }
  91.         writeableBitmap.Invalidate();
  92.     };
  93. }
  94.  
  95. void launchButton_Click(object sender, RoutedEventArgs e)
  96. {
  97.     if (launchButton.Content.ToString() == "Launch")
  98.     {
  99.         previous.Clear();
  100.         timer.Start();
  101.         launchButton.Content = "Stop";
  102.     }
  103.     else
  104.     {
  105.         launchButton.Content = "Launch";
  106.         timer.Stop();
  107.     }
  108. }
  109.  
  110. static int GetColor(int red, int green, int blue)
  111. {
  112.     return (255 << 24) + (red << 16) + (green << 8) + blue;
  113. }
  114.  
  115. static void ExtractColor(int value, out int red, out int green)
  116. {
  117.     red = ((value & 0x00FF0000) >> 16);
  118.     green = ((value & 0x0000FF00) >> 8);
  119. }
  120.  
  121.  
  122. void PutPixel(int x, int y)
  123. {
  124.     int red = GetColor(255, 0, 0);
  125.  
  126.     for (int clipX = Math.Max(0, x - 4); clipX <= x + 4 && clipX < writeableBitmap.PixelWidth; clipX++)
  127.     {
  128.         for (int clipY = Math.Max(0, y - 4); clipY <= y + 4 && clipY < writeableBitmap.PixelHeight; clipY++)
  129.         {
  130.             var basePosition = (clipX + clipY * writeableBitmap.PixelWidth);
  131.  
  132.             writeableBitmap.Pixels[basePosition] = red;
  133.         }
  134.     }
  135. }
  136.  
  137. private void renderImage_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
  138. {
  139.     Point location = e.GetPosition(renderImage);
  140.  
  141.     PutPixel((int)location.X, (int)location.Y);
  142.  
  143.     writeableBitmap.Invalidate();
  144. }

The result on my computer is

System

FPS

Silverlight 5

80

Chrome 12

30

IE 10 PP1

33

IE 9

33

Firefox 4

60

Opera 11

47

Safari 5

30 (very jaggy)

Silverlight gets the best result thanks to its pixel storage system. However, due to their architecture, browsers can not overcome the 60 frames per second barrier. We can therefore conclude that we have a draw here (as at least one browser gets the same performance level as Silverlight).

Drawing shapes

To be complete, however we must also test the performance of the shape drawing mechanism. We'll play the demo used for the SVG vs Shapes comparison but this time we will drawing the shapes in our 2D surfaces:

HTML 5

Silverlight

 

Launch

Canvas not supported :(
Get Microsoft Silverlight

For HTML 5:

  1. var shapescontext;
  2. var launchShapesCanvas;
  3. var radius = 20;
  4. var shapescanvas;
  5.  
  6. var shapesPrevious = [];
  7.  
  8. var shapesparticles = [];
  9.  
  10. var shapesAlpha = 0;
  11.  
  12. function computeFPSShapesCanvas() {
  13.     // FPS
  14.     if (shapesPrevious.length > 60) {
  15.         shapesPrevious.splice(0, 1);
  16.     }
  17.     var start = (new Date).getTime();
  18.     shapesPrevious.push(start);
  19.     var sum = 0;
  20.  
  21.     for (var index = 0; index < shapesPrevious.length - 1; index++) {
  22.         sum += shapesPrevious[index + 1] - shapesPrevious[index];
  23.     }
  24.  
  25.     var diff = 1000.0 / (sum / shapesPrevious.length);
  26.  
  27.     var fpsCanvas = document.getElementById('fpsShapesCanvas');
  28.     fpsCanvas.innerHTML = diff.toFixed() + ' fps';
  29. }
  30.  
  31. function animateShapesCanvas() {
  32.     computeFPSShapesCanvas();
  33.  
  34.     // Clear
  35.     shapescontext.fillStyle = "rgb(255,255,255)";
  36.     shapescontext.fillRect(0, 0, shapescanvas.width, shapescanvas.height);
  37.  
  38.     // Path
  39.     var h1 = (200 + 20 * Math.cos(shapesAlpha)).toFixed();
  40.     var h2 = (200 - 20 * Math.cos(shapesAlpha)).toFixed();
  41.     shapesAlpha += 0.05;
  42.  
  43.     shapescontext.beginPath();
  44.     shapescontext.moveTo(0, 0);
  45.     shapescontext.lineTo(400, 0);
  46.     shapescontext.lineTo(400, 200);
  47.     shapescontext.bezierCurveTo(350, h2, 250, h2, 200, 200);
  48.     shapescontext.bezierCurveTo(150, h1, 50, h1, 0, 200);
  49.     shapescontext.closePath();
  50.  
  51.     shapescontext.fillStyle = "rgb(0, 0, 255)";
  52.     shapescontext.fill();
  53.  
  54.     // Particles
  55.     shapescontext.save();
  56.     for (var particle in shapesparticles) {
  57.        shapesparticles[particle].draw();
  58.    }
  59.    shapescontext.restore();
  60.  
  61. }
  62.  
  63. var intervalShapesCanvasID;
  64.  
  65. function stopShapesCanvas() {
  66.     launchShapesCanvas.innerHTML = "Launch";
  67.     window.clearInterval(intervalShapesCanvasID);
  68.     launchShapesCanvas.onclick = startShapesCanvas;
  69.     shapesPrevious = [];
  70. }
  71.  
  72. function startShapesCanvas() {
  73.     launchShapesCanvas.innerHTML = "Stop";
  74.     launchShapesCanvas.onclick = stopShapesCanvas;
  75.  
  76.     intervalShapesCanvasID = window.setInterval("animateShapesCanvas()", 17);
  77. }
  78.  
  79. function ShapeParticle() {
  80.     var x = 400 * Math.random();
  81.     var y = 400 + radius;
  82.     var velocity = 4 * Math.random() + 0.5;
  83.     var opacity = 1.0;
  84.  
  85.     // Set colour of element
  86.     var color = "rgb(" + Math.floor(255 * Math.random()) + ", 0, 0)";
  87.  
  88.     function draw() {
  89.         y -= velocity;
  90.  
  91.         if (y < -radius) {
  92.             x = 400 * Math.random();
  93.             y = 400 + radius;
  94.             velocity = 4 * Math.random() + 0.5;
  95.             return;
  96.         }
  97.  
  98.         opacity = Math.max(0, y / 400.0);
  99.  
  100.         shapescontext.globalAlpha = opacity;
  101.         shapescontext.beginPath();
  102.         shapescontext.arc(x, y, radius, 0, 2 * Math.PI, false);
  103.         shapescontext.closePath();
  104.  
  105.         shapescontext.fillStyle = color;
  106.         shapescontext.fill();
  107.     }
  108.  
  109.     return {
  110.         draw: draw
  111.     }
  112. }
  113.  
  114. shapescanvas = document.getElementById('shapescanvas');
  115.  
  116. shapescontext = shapescanvas.getContext('2d');
  117.  
  118. launchShapesCanvas = document.getElementById('launchShapesCanvas');
  119. launchShapesCanvas.onclick = startShapesCanvas;
  120.  
  121. for (var i = 0; i < 100; i++) {
  122.     shapesparticles.push(new ShapeParticle());
  123. }

For Silverlight:

Particule.cs
  1. public class Particle
  2. {
  3.     public double Velocity { get; set; }
  4.     public Ellipse Ellipse { get; set; }
  5.     readonly TranslateTransform translate;
  6.     static readonly Random random = new Random();
  7.     readonly WriteableBitmap root;
  8.  
  9.     const double Radius = 20;
  10.  
  11.     public Particle(WriteableBitmap root)
  12.     {
  13.         this.root = root;
  14.         byte red = (byte)random.Next(256);
  15.         Ellipse = new Ellipse
  16.                       {
  17.                           Width = Radius * 2,
  18.                           Height = Radius * 2,
  19.                           Fill = new SolidColorBrush(new Color{A= 255, B = 0, G = 0, R = red})
  20.                       };
  21.  
  22.         translate = new TranslateTransform();
  23.  
  24.         Ellipse.RenderTransformOrigin = new Point(0.5, 0.5);
  25.         Ellipse.HorizontalAlignment = HorizontalAlignment.Left;
  26.         Ellipse.VerticalAlignment = VerticalAlignment.Top;
  27.  
  28.         Spawn();
  29.     }
  30.  
  31.     void Spawn()
  32.     {
  33.         translate.X = 400 * random.NextDouble();
  34.         translate.Y = 400 + Radius;
  35.         Velocity = 4 * random.NextDouble() + 0.5;
  36.     }
  37.  
  38.     internal void Update()
  39.     {
  40.         translate.Y -= Velocity;
  41.  
  42.         if (translate.Y < -Radius)
  43.         {
  44.             Spawn();
  45.         }
  46.  
  47.         Ellipse.Opacity = translate.Y / 400.0;
  48.  
  49.         root.Render(Ellipse, translate);
  50.     }
MainPage.xaml.cs
  1. void UserControl_Loaded(object sender, RoutedEventArgs e)
  2. {
  3.     writeableBitmap = new WriteableBitmap(400, 400);
  4.     renderImage.Source = writeableBitmap;
  5.  
  6.     path = new Path();
  7.     path.Fill = new SolidColorBrush(Colors.Blue);
  8.  
  9.     for (int index = 0; index < 100; index++)
  10.     {
  11.         particules.Add(new Particle(writeableBitmap));
  12.     }
  13.  
  14.  
  15.     timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(10) };
  16.     timer.Tick += (s, evt) =>
  17.     {
  18.         // FPS
  19.         previous.Add(DateTime.Now);
  20.  
  21.         double sum = 0;
  22.  
  23.         for (int index = 0; index < previous.Count - 1; index++)
  24.         {
  25.             sum += previous[index + 1].Subtract(previous[index]).TotalMilliseconds;
  26.         }
  27.  
  28.         sum /= previous.Count;
  29.  
  30.         fps.Text = string.Format("{0:0} fps", 1000.0 / sum);
  31.  
  32.         // Render
  33.         writeableBitmap.Render(new Rectangle { Width = 400, Height = 400, Fill = new SolidColorBrush(Colors.White) }, null);
  34.  
  35.         var h1 = (int)(200 + 20 * Math.Cos(alpha));
  36.         var h2 = (int)(200 - 20 * Math.Cos(alpha));
  37.  
  38.         PathFigure pathFigure = new PathFigure { StartPoint = new Point(0, 0) };
  39.         pathFigure.Segments.Add(new LineSegment { Point = new Point(400, 0) });
  40.         pathFigure.Segments.Add(new LineSegment { Point = new Point(400, 200) });
  41.         pathFigure.Segments.Add(new BezierSegment { Point1 = new Point(350, h2), Point2 = new Point(250, h2), Point3 = new Point(200, 200) });
  42.         pathFigure.Segments.Add(new BezierSegment { Point1 = new Point(150, h1), Point2 = new Point(50, h1), Point3 = new Point(0, 200) });
  43.         pathFigure.IsClosed = true;
  44.  
  45.         PathGeometry pathGeometry = new PathGeometry();
  46.         pathGeometry.Figures.Add(pathFigure);
  47.  
  48.         path.Data = pathGeometry;
  49.  
  50.         writeableBitmap.Render(path, null);
  51.  
  52.         foreach (var part in particules)
  53.         {
  54.             part.Update();
  55.         }
  56.  
  57.         alpha += 0.05;
  58.         writeableBitmap.Invalidate();
  59.     };
  60. }

The result on my computer is :

System

FPS

Silverlight 5

60

Chrome 12

60

IE 10 PP1

60

IE 9

60

Firefox 4

60

Opera 11

60

Safari 5

60

Nothing more to say, both in terms of performance and features both competitors are at the same level.

Brushes

Brushes are used to fill interface elements with a color, gradient or a pattern.
In HTML5, it is possible to use them with CSS or directly in a canvas or SVG. It is also possible to use images or videos as brushes.
In Silverlight 5, we have the same concept with the added ability of using other controls rendered as a base texture (VisualBrush).

Here is an example:

HTML 5

Silverlight 5

Full color :

Radial gradient :

Linear gradient :

Get Microsoft Silverlight

For HTML 5:

  1. <p>Couleur pleine :</p>
  2. <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  3.     <rect x="0" y="0" width="100" height="100" fill="#ff00ff" />
  4. </svg>
  5. <p>Radial gradient :</p>
  6. <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  7.     <radialGradient id="radial" gradientUnits="userSpaceOnUse" cx="50%" cy="50%" r="50%">
  8.         <stop stop-color="#FFFFFF" offset="0"/>
  9.         <stop stop-color="#470A45" offset="1"/>
  10.     </radialGradient>
  11.     <rect x="0" y="0" width="100" height="100" fill="url(#radial)" />
  12. </svg>
  13. <p>Linear gradient :</p>
  14. <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
  15.     <linearGradient id="linear" gradientUnits="userSpaceOnUse">
  16.         <stop stop-color="#FFFFFF" offset="0"/>
  17.         <stop stop-color="#470A45" offset="1"/>
  18.     </linearGradient>
  19.     <rect x="0" y="0" width="100" height="100" fill="url(#linear)" />
  20. </svg>

For Silverlight :

  1. <StackPanel>
  2.     <TextBlock Text="Couleur pleine:" Margin="0,10"></TextBlock>
  3.     <Rectangle Width="100" Height="100" Fill="#ff00ff" HorizontalAlignment="Left"/>
  4.     <TextBlock Text="Radial gradient:" Margin="0,10"></TextBlock>
  5.     <Rectangle Width="100" Height="100" HorizontalAlignment="Left">
  6.         <Rectangle.Fill>
  7.             <RadialGradientBrush>
  8.                 <GradientStop Color="#FFFFFF" Offset="0"></GradientStop>
  9.                 <GradientStop Color="#470A45" Offset="1"></GradientStop>
  10.             </RadialGradientBrush>
  11.         </Rectangle.Fill>
  12.     </Rectangle>
  13.     <TextBlock Text="Linear gradient:" Margin="0,10"></TextBlock>
  14.     <Rectangle Width="100" Height="100" HorizontalAlignment="Left">
  15.         <Rectangle.Fill>
  16.             <LinearGradientBrush StartPoint="0, 0" EndPoint="1, 0">
  17.                 <GradientStop Color="#FFFFFF" Offset="0"></GradientStop>
  18.                 <GradientStop Color="#470A45" Offset="1"></GradientStop>
  19.             </LinearGradientBrush>
  20.         </Rectangle.Fill>
  21.     </Rectangle>
  22. </StackPanel>

For once the syntax is very similar. We can therefore consider it a draw.

Controls

In Silverlight 5, it is both possible to define ones own controls from scratch or by aggregation (UserControl and CustomControl). It is also possible to inherit from the basic controls or even modify the associated templates to modify their appearance. In brief, Silverlight is extremely powerful for dealing with user interface.

HTML 5 does not offer any integrated solution for creating controls except basic copy/pasting of code. This is a big minus for business projects looking at industrializing their developments. We are far from the plethora of controls that can be simply referenced in Silverlight.

Note that HTML 5 introduces the concept of validation checks (required, etc.) and drag'n'drop.

Layout

Layout management (layout of the GUI and customization) is very rich in Silverlight. It is possible to position objects:

  • In a grid with cell size in absolute, relative or even adaptable to the content
  • With vertical or horizontal stacking in a StackPanel
  • In a canvas that enables positioning through absolute coordinates
  • With the margins and alignments
  • With overflows exposed by the new control RichTexboxOverflow

This system may be extended to infinity by adding usercontrols which can define their own layout. A good example can be found in the Silverlight Toolkit, which adds for example a WrapPanel.

HTML5 also provides complete solutions for layout management:

  • Grids with <table> <td> <tr>
  • New system for placing and sizing grids: Alignment Grid CSS Level 3. You will find that this mechanism is almost exactly identical to that of Silverlight (With good reason, as it is a Microsoft proposed specification)
  • System integrated with CSS layout (absolute or relative placement, absolute or relative size, etc..)
  • New CSS3 Flexbox system for which you can see a demo right here (if your browser supports it). This specification allows management  of alignments and placement relative to boxes (yes that's exactly the same thing for XUL and it's not a coincidence Sourire)
  • CSS3 Multi-column layout which is a rendering system with multi-column (example here).
  • CSS3 Media Queries that define different layouts based on display sizes with an example here (besides Samuel Blanchard's had fun doing the same thing in Silverlight here).

Layout technologies in HTML5 are not well supported by all browsers (the always repeating story of standards under development) but based purely on functionality, this is a fairly even game since the two competitors are able to produce easily adaptable and scalable layouts.

Databinding

A key feature of Silverlight is the databinding that opens the door to design patterns such as MVVM (Model / View / ViewModel) that can implement effective and modern architectures.

The databinding also enable defining dynamic interfaces without any line of code.

In the land of HTML 5 there is nothing. This implies that HTML 5 is heading more towards the production of consumer websites where Silverlight 5 aims at business line type of applications.

To do databinding in HTML 5, we will necessarily go through Javascript code to manually assign values ​​to controls and subscribe to events to retrieve the changed data. Some libraries exist (for example, you can use jQuery or Knockout) but nothing as effective (in terms of implementation and performance) as Silverlight.

Threading : Web workers vs System.Threading

Silverlight 5 offers enhanced support for threading through the class System.Threading.Thread and even provides access to the thread pool.

I have even recently published an article on porting the Silverlight Task Parallel Library.

HTML5 has the concept of Web Workers, threads that are independent from the main thread (the one that displays and manipulates the DOM).

These workers are actually totally compartmentalized and so they communicate with the main thread via a messaging mechanism. This prevents having to worry about keeping critical sections on shared data since there is no shared data. Thus the workers can not access the DOM:

Main script
  1. var worker = new Worker("webworker.js");
  2.  
  3. worker.onmessage = function(e) {  
  4.     alert(e.data);
  5. };
  6.  
  7. worker.onerror = function (e) {
  8.     alert("Erreur: " + e.message);
  9. };
  10.  
  11. worker.postMessage("David");
Worker
  1. self.onmessage = function (e) {
  2.     self.postMessage(e.data.toUpperCase());
  3. }

Communication with Workers passes through strings, it is necessary to serialize objects to JSON which can be painful.

The standard is still evolving very rapidly and we cannot know what will be its final state. For example, it has recently adopted the concept of Shared Workers who can communicate with more scripts.

Here is an example of raytracing engine in Javascript using the workers (if your browser supports them): http://nerget.com/rayjs-mt/rayjs.html

For Silverlight, communication with other threads is done by calling methods and passing parameters (in fact, nothing special). There are many more tools to manage concurrency and timing such as ManualResetEvent, AutoResetEvent, Monitor, etc..

You will find below an example of code that uses Silverlight ManualResetEvent to control a thread. It also show the use of the Dispatcher allowing the thread to execute code on the thread of the interface:

  1. readonly ManualResetEvent evt = new ManualResetEvent(false);
  2. readonly string textToTransform;
  3.  
  4. public MainPage()
  5. {
  6.     InitializeComponent();
  7.  
  8.     Thread thread = new Thread(DoJob);
  9.  
  10.     textToTransform = textBlock.Text;
  11.     thread.Start();
  12. }
  13.  
  14. void DoJob()
  15. {
  16.     while (true)
  17.     {
  18.         string result = textToTransform.ToUpper();
  19.         Dispatcher.BeginInvoke(() => textBlock.Text = result);
  20.         evt.WaitOne();
  21.     }
  22. }

As we can see, Silverlight outperforms Web Workers on potential and tools (again, thanks to Visual Studio which provides several debugging tools) but also in terms of control over the threads. The addition of future technologies such as Async Framework will add even more power to Silverlight.

Obviously, the approach of Web workers (even if the standard is far from being done) is different from the conventional threading of Silverlight. It certainly helps to do simple threading but unfortunately it cannot cover all the needs of modern application development.

Animations

The Silverlight animation engine can easily manipulate control properties.

These manipulations are done seamlessly by an autonomous system that can manage events on simple properties (double, integer, etc..) or complex properties (color, thickness, etc..). These activities are done by a storyboard which handles timing for us.

  1. <Storyboard x:Key="monStoryboard">
  2.     <DoubleAnimation Duration="0:0:0.1" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="LayoutRoot">
  3.         <DoubleAnimation.EasingFunction>
  4.             <BackEase Amplitude="0.6" EasingMode="EaseInOut"/>
  5.         </DoubleAnimation.EasingFunction>
  6.     </DoubleAnimation>
  7. </Storyboard>

These animations can be created either in XAML or in code. As shown above, it is even possible to define functions to use non-linear animation.

In HTML5, it is possible to use the setInterval and setTimeout to animate (manually) DOM elements:

  1. function startCanvas() {
  2.     launchCanvas.innerHTML = "Stop";
  3.     launchCanvas.onclick = stopCanvas;
  4.  
  5.     intervalCanvasID = window.setInterval("blur()", 17);
  6. }

Here, no special support by the system. It is up to us to manage everything. But, obviously, anything is possible.

However a new technology has emerged (still poorly supported by browsers) to improve things: CSS Animations Module Level 3.
With this module, it is possible to animate the CSS styles with a very interesting statement:

  1. @keyframes 'anim01' {
  2.  
  3.     0% {
  4.       left: 100px;
  5.     }
  6.  
  7.     40% {
  8.       left: 150px;
  9.     }
  10.  
  11.     60% {
  12.       left: 75px;
  13.     }
  14.  
  15.     100% {
  16.       left: 100px;
  17.     }
  18.  
  19.   }

In this animation, we decided to animate the attribute "left" by labelling key points of the animation. The system will subsequently change the attribute value over time.

The assignment of this animation will be:

  1. div {
  2.     animation-name: 'anim01';
  3.     animation-duration: 5s;
  4.     animation-iteration-count: 10;
  5.   }

In Silverlight, it is possible to define functions to set the linearity (or not) of the animation.
In addition, HTML5 (actually CSS3) specification also includes CSS Transitions Module Level 3, which allows you to define animations on a transition, i.e. when an attribute receives a new value:

  1. div {
  2.     transition-property: opacity;
  3.     transition-duration: 2s;
  4.   }

In this example, when we change the opacity value, the system will gradually change the current value to the new value in 2 seconds. It is also possible to define how the animation will take place over the period (transition-timing-function).

In Silverlight, we also have a system to manage these transitions: VisualStateManager. The latter cannot define the animations when changing the value of a variable, only when changing the state of a control:

  1. <ControlTemplate TargetType="Button">
  2.     <Grid >
  3.         <VisualStateManager.VisualStateGroups>
  4.             <VisualStateGroup x:Name="CommonStates">
  5.                 <VisualStateGroup.Transitions>
  6.                     <VisualTransition To="MouseOver" GeneratedDuration="0:0:0.5"/>
  7.                 </VisualStateGroup.Transitions>
  8.                 <VisualState x:Name="Normal" />
  9.                 <VisualState x:Name="MouseOver">
  10.                     <Storyboard>
  11.                         <ColorAnimation Storyboard.TargetName="ButtonBrush" Storyboard.TargetProperty="Color" To="Red" />
  12.                     </Storyboard>
  13.                 </VisualState>
  14.             </VisualStateGroup>
  15.         </VisualStateManager.VisualStateGroups>
  16.         <Grid.Background>
  17.             <SolidColorBrush x:Name="ButtonBrush" Color="Green"/>
  18.         </Grid.Background>
  19.     </Grid>
  20. </ControlTemplate>

So here we animate the color of our button when the mouse is over it.

Also note that Silverlight can launch animations when the value of a property changes (with some code).

In conclusion, if we ignore the very low support (for now) of animations technologies in browsers, we can consider that both competitors are well equipped in terms of animations with quite similar philosophies.

Web requests & Web services

Web requests

The Web Requests are requests made to a server from the client application code. They can query a remote resource without changing the user interface.

Eventually the query result can be processed by the code to impact the user interface.
In HMTL5 (well, mostly in Javascript), it is possible to make XMLHttpRequest:

  1. function write(data) {
  2.     var webrequestResult = document.getElementById('webrequestResult');
  3.     webrequestResult.innerHTML = data;
  4. }
  5.  
  6. function handler() {
  7.     if (this.readyState == 4 && this.status == 200) {
  8.         if (this.responseXML != null)
  9.             write(this.responseXML.text);
  10.         else
  11.             write(null);
  12.     } else if (this.readyState == 4 && this.status != 200) {        
  13.         write('Erreur...');
  14.     }
  15. }
  16.  
  17. var client = new XMLHttpRequest();
  18. client.onreadystatechange = handler;
  19. client.open("GET", "http://www.catuhe.com/files/data.xml");
  20. client.send();

With this same system it is also possible to make HTTP POST.

In Silverlight, we have two classes to do this kind of request: HttpWebRequest (lower level) and WebClient (high level):

  1. private void UserControl_Loaded(object sender, RoutedEventArgs e)
  2. {
  3.     WebClient webClient = new WebClient();
  4.     webClient.DownloadStringCompleted += (s, arg) =>
  5.                                              {
  6.                                                  result.Text = arg.Result;
  7.                                              };
  8.  
  9.     webClient.DownloadStringAsync(new Uri("http://www.catuhe.com/files/data.xml"));
  10. }

Note that we are not limited to download XML in Silverlight. Indeed, it is possible to send / receive byte arrays so we can transfer anything (in digital form obviously).

Web services

Regarding web services, Silverlight with Visual Studio allows us to make a simple [Add Reference]. It generates the local proxy to call a web service (WCF for example) using the HttpWebRequest.

In Javascript, it is less easy because the tools are not (yet) available but it is still possible for example to use the AJAX framework. Otherwise you will have to write your own queries and handle the protocol.

We must therefore recognize that Web Services/WCF & Silverlight (thanks to its excellent integration with Visual Studio) offers a much easier implementation.

Media (Audio & Vidéo)

Silverlight 5 and HTML 5 both offer advanced support for audio and video. The main problem for HTML 5 is at the non-standard codecs (and the war between the H.264 and WebM). Thus, depending on the browser, we have to send a video in one format or another.

However HTML 5 provides an elegant solution, with the possibility to define in a single <video> or <audio> tag several potential sources in order of preference:

  1. <video controls>
  2.     <source src="mavideo.mp4" type="video/mp4"/>
  3.     <source src="mavideo.webm" type="video/webm"/>
  4.     Unable to read the video...
  5. </video>

It is also possible to add a Silverlight after all the sources in case the browser does not support HTML 5.

It is of course possible to manipulate audio and video via conventional controls such as Play / Pause / Stop / Seek. It is even possible to capture the video stream into an image that can be used elsewhere in the application.

In Silverlight 5, there is no codecs war (the advantage of being a single decision maker). So as long as Silverlight is supported, we guarantee that our video works. So no need to encode multiple sources. In the same way (as in HTML 5) it is possible to manipulate the video via commands or use the video as a brush to another control.

  1. <MediaElement x:Name="mediaelement" Source="http://monserveur.com/video" AutoPlay="True" />

In addition, Silverlight 5 supports smooth streaming (broadcast stream that will adapt to the connection and the power of the client) through its associated control:

  1. <SmoothStreamingMediaElement AutoPlay="True" x:Name="SmoothPlayer" SmoothStreamingSource="http://monserveur.com/flux.ism/Manifest" />

Silverlight also supports the concept of DRM (Digital Rights Management) and can therefore deliver video protected by copyright as HTML 5 not provide the same functionality. Sites using HTML 5 will thus be limited to providing free of rights material.

Again, both players are functionally well-equipped. However Silverlight supports additional services and is not subject to the codecs war. So it is a slight victory for Silverlight 5.

Isolated Storage

Silverlight 5 offers local data storage via the API Isolated Storage. The Isolated Storage is a file system accessible only by the application and/or the current user.

Subsequently the use of this storage space is identical to that of a standard file system:

  1. using (var isostore = IsolatedStorageFile.GetUserStoreForApplication())
  2. {
  3.     IsolatedStorageFileStream stream = isostore.OpenFile("toto.txt", FileMode.Open);
  4.     using (StreamReader reader = new StreamReader(stream))
  5.     {
  6.         reader.ReadToEnd();
  7.     }              
  8. }

In HTML 5, there are 2 main solutions for isolated storage:

  • localStorage: This is a solution to save pairs of keys/values ​​for the long term (the data is retained after the browser is closed), accessible only by the current window object:
  1. <body>
  2.     <div id='userName'>
  3.     </div>
  4. </body>
  5. <script>
  6.     if (localStorage['user'] == undefined)
  7.         localStorage.setItem('user', 'David');
  8.  
  9.     var div = document.getElementById('userName');
  10.  
  11.     div.innerHTML = localStorage['user'];
  12. </script>
  • sessionStorage: this can store key/value pair for the lifetime of the current session and is only accessible by the current window object

As we can see the two competitors offer solutions philosophically identical but with different implementations: Silverlight with a file system orientation and HTML 5 storage with a structured orientation.

WebSockets vs System.Net.Sockets

HTML 5 introduces the concept of WebSocket for network communication. It is an evolution of TCP/HTTP that will allow continuous bi-directional connections between the client and the server. Indeed, the HTTP protocol is stateless and not connected.Therefore it is difficult to use for transient or push type communications.

Currently WebSocket has an issue: they are changing continuously (for example because of some recently discovered safety problems). So the browsers either: do not support the standard, block the feature temporary, or leave the door open to network vulnerabilities.
Moreover, the name is misleading, WebSocket are not sockets for the web. You must indeed connect to server that can handle the protocol. You cannot use them to connect to any TCP server.

Silverlight 5, meanwhile, offer support for sockets on TCP and multicast. There is of course security constraints related to using of these classes (cross-domain policy for example) to prevent opening security gaps in Silverlight.
So we can easily attribute the victory to Silverlight both on functionality and availability.

Devices (cameras, microphones & printers)

Silverlight 5 provides access to the datastream from the camera or microphone. It can also send a print job controlling the drawing of each printed page.
HTML 5 on the subject is currently a bit light in terms of access to the camera or microphone. Several specifications are in progress and for the moment no browser supports them:

It is difficult today to judge the HTML 5 platform on its ability to capture audio and video.

To manage the printer, the only available method is window.print. Now it can just start printing without deciding the behavior of each page.
On the topic of devices access, Silverlight 5 wins by a large margin (for now).

Business case

Beyond the technical aspects, there are many other points to consider when choosing a technology.

The first of these is the team skill level with those technologies. If the developers are trained in .NET obviously, Silverlight is an easy choice. Similarly, if the team is already versed in the dark arts of JavaScript, HTML 5 will be a better option.

In a second step, the search for sustainability may be a strong factor of selection. And this is not so clear cut. Indeed, one can easily picture Silverlight having beautiful years ahead of it (or at least XAML +. NET). One thing is sure though, we are at the beginning of the adventure of HTML 5.
With the onset of tools, ever increasing browsers support or even the finalization of the standard, it does not take a rocket scientist to see that HTML 5 will be a huge success.

However, we must remember that HTML 5 is a slow-moving standard where Silverlight can change very quickly and if you ever miss a Silverlight feature in an HTML 5 development, there will be water under the bridge before it actually makes it to the standard. 

Focusing next on ease of implementation, I think Silverlight today has clearly a better VS support, debugger, profiler, frameworks and patterns. So for now, there is no match. Of course this could change rapidly especially with the future versions of Visual Studio. In addition for certain takes browsers can help with tools like the developers bar in IE9 (F12) that allows debugging, profiling and analyzing the code.

Finally, there remains the question of portability. From the site http://riastats.com, here are the distributions found worldwide:

image

73 % of browsers have Silverlight 4 installed

image

75 % of browsers supports HTML5 (a least a part of it)

We can see that Silverlight 5 and HTML 5 seem to be supported at the same level. However, it is somewhat more complex in reality. In fact, if your project targets only Windows and Mac OS, Silverlight is as well supported as HTML 5. By contrast, in IOS and Android, only HTML 5 is supported.

Also note that Silverlight can work "outside the browser" like a normal application (and therefore with elevated rights) which may be interesting for some projects. 

One should not be lulled by the myth of absolute portability of HTML 5. For now, the standard is evolving and will not be completed until 2014 at best. During this time and certainly for a long time afterwards, the browsers will be trying to support the standard. Thus, it will force us to write more code than necessary sometimes for specific versions (besides there is a JavaScript library that facilitates this work modernizr).

A final important aspect lies in the protection of intellectual property. There are obfuscators for both technologies (for example this one for Javascript) but we can see that as a result of compilation, Silverlight (IL) is more difficult to reverse engineer. In addition the XAML is not directly exposed: it is easier to get the HTML (directly sent to the browser).

Conclusion

In the end, there is no winner. We have two complementary technologies. Even if today there are more boxes with Silverlight 5 than boxes with HTML, the choice is not as simple as it is ultimately project dependent.

Indeed, it is sufficient that the project targets both Windows and Android tablets to push HTML 5 as the best solution.

So in the Web development world, we have to live with both, and know them well enough to provide the right solution at the right time.

Leave a Comment
  • Please add 8 and 8 and type the answer here:
  • Post
  • "73 % of browsers have Silverlight 5 installed" - should be SL4

  • Also, SL doesn't show, asks to install latest version, so mabe you are using SL5Beta?

  • Yes I use SL5 and you're right the right sentence is "73 % of browsers have Silverlight 4 installed'

    Thanks!

  • You consistently call it a draw when Silverlight wins numerically by substantial margins. Do you have a problem with honesty, or do you not understand relative numeric values?

  • I call a draw when at leat one browser do as well as Silverlight (with a little margin).

    But if you consider a draw game as a real victory for Silverlight, can you indicate me which one?

  • I am a long time WPF and Silverlight developer.  We have recently had to ditch most of our WPF and Silverlight efforts due to the iOS/Andriod incompatibilities.  We have customers who insist on using iPad or Andriod tablets for retail managerial tasks and once that cat was out of the bag, there's no way we could ignore it.  Knowing that there is no way we'll ever see Silverlight on iOS, we had to rebuild the apps in HTML 5 so that they could be used on iPad/tablet type devices.

    I LOVE WPF and Silverlight as development platforms - they give you the ability to do some really amazing things.  But with the increasing use of tablets (and their non-MS operating systems) in corporate environments, there's no way we can focus on those technologies if there's even a remote possibilty of someone wanting to use the app on a tablet type device.  I'd love to see Silverlight working on an iPad (or Andriod) tablet, but there is no way Apple will ever allow Silverlight to be installed on an iOS device.

  • Please do it on non-beta SL. THanks.

  • I agree with Tutu, this really should have been a Silverlight 4 vs. HTML5 article... Opinions that actually matters are from those who most probably do not have silverlight 5 installed yet, which you even point out in your last chart (SL 4 being the 73% majority)....sad really.

  • Hey nice article.

    Still I have to say Silverlight is nice.. it is developers friendly but no one cares.. because it is total crap crashes the browser and no one have it also it is not available for thousands of platforms (symbian, andriod, linux, meego, ) so actually it is nothing.

    I am a bit curious more if you add Flash in this picture because... Actually HTML5 is comparable to Flash (as cross platform cross browser solution ) but to compare with .. silversomething just doesnt have value for me and many. Even if silverlight is faster who cares no one can see your content.Comparing Html5 vs Flashplayer 10.2 is different story.

  • @TexasRay - Curious if you considered Mono (Touch/Droid) to leverage a common foundation in a .NET language for the non-visual layers of the client app and then layer on the visuals in the native platform ... or if the need to "write once" (for the most part) in HTML trumped everything. I'm still not clear on the perception of that approach, which we could call the "native-UI-on-.NET-base" approach, relative to a pure HTML/JavaScript/CSS client.

  • You should note that Silverlight does support scaling processing up to 8 logical cores.  So, your computational example is even faster in Silverlight when using multiple CPUs.

  • As one who has written dozens of HTML/js as well as WPF/Silverlight applications - mostly LOB and Geospatially enhanced sites; the thought of going back to the nightmare days of cross-browser compatibility and javascript debugging makes me ill. I understand the demand for HTML5 due to iOS and Android, but there is no question today we are able to produce RIA applications in SL in a fraction of the time it would take to do something even comparable in HTML5.

  • Pretty darn good article. People just can't give others the merit for well written stuff. Also, I'd consider that SL5 is much as a Beta as HTML5 is.

    Congratulations for your job.

    Regards,

    Bruno Rodrigues

    www.devdotnet.com.br

  • Are we looking at performance on non-Microsoft OSes here?  

  • We can use Expression Blend to design UI & Animation for Silverlight Application, is there any design tool for HTML 5? Thanks a lot.

Page 1 of 2 (27 items) 12