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

FR - HTML 5 & Silverlight 5


 

FR - HTML 5 & Silverlight 5

  • Comments 8

Philosophie de l’article

Le but de cet article est de présenter une comparaison objective entre HTML 5 (au sens large avec donc : Javascript / ECMAScript 5 + CSS3 +les éventuels frameworks et API additionnels)  et Silverlight 5. Nous nous attacherons à certaines fonctionnalités car il faudrait un livre entier pour couvrir tout ce que permet ces deux technologies.

L’idée est de fournir un guide permettant d’aider à la décision pour sélectionner une technologie plutôt qu’une autre dans le cadre d’un projet à réaliser.

Tous les éléments de décisions ne peuvent bien sûr pas être présentés ici et il faut prendre ce document comme une assistance au choix plutôt que comme une vérité absolue.

Nous nous attacherons dans chacune des parties à comparer à la fois les fonctionnalités mais également la facilité de mise en œuvre et la performance obtenue.

Le but ici n’étant pas d’étudier en détail les fonctionnalités de HTML 5 ou de Silverlight 5, vous trouverez en bas de l’article des liens utiles à lire pour approfondir vos connaissances.

Le code source des exemples est disponible ici.

HTML vs XAML

Les deux concurrents sont à égalité sur l’approche puisqu’ils sont tous les deux basés sur un langage balisé (HTML et XAML). Ils utilisent également tous les deux les attributs de manière intensive.

Extensibilité

Silverlight 5 permet de rajouter des attributs personnalisés aux balises existantes via les propriétés attachés. C’est également faisable en HTML 5 mais via l’utilisation d’un hack assez peu élégant (si HTML 5 ne reconnait pas une balise ou un attribut, il va juste l’ignorer. Il s’agira par la suite de disposer du bon Javascript qui viendra traiter ces informations). On peut en voir un exemple avec le projet KnockOut.

Silverlight possède en plus les Markup Extensions qui permettent d’ajouter du comportement au niveau des attributs existants (Binding notamment ou même des comportements personnalisés). De plus, la liste des balises n’est pas figée puisqu’il est possible de développer ses propres contrôles ce qui apporte un plus décisif dans l’industrialisation d’une solution Silverlight.

Accès au DOM

En Silverlight, chaque balise peut se retrouver directement dans le code behind via l’association à un nom (x:Name). En HTML 5, il est possible de faire de même via l’attribut 'id' mais uniquement sur certains navigateurs (IE, Chrome). Il faut donc passer par les services de localisation par identifiant de Javascript, ce qui pénalise légèrement la facilité de développement :

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

En ce qui concerne la traversée des arbres logiques, Silverlight et HTML font jeu égal puisqu’ils fournissent tous les deux des services associés.

Il est toutefois important de noter que HTML 5 est en train de se doter d’un outil de requête pour son DOM nommé Selectors API. Ce dernier va permettre de chercher de manière très efficace les objets de la page en utilisant des requêtes de sélection :

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

Dans cet exemple, nous demandons à l’API de nous retourner la liste des paragraphes dont la classe est “warning” ou “error”. Il est également possible des requêtes sur les ID, les types et de nombreux autres critères.

Séparation Code/Balises

Silverlight propose une séparation nette entre les balises et le code grâce d’une part à Visual Studio et d’autres part aux classes partielles.

En Javascript, il est possible de laisser le code dans la page html ou de passer par la balise script pour externaliser son code :

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

Les deux concurrents permettent donc de bien séparer le développement du design pour permettre l’intégration de designers/graphistes dans les projets.

Outils

L’outillage est un match facile pour Silverlight puisqu’il est simple de comparer Visual Studio et Notepad. En effet Silverlight va bénéficier de toute la puissance de Microsoft Visual Studio et de Microsoft Blend là ou HTML 5 (pour le moment) ne dispose pour ainsi dire d’aucun outil professionnel.

Avec Blend il est aisé de faire du design de XAML pour Silverlight. Il est aussi aisé de debugger et d’avoir accès à tous les services de colorations syntaxiques et autre Intellisense avec Visual Studio. Tout cela sans parler des profilers et des solutions de développement par simple glisser/déposer.

Le principal outillage dont on dispose aujourd’hui avec HTML 5 réside dans les barres de développements des navigateurs (touche F12). Elles vont permettre de débugger ou de profiler votre code lorsqu’il est traité par le navigateur. Le résultat est tout à fait satisfaisant mais loin de l’intégration et du confort de Visual Studio.

C’est bien évidemment appelé à changer mais pour le moment la victoire de la productivité est au net avantage de Silverlight.

Langages

Développement

Silverlight va s’appuyer sur C# ou Visual Basic qui sont des langages fortement typés avec une compilation JIT (Just in Time). Javascript est un langage dynamique interprété (mais qui peut être compilé à la volée sur certains navigateurs). Ce sont donc résolument deux approches différentes.

Le fait de ne pas être compilé a pour conséquence la découverte tardive des erreurs de syntaxe par exemple.

De plus il est plus difficile de débugger avec un langage dynamique non typé qui du coup accepte tout (surtout les erreurs). Avec un langage fortement typé, il n’est pas possible (ou pas simplement) de se tromper dans une affectation, dans le passage de paramètres ou bien encore dans le retour d’une valeur depuis une fonction. En Javascript au contraire, il est possible de mettre un tableau dans une variable et deux lignes plus bas y affecter un entier. De même si l’on se trompe dans une affectation en notant par exemple monobjet.prop = 1 et que la propriété prop n’existe pas, Javascript en tant que langage dynamique va créer la propriété. Cela complexifie grandement le débogage. Mais cela augmente aussi fortement la puissance du langage et ses capacités. D’ailleurs les nouvelles versions de C# ont fait un pas vers le monde dynamique avec les lambdas expressions et autre objets dynamiques (dynamic).

Il ne s’agit bien sûr pas ici de faire le procès des langages dynamique contre les langages statiques fortement typés. Il est juste important de bien comprendre les implications des uns et des autres. Finalement il est important de noter que la norme ECMAScript 5 va un peu mettre d’ordre puisqu’elle rajoute un mode strict qui contraint certaines fonctionnalités sources d’erreurs et normalise de nombreux comportements un peu flous ou ambigus.

Performances

La principale question cependant se situe bien sûr au niveau des performances.

Ainsi prenons un exemple simple : nous allons faire calculer un million de fois une opération faisant appel à la manipulation de chaines et au calcul mathématiques.

Nous regarderons alors le temps passé à exécuter notre code. Ce qui donne donc en direct :

Javascript

Silverlight 5

Get Microsoft Silverlight

La mise en œuvre pour 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>

Et le code  suivant pour 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);

Le résultat (sur ma machine) est très surprenant  :

Système

Temps de calcul

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


On peut donc voir que HTML 5 n’a rien à envier en puissance pure à Silverlight. Selon les navigateurs le résultat est bien entendu variable et il est évident que plus le temps passera plus la performance des runtimes Javascript s’améliorera. On peut toutefois déjà constater que certains navigateurs arrivent à faire mieux que Silverlight.

SVG vs Shapes

Silverlight 5 et HTML 5 offrent tous les deux la possibilité de faire du dessin vectoriel. Un dessin vectoriel est composé de formes géométriques contrairement à des images bitmaps qui travaillent avec des pixels.

Par nature, un dessin vectoriel est dessiné à chaque fois que l’on souhaite le visualiser. L'intérêt est de pouvoir redimensionner l'image à volonté sans aucun effet d’escalier (aliasing).

SVG (Scalable Vector Graphics) est la technologie de dessin vectoriel de HTML 5. Elle dispose des objets de base suivants:

  • Rectangle
  • Cercle
  • Ellipse
  • Line
  • Polyline
  • Polygon
  • Path (avec système de commandes : MoveTo, LineTo, …)

Silverlight utilise les classes héritant de la classe de base Shapes pour définir les formes géométriques de base:

  • Rectangle
  • Ellipse
  • Line
  • Polyline
  • Polygon
  • Path (avec système de commandes : MoveTo, LineTo, …)

On peut donc constater qu’en termes d’options, c’est une égalité. De même les deux systèmes proposent un système de transformations à base de matrices tout à fait comparable. Nous allons donc nous pencher sur les performances pour essayer de départager nos concurrents.  Pour ce faire nous allons développer une petite application qui va manipuler des cercles (ou des ellipses rondes) et des paths (que nous allons composer de deux courbes de béziers). Ainsi le fond sera composé de notre path dont on animera la forme et de 100 cercles de couleurs différentes qui se déplaceront du bas vers le haut en réduisant progressivement leur opacité.

HTML 5

Silverlight 5

Launch

Get Microsoft Silverlight

Le code associé pour HTML 5 est le suivant :

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;

Le code associé pour 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. }

Le résultat (sur ma machine) est le suivant :

Système

FPS

Silverlight 5

63

Chrome 12

60

IE 10 PP1

50

IE 9

50

Firefox 4

50

Opera 11

Ne fonctionne pas

Safari 5

Ne fonctionne pas

Pour le coup il est impossible de départager les adversaires. Peut-être que le code Silverlight est plus propre et agréable à lire  mais cela reste une opinion très personnelle qui ne doit pas rentrer en jeu. Il s’agit donc d’un match nul.

Canvas vs WriteableBitmap

HTML 5 et Silverlight 5 offrent tous les deux la possibilité de travailler sur des surfaces 2D au niveau des pixels directement. En HTML 5 cette surface se nomme un canvas et en Silverlight 5 on parle de WriteableBitmap.

Accès aux pixels

De manière comparable les deux surfaces sont à la fois capables de dessiner des formes de bases (comme pour du SVG/Shape) mais surtout elles permettent un accès direct à leur contenu sous la forme RGBA (en HTML 5 nous manipulons 4 entiers par couleur) ou ARGB (en Silverlight on manipule un entier pour chaque couleur avec chaque composante occupant 8 bits).

On peut d’ores et déjà noter que la manière de manipuler les pixels de Silverlight est plus efficace puisqu’elle n’utilise qu’un seul entier contre quatre pour HTML 5.

Encore une fois, les fonctionnalités étant similaires, nous allons nous attacher à la comparaison des performances pour déterminer un gagnant. Pour cela, nous allons développer un effet que l’on trouvait sur les premières démos technologiques sur Amiga ou Atari ST lorsque l’informatique grand public était balbutiante : l’effet de feu! Cet effet se réalise en appliquant un flou vertical (de bas en haut) tout en générant des points de couleurs rouges sur la partie basse de l’image. De plus nous génèrerons des flammes sous le passage de la souris :

HTML 5

Silverlight 5

Launch

Canvas not supported :(
Get Microsoft Silverlight

Le code associé pour 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;

Pour 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. }

Le résultat (sur ma machine) est le suivant :

Système

FPS

Silverlight 5

80

Chrome 12

30

IE 10 PP1

33

IE 9

33

Firefox 4

60

Opera 11

47

Safari 5

30 (avec beaucoup de saccades)

Silverlight arrive au meilleur résultat notamment grâce à son système de stockage des pixels. Toutefois, les navigateurs de par leur architecture ne peuvent pas dépasser la barrière des 60 images par seconde. On peut donc conclure à un match nul ici (car au moins un navigateur arrive au même niveau que Silverlight).

Tracé de formes

Pour être complet toutefois il faut également tester la performance du mécanisme de tracés de formes. Nous allons donc reproduire la démo utilisée pour le match SVG vs Shapes mais en dessinant dans nos surfaces 2D :

HTML 5

Silverlight

Launch

Canvas not supported :(
Get Microsoft Silverlight

Le code qui va avec en 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. }

Et en 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. }

Le résultat (sur ma machine) est le suivant :

Système

FPS

Silverlight 5

60

Chrome 12

60

IE 10 PP1

60

IE 9

60

Firefox 4

60

Opera 11

60

Safari 5

60

Rien à dire de plus, tant en termes de performances que de fonctionnalités les deux concurrents font jeu égal pour la partie tracé de formes.

Brushes

Les brushes (ou brosses dans la langue de Molière) servent à remplir avec une couleur, un dégradé ou un pattern les différents éléments de l’interface.

En HTML5, il est possible de s’en servir via CSS ou directement dans un canvas ou un SVG. Il est également possible de se servir de textures sous la forme d’images ou de vidéos (notamment dans le cadre des canvas).

En Silverlight 5, nous retrouvons le même concept avec en plus la possibilité de se servir du rendu d’autres contrôles comme texture de base (VisualBrush).

Un exemple de ces brosses donne :

HTML 5

Silverlight 5

Couleur pleine :

Radial gradient :

Linear gradient :

Get Microsoft Silverlight

Le code HTML 5 correspondant est le suivant :

  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>

Et en 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>

Finalement, même les syntaxes se ressemblent fortement. On peut donc considérer qu’il s’agit d’un match nul.

Contrôles

En Silverlight 5, il est à la fois possible de définir ses propres contrôles par agrégation ou depuis zéro (UserControl et CustomControl). Il est de plus possible d’hériter des contrôles de base pour les enrichir ou bien encore de modifier les templates associés pour définir leur visualisation. En deux mots Silverlight est extrêmement puissant pour la partie interface visuelle.

HTML 5 ne propose pas de solution intégrée pour faire des contrôles hormis le bête copier/coller de code. C’est un gros moins pour des projets d’entreprises qui nécessitent de pouvoir découper/industrialiser leurs développements. Nous sommes loin des assemblies de contrôles que l’on peut simplement référencer en Silverlight même si il reste possible de faire des bidouilles en Javascript.

A noter que HTML 5 introduit la notion de validation des contrôles (champ obligatoire, …) et de drag’n’drop.

Layout

La gestion du layout (la disposition de l’interface graphique et sa capacité à s’adapter) est très riche en Silverlight. Il est en effet possible de faire du placement:

  • Dans une grille (Grid) avec la taille des cellules en absolue, en relatif ou même adaptable au contenu)
  • En empilage vertical ou horizontal via un StackPanel
  • Dans un canvas (au sens Silverlight) qui permet un placement absolu via des coordonnées X et Y
  • Grâce au mécanisme de positionnement via les margins et les alignements
  • Via les overflows offerts par le nouveau contrôle RichTexboxOverflow

Ce système peut être de plus étendu à l’infini par l’ajout de contrôles utilisateurs qui peuvent définir le layout qui les intéresse. Un bon exemple peut être trouvé dans la Silverlight Toolkit qui rajoute notamment un WrapPanel.

HTML5 fournit également des solutions complètes pour construire son layout:

  • Mécanisme de grilles via les <table><td><tr>
  • Nouveau système de placement et de dimensionnement des grilles : CSS Grid Alignment Level 3. Vous constaterez que ce mécanisme est presque strictement identique à celui de Silverlight (D’ailleurs ce n’est pas sans raison, puisque c’est Microsoft qui a proposé cette spécification)
  • Système de layout intégré aux CSS (placement absolu ou relatif, taille absolue ou relative, etc.)
  • Nouveau système de CSS3 Flexbox dont on peut voir une démo juste ici (si votre navigateur le supporte). Cette spécification permet de gérer les alignements et le placement par rapport à des boites qui peuvent s’englober (oui c’est exactement la même chose que pour XUL et ce n’est pas non plus un hasard Sourire)
  • Système de rendu en multi-colonnes CSS3 Multi-column layout avec un exemple ici.
  • CSS3 Media Queries qui permettent de définir des layouts différents en fonction des tailles d’affichage avec un exemple ici (d’ailleurs Samuel Blanchard c’est amusé à refaire la même chose en Silverlight ici).

Le support des technologies de layout en HTML5 est encore moyen selon les navigateurs (toujours cette histoire de norme en cours d’évolution) mais si l’on ne se base que sur la fonctionnalité, il s’agit ici d’un match assez équilibré puisque les deux concurrents sont capables de produire des layouts adaptables et évolutifs facilement.

Databinding

Une fonctionnalité essentielle de Silverlight est le databinding qui ouvre notamment la porte à des design patterns tels que MVVM (Model/View/ViewModel) qui permettent de mettre en place des architectures modernes et efficaces.

Le databinding va également permettre de définir des interfaces dynamiques sans pour autant avoir besoin de faire du code.

Coté HTML 5, c’est le néant. Ce qui tend à faire penser que HTML 5 se dirige plus vers la mise en place de sites grand public là où Silverlight 5 permet de réaliser des projets d’entreprises.

Pour faire du databinding en HTML 5, il faudra forcément passer par du code Javascript afin de manuellement affecter les valeurs vers les contrôles puis s’abonner aux évènements de ces derniers pour récupérer les données modifiées. Des librairies existent (et utilisent par exemple jQuery ou bien Knockout) mais rien d’aussi efficace (tant en termes de mise en œuvre qu’en termes de performances) qu’avec Silverlight.

Threading : Web workers vs System.Threading

Silverlight 5 propose un support avancé du threading via la classe System.Threading.Thread et propose même un accès au pool de threads.

J’ai même récemment publié un article sur le portage de la Task Parallel Library sur Silverlight.

HTML5 vient quant à lui avec la notion de Web Workers. Il s’agit en effet de threads indépendants du thread principal (celui qui affiche et manipule le DOM).

Ces workers sont en fait des threads totalement cloisonnés qui communiquent avec le thread principal via un mécanisme de messagerie. Cela permet de ne pas avoir à se préoccuper de faire des sections critiques sur des données partagées puisqu’il n’y a pas de données partagées Sourire. De ce fait les workers ne peuvent accéder au DOM :

Script principal
  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");
Code du worker
  1. self.onmessage = function (e) {
  2.     self.postMessage(e.data.toUpperCase());
  3. }

La communication avec les workers se faisant via des chaines de caractères, il est nécessaire de sérialiser les objets à faire transiter en utilisant JSON ce qui peut être pénible à la longue.

La norme évolue encore très rapidement et l’on ne peut savoir quelle sera sa forme au final. Par exemple, elle vient de se doter de la notion de Shared Workers qui peuvent communiquer avec plusieurs scripts.

Vous trouverez ici un exemple de moteur de raytracing en Javascript utilisant les workers (si votre navigateur les supporte) : http://nerget.com/rayjs-mt/rayjs.html

Pour Silverlight, la communication avec les autres threads se fait par appel de méthodes ou passage de paramètres (en fait, rien de particulier que l’on soit en multi-threading ou non finalement). Il existe de plus de nombreux outils pour gérer la concurrence et la synchronisation tels que les ManualResetEvent, AutoResetEvent, Monitor, etc.

Vous trouverez ci-après un exemple de code en Silverlight qui utilise un ManualResetEvent pour contrôler un thread. On y voit également l’utilisation du Dispatcher qui permet au thread de faire exécuter du code sur le thread de l’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. }

Comme on peut le voir, Silverlight surclasse les Web Workers en matière de potentialités et d’outillages (encore une fois, grâce à Visual Studio qui fournit plusieurs outils de débogage) mais également en termes de contrôle sur les threads. L’ajout futur de technologies telles qu’Async Framework ou la TPL finira d’enfoncer le clou.

Bien évidemment, l’approche des Web workers (même si la norme est loin d’être sèche) est différente de celle du threading classique de Silverlight. Elle permet certes de faire du threading simplement mais ne suffit pas hélas à couvrir tous les besoins (sans faire de machine à gaz) que l’on rencontre dans les applications modernes.

Animations

Le moteur d’animations de Silverlight permet de manipuler très simplement les propriétés des contrôles. Ces manipulations sont faites de manière fluide par un système autonome qui permet de gérer des animations linéaires ou non autant sur des propriétés simples (double, entier, etc.) ou sur des propriétés complexes (couleurs, tickness, etc.). Le contrôle de ces animations se fait sur un storyboard qui s’occupe pour nous du timing et des diverses synchronisations.

  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>

Ces animations peuvent être créées soit au niveau du XAML soit au niveau du code. Comme on peut le voir ci-dessus, il est même possible de définir des fonctions pour définir la non-linéarité des animations.

En HTML5, il est possible de s’appuyer sur la fonction setInterval et setTimeout pour animer (manuellement) des éléments du DOM:

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

Ici, point de support particulier par le système, c’est à nous de tout gérer. Par contre, forcément, tout est possible du coup.

Une nouvelle technologie est toutefois apparue (mais encore bien peu supportée par les navigateurs) pour améliorer les choses : CSS Animations Module Level 3.

Grâce à ce module, il est possible d’animer les styles CSS sur le temps avec une gestion déclarative très intéressante :

  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.   }

Sur cette animation, on décide d’animer l’attribut “left” en définissant des points clés de l’animation. Le système se chargera par la suite de faire varier l’attribut en fonction du temps.

L’affectation de cette animation se fera au niveau d’un style:

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

Comme pour Silverlight, il est possible de définir des fonctions pour donner la linéarité (ou non) de l’application.

De plus, HTML5 (en fait CSS3) intègre également la spécification CSS Transitions Module Level 3 qui permet de définir des animations sur une transition, c’est à dire quand un attribut reçoit une nouvelle valeur:

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

Sur cet exemple, lorsque l’on va toucher à la valeur opacité, le système fera progressivement changer la valeur courante vers la nouvelle valeur sur 2 secondes. Il est également possible de définir la manière dont l’animation va se dérouler sur la période (transition-timing-function).

En Silverlight, nous avons également un système permettant de gérer les transitions : le VisualStateManager. Ce dernier permet de définir les animations non pas lors du changement de la valeur d’une variable mais lors du changement d’état d’un contrôle:

  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>

Ici donc nous animons la couleur de notre bouton lorsque la souris le survole.

On peut aussi noter qu’en Silverlight, on peut lancer des animations au changement de valeur d’une propriété si l’on le souhaite via un peu de code.

En conclusion, si l’on ne tient pas compte du très faible support (pour le moment) des technologies d’animations de CSS3 par les navigateurs, on peut considérer que les deux concurrents sont bien outillés en termes d’animations avec finalement des philosophies assez similaires.

Web requests & Web services

Web requests

Les web requests sont des requêtes effectuées vers un serveur depuis le code de l’application cliente. Elles permettent d’interroger une ressource distante sans modifier l’interface utilisateur. Par la suite le résultat de la requête peut-être traité par le code pour présenter l’information au client.

En HMTL5 (enfin, surtout en Javascript), il est possible de faire des 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();

Via ce même système il est également possible de faire du POST sur Http.

En Silverlight, nous disposons de deux classes pour faire ce genre de requêtes : HttpWebRequest (bas niveau) et WebClient (haut niveau).

Ainsi le téléchargement de notre fichier en Silverlight donnerait:

  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. }

A noter que nous ne sommes pas limités en Silverlight à télécharger du XML. En effet, il est possible d’envoyer/recevoir des tableaux de bytes ce qui nous permet de transférer ce que l’on souhaite.

Web services

En ce qui concerne les web services, Silverlight via Visual Studio permet de faire un simple [Add Reference] qui génère pour nous le proxy local pour appeler un web service (WCF par exemple) en utilisant les HttpWebRequests.

En Javascript, c’est moins aisé car les outils ne sont pas (encore) disponibles mais il reste possible par exemple d’utiliser le framework AJAX. Sinon vous devrez faire vous-même vos requêtes et gérer le protocole.

Il faut donc bien reconnaitre que sur la partie Web Services/WCF, Silverlight grâce à son excellente intégration dans Visual Studio remporte la palme avec une bien meilleure facilité de mise en œuvre.

Média (Audio & Vidéo)

HTML 5 et Silverlight 5 proposent tous les deux un support avancé de l’audio et de la vidéo. Le principal problème pour HTML 5 réside au niveau de la non-normalisation des codecs (avec une guerre entre le H.264 et WebM). De ce fait, selon les navigateurs, il faudra envoyer une vidéo dans un format ou dans un autre.

HTML 5 propose toutefois une solution élégante avec la possibilité de définir dans le tag <video> ou <audio> plusieurs sources potentielles par ordre de préférence :

  1. <video controls>
  2.     <source src="mavideo.mp4" type="video/mp4"/>
  3.     <source src="mavideo.webm" type="video/webm"/>
  4.     Impossible de lire la vid?o...
  5. </video>

Il est également possible de mettre après toutes nos sources un plugin Silverlight pour charger la vidéo si le navigateur ne supporte pas HTML 5.

Il est bien entendu possible de manipuler l’audio et la vidéo via des commandes classiques telles que Play/Pause/Stop/Seek. Il est même possible de récupérer dans le flux vidéo une image que l’on peut utiliser ailleurs dans l’application.

En Silverlight 5, il n’y a pas de guerre de codecs (l’avantage d’être seul à décider). Ainsi du moment que Silverlight est supporté, nous avons la garantie que notre vidéo fonctionnera. Pas besoin donc de multi-encoder les sources. De la même manière (comme en HTML 5) il est possible de manipuler la vidéo via des commandes ou bien se servir de la vidéo comme d’une brosse pour un autre contrôle.

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

De plus, Silverlight 5 supporte le smooth streaming (diffusion de flux qui vont s’adapter à la connexion et à la puissance du client) via son contrôle associé :

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

Silverlight supporte aussi la notion de DRM (Digital Rights Management) et permet donc de diffuser de la vidéo protégée avec une gestion des droits d’auteurs ce qu’aujourd’hui HTML 5 n’est pas capable de réaliser. Les sites HTML 5 devront donc se cantonner à fournir de la vidéo libre de droits.

Encore une fois, les deux acteurs sont bien équipés fonctionnellement. Siverlight supporte toutefois des services supplémentaires et n’est pas soumis à la guerre des codecs. C’est donc une légère victoire pour Silverlight 5.

Isolated Storage

Silverlight 5 propose à l’utilisateur de sauvegarder sur le poste client ses données via l’API de l’Isolated Storage. Cette dernière permet de récupérer un système de fichiers isolé, c’est à dire uniquement accessible par l’application et/ou l’utilisateur courant.

Par la suite l’utilisation de cet espace de stockage est identique à celui d’un système de fichiers standard:

  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. }

En HTML 5, il existe 2 grandes solutions pour faire de l’Isolated Storage :

  • localStorage : Il s’agit d’une solution permettant de sauvegarder des paires de clefs/valeurs pour une durée longue (la donnée est conservée après la fermeture du navigateur) et accessible uniquement par l’objet window courant :
  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 : Il permet de stocker des paires clefs/valeurs pour la durée de vie de la session courante et accessible uniquement par l’objet window courant

Comme nous pouvons le constater les deux concurrents proposent des solutions philosophiquement identiques mais avec des implémentations différentes : Silverlight avec une orientation système de fichiers et HTML 5 avec une orientation stockage structuré.

WebSockets vs System.Net.Sockets

HTML 5 introduit la notion de WebSockets pour la communication réseau. C’est une évolution du protocole TCP/HTTP qui va permettre une connexion bi-directionnelle permanente entre le client et le serveur. En effet, le protocole HTTP est non connecté et sans état et il reste donc difficile de faire des communications rapides ou en mode push en l’utilisant.

Le gros problème pour le moment des WebSockets est qu’elles sont en pleine évolution car de graves problèmes de sécurité ont été trouvés. Du coup soit les navigateurs ne supportent pas la norme, soit ils bloquent la fonctionnalité pour le moment, soit ils laissent la porte ouverte à des vulnérabilités réseaux.

De plus, même si le nom est trompeur, les WebSockets ne sont pas des sockets pour le web. Il faut en effet disposer d’un serveur en face capable de traiter le protocole. Vous ne pourrez pas vous en servir pour vous connecter en TCP sur n’importe quel serveur.

Silverlight 5, quant à lui, proposent le support des sockets sur le protocole TCP ainsi que le support du multicast. Il existent bien entendu des contraintes de sécurité liées à l’utilisation de ces classes (cross-domain policy par exemple) pour ne pas ouvrir de failles au sein de Silverlight.

Nous pouvons donc aisément attribuer la victoire à Silverlight tant sur la fonctionnalité que sur la disponibilité.

Devices (caméras, microphones & imprimantes)

Silverlight 5 permet d’accéder au flux de la caméra ou du microphone. Il permet également de lancer une impression en pilotant le dessin de chaque page imprimée.

HTML 5 sur le sujet est pour l’instant un peu léger en ce qui concerne l’accès à la caméra ou au microphone. Plusieurs spécifications sont en cours de réalisations/réflexions et pour le moment aucun navigateur ne les gère :

Il est donc difficile aujourd’hui de juger la plateforme HTML 5 sur sa capacité de capture audio et vidéo.

Pour la gestion de l’imprimante, seule la méthode window.print est disponible. Or cette dernière permet juste de lancer une impression sans décider du comportement de chaque page.

Sur le sujet de l’accès aux devices, Silverlight 5 est donc largement gagnant (pour le moment). Et ceci sans parler de l’accès aux ports COM disponibles en mode Out of browser.

Choix métiers

Au-delà des aspects techniques, il existe de nombreux autres points à prendre en compte lors du choix d’une technologie.

Le premier d’entre eux est la compétence courante de l’équipe. Si cette dernière est déjà formé à .NET (ou mieux à Silverlight) il est évident que le choix de Silverlight sera plus simple. De même, si l’équipe est déjà versée dans les arts obscurs du Javascript, HTML 5 sera plus préconisé.

Dans un second temps, la recherche de pérennité risque d’être un fort facteur de sélection. Et là, c’est déjà moins facile. En effet, on peut aisément imaginer que Silverlight a encore de belles années devant lui (ou tout du moins XAML + .NET). Mais une chose est sure nous sommes au début de l’aventure HTML 5. Avec l’apparition des premiers outils, le support toujours plus grand par les navigateurs ou bien encore la finalisation de la norme, il ne faut pas être grand clerc pour voir que HTML 5 sera un énorme succès.

Toutefois, il faut voir que HTML 5 est une norme à évolution lente là ou Silverlight peut évoluer très vite et si jamais une fonctionnalité de Silverlight est absente de HTML 5, il va couler de l’eau sous les ponts avant que l’on la voit apparaitre dans un futur HTML.

Il faut ensuite se pencher sur la facilité de mise en œuvre. Et force est de constater que pour le moment, Silverlight lamine HTML 5 : support complet dans Visual Studio (IntelliSense, coloration syntaxique), débuggeur complet, profileur, frameworks et patterns modernes et industrialisés. Pour le moment donc, il n’y a pas photo. Bien entendu cela risque d’évoluer rapidement notamment avec la disponibilité future des nouvelles versions de Visual Studio. De plus sur certains aspects les navigateurs peuvent aider comme par exemple avec la barre de développeurs de IE9 (touche F12) qui permet de débugger, de profiler et d’analyser le code.

Finalement, il reste la question de la portabilité. En provenance du site http://riastats.com, voici les différentes répartitions constatées en France :

image

65,2 % des navigateurs ont Silverlight 4 d’installé

image

66,8 % des navigateurs ont un navigateur supportant HTML 5 (au moins en partie)

On peut constater que Silverlight 5 et HTML 5 font jeu égal. Toutefois, c’est un peu plus complexe dans la réalité. En effet, si votre projet cible uniquement Windows et Mac OS, Silverlight est aussi indiqué que HTML 5. Par contre si vous rajoutez les systèmes iOS et Androïd, seul HTML 5 est supporté.

Il faut également noter que Silverlight peut fonctionner en mode “hors du navigateur” comme une application normale (et donc avec des droits élevés) ce qui peut être intéressant pour certains projets.

Il faut toutefois ne pas se laisser bercer par la fable de la portabilité absolue de HTML 5. Pour le moment, la norme évolue et ne sera finalisée au mieux qu’en 2014. Pendant ce temps et certainement pendant une longue période après, les navigateurs font supporter une partie plus ou moins importante de la norme. De ce fait, cela nous forcera à écrire plus de code que nécessaire voire même à écrire des versions spécifiques (d’ailleurs il existe une librairie Javascript qui facilite ce travail : modernizr).

Un dernier aspect important se situe au niveau de la protection de la propriété intellectuelle. Il existe des obfuscateurs pour les deux technologies (ici par exemple pour Javascript) mais l’on peut constater que du fait de la compilation de Silverlight (en IL), il est plus complexe de récupérer le code en Silverlight. De plus le code XAML n’étant pas exposer directement, ce dernier est donc moins facile à obtenir que le HTML qui est envoyé naturellement pour le navigateur.

Conclusion

Au final, il n’y a donc pas de grand gagnant. Il y a bien deux technologies complémentaires. Même si aujourd’hui il y a plus de cases avec Silverlight que de cases avec HTML 5, le choix n’est pas aussi simple car tout dépend finalement du contexte et du projet ciblé. En effet, il suffit que le projet cible à la fois Windows et les tablettes Androïd pour que HTML 5 apparaisse comme la meilleure solution.

Il faudra donc faire avec et essayer de bien connaitre les deux pour proposer la bonne solution au bon moment.

Pour aller plus loin

Leave a Comment
  • Please add 4 and 8 and type the answer here:
  • Post
  • Je vous remercie pour cet comparaison très intéressante, complète et parfois surprenante de HTML5 et SL.

    Elle m'inspire quelques commentaires:

    - HTML5/JS mêle de façon inextricable un moteur d'UI, HTML, et un un moteur d'exécution: JS.

     Ce seul fait rend cette solution rebutante: pour l'utiliser autrement que pour des petits projets

     il me faudrait réapprendre un langage, un framework, et renoncer à utiliser tout code existant: absurde.

     Il est d'autant plus extravagant de voir MS promouvoir cette technologie qu'elle a développé et promu

     pendant dix ans .Net, et qu'il aurait été simple de proposer une solution JS basée sur un moteur

     CLR, capable d'héberger ledit JS mais aussi les autres langages .Net...

     Le projet (P)NaCl de Google va dans ce sens.

    - le test de performance n'est pas très convaincant puisqu'il consiste principalement à appeler des fonctions

     du framework. IL serait intéressant de tester des séquences plus longues de 'pur' code JS/CSharp.

     A propos de performance, la dispersion des résultats affichée pour une même plateforme par divers navigateurs

     illustre la limite de l'argument de la portabilité des applis HTML5/JS: pour évaluer le seuil d'écroulement

     de telles applis vous devrez et en vérifier la portabilité, vous baser sur le browser le moins performant,

     le surcroit de capacité apporté par le browser le plus puissant devient accessoire. Cet argument devient encore

     plus pertinent dans le cas d'applications devant fonctionner sur des plateformes matérielles différentes.

    - le manque de portabilité imputé à SL est de la seule responsabilité de MS: rien ne l'empêcherait de porter SL

     (initalement nommé WPF/E, 'E' pour 'everywhere' ;-)) sur des plateformes autres que Windows, ni de faire des différentes

     variantes de WPF, WPF/SL/WP7 une technologie plus cohérente, base d'applications plus portables qu'elles ne le sont actuellement,

     et finalement trés en avance sur toutes les autres technologies comparables.

    - la gestion des threads, la capacité à créer des composants, des user controls, le databinding, les commands, le support de la 3D ...

     sont autant d'arguments plaçant SL loin devant HTML5/JS pour des projets conséquents

    - le coté multiplateforme du HTML5 vu par MS est paradoxal, puisqu'il semble que HTML5 semble devoir être la technologie recommandée

     pour produire les futures applis W8, ce qui ne sera pas, sauf grossière erreur de ma part, sans 'améliorer' HTML5 pour lui permettre

     de mettre en oeuvre les ressources logicielles faisant l'intérêt de W8. Les applis HTML5 ainsi produites ne seront plus multi-plateformes,

     ce qui est probablement le but recherché.

    Plus généralement, le fait que MS se propose de 'supporter' HTML5 me semble une bonne chose, mais que cela se fasse

    au détriment, voire au prix de l'abandon à terme de technologies autrement puissantes bien que non totalement abouties

    et sur lesquelles tant de gens ont autant investi est inacceptable: je partage la rage qui s'exprime içi et là à ce sujet.

    Philippe

  • Bonjour Philippe,

    en voila un beau commentaire ! :)

    Et de manière globale je suis d'accord avec vous.

    Toutefois:

    - Il n'a jamais été dit que la promotion de HTML5 par Microsoft soit faite au détriment d'autres technologies Microsoft. C'est juste une parmi tant d'autres.

    - Pour le test de performances, je suis d'accord avec vous. Toutefois je préfére retenir le meilleur des navigateurs car les autres finiront par arriver au même niveau (mais quand? et c'est la un des soucis de HTML5)

    - Effectivement, si nous souhaitions il serait possible de faire marcher Silverlight sur Android (plus dur sur Iphone mais faisable). Toutefois, ce n'est pas la stratégie de Microsoft (et ce n'est pas moi qui décide^^).

    -"puisqu'il semble que HTML5 semble devoir être la technologie recommandée pour produire les futures applis W8" :  ce n'est pas ce qui a été dit. Nous avons juste présenter une technologie de Win8. Il y en aura BIEN d'autres! De plus il n'a pas non plus été dit que nous ferons un ms-HTML5. Ce n'est pas l'objectif.

    En tout cas on peut retenir que le sujet est brulant et au combien interessant.

    Encore une fois merci pour votre excellent commentaire.

    David.

  • Bonjour David,

    <<- Il n'a jamais été dit que la promotion de HTML5 par Microsoft soit faite au détriment d'autres technologies Microsoft. C'est juste une parmi tant d'autres.>>

    Ca n'a pas été dit, mais il n'a pas été formellement affirmé non plus que WPF/SL/WP7 continueraient à être développé sur le long terme, d'où inquiétude et tension légitimes, et sentiment de gâchis, voire de trahison.

    <<Toutefois je préfère retenir le meilleur des navigateurs car les autres finiront par arriver au même niveau

    On peut retenir cet argument, mais de mon point de vue il ne s'applique pas pour des applis devant fonctionner sur des plateformes très différentes,

    ce qui est sensé être une des promesses de HTML5: il faut alors se caler sur les configurations cible les plus modestes...

    <<Toutefois, ce n'est pas la stratégie de Microsoft (et ce n'est pas moi qui décide^^).

    Il semble que l'équipe Mono ait pour projet de porter leur Moonlight sur Android, entre autres intéressants projets à base de .Net.  

    A titre personnel, j'utilise leur produits MonoTouch et MonoMac avec grand profit: ils proposent une autre approche du multiplateforme,

    consistant à conserver d'une plateforme à l'autre IDE, framework, language tout en ayant plein accès aux aspects spécifiques des plateformes cible, XCode/Cocoa... pour les produits cités...  

    C'est toujours un plaisir de 'croiser le fer' avec vous :-)!

    Philippe

  • "Ca n'a pas été dit, mais il n'a pas été formellement affirmé non plus que WPF/SL/WP7 continueraient à être développé sur le long terme, d'où inquiétude et tension légitimes, et sentiment de gâchis, voire de trahison."

    Est-ce que ne pas dire une chose c'est dire son contraire ? Question philosophique...

    "On peut retenir cet argument, mais de mon point de vue il ne s'applique pas pour des applis devant fonctionner sur des plateformes très différentes,"

    Pour les performances, je le retiens. Pour la portabilité non et je vous rejoins.

    Pour Mono, ce qui me fait peur c'est la pérennité sans Novell. Mais j'espere sincerement que leur aventure durera!

    David.

  • <<De plus il n'a pas non plus été dit que nous ferons un ms-HTML5

    Si on lit l'accroche de Build: http://www.buildwindows.com/

    "Web-connected and web-powered apps built using HTML5 and JavaScript have access to the power of the PC"

    on se pose la question: comment faire bénéficier ces applications des spécificités de W8 avec le HTML5 standard,

    sans extension le rendant incompatible avec les autres plateformes?

    Si c'est possible, ce dont je doute, ces applications HTML5 'pures' fonctionneront directement sur MacOSX, iOS, Android

    et aussi avec W7 en l'état: W8 en particulier et Windows en général deviennent anecdotiques, transparents!

    MS refuse de développer .Net/WPF sur des plateformes non Windows, et prétend par ailleurs promouvoir une technologie

    par nature multiplateforme permettant de se 'libérer' totalement de Windows: amusant :-)!

    L'idée d'attirer les développeurs HTML5 vers W8 en leur permettant de mettre en oeuvre leur savoir faire pour développer

    des applis W8, et probablement W8 seulement, tout en dépréciant ses propres technologies pourtant nettement supérieures

    et en destabilisant sa base de développeurs ne me semble pas moins absurde.

    J'attends les précisions devant être apportées par Build avec gourmandise: le marketing MS n'a pas encore révélé toute l'étendue

    de son talent :-)!

    Philippe

  • Je ne peux hélas pas me prononcer sur ces aspects mais je reprendrais juste votre phrase "J'attends les précisions devant être apportées par Build avec gourmandise" :)

  • J’aimerais beaucoup me lancer dans "l’aventure" HTML5, mais le simple fait de devoir bidouiller (désolé pour le terme) du JavaScript/CSS/html, le tout dans un joyeux plat de spaghettis, me refroidi énormément. J’ai l’impression que je n’arriverai jamais à franchir le cap C#/XAML -> plat de spaghettis... et ça va me retomber dessus.

  • Bonjour,

    je suis occupé sur un projet en Silverlight 5/Sql Server 2008R2 et la seule barrière rencontrée à ce jour c'est la non portabilité sur Android malgré que Novell ait annoncé à plusieurs reprises une solution;

Page 1 of 1 (8 items)