Dynamische Grafiken

Anforderung

  • Grafik mit Prozent-Darstellung
  • optionale Darstellung eines Icons in der Mitte
  • flexible Größe
  • schnelle Ladezeit
  • Animation
  • Text mit Webfont

Lösungsmöglichkeiten

  • PHP GD und Ajax?
  • Flash?
  • SVG?
  • Canvas?

Canvas - kann was

Idee

Markup

<canvas 
class="canvasArc" 
width="400" height="400" 
data-procent="75" 
data-icon="0xe804">
</canvas>

callback google webfont

      var WebFontConfig = {
        google: {
          families: ['Roboto Slab']
        },
        active : function () {
          $(function() {
            $('.canvasArc').each(function () {
              ARC.init($(this));
            });
          });
        }
      };

callback local font

var loadCSS = function(url, callback){
    var link =  document.createElement('link');
        link.type = 'text/css';
        link.rel = 'stylesheet';
        link.href = url;
    document.getElementsByTagName('head')   
       [0].appendChild(link);
    var img = document.createElement('img');
    img.onerror = function() {
        if (callback) callback(link);
    }
    img.src = url;
};

requestAnimationFrame

window.requestAnimFrame = (function(){
    return  window.requestAnimationFrame       ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame    ||
            function( callback ){
                window.setTimeout(callback,     
                    1000/60);
            };
})();

Ergebnis

Test mobile

<!DOCTYPE HTML>
<html>
  <head>
    <title>canvas arc</title>
    <style>
      body {
        margin: 0px;
        padding: 0px;
      }
      .canvasArc {
        margin: 30px;
      }
    </style>
  </head>
  <body>
    <canvas class="canvasArc" width="400" height="400" data-procent="75" data-icon="0xe804"></canvas>
    <canvas class="canvasArc" width="200" height="200" data-procent="50" data-icon="0xe808"></canvas>
    <canvas class="canvasArc" width="100" height="100" data-procent="25" data-icon=""></canvas>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script>
        var loadCSS = function(url, callback){
            var link = document.createElement('link');
                link.type = 'text/css';
                link.rel = 'stylesheet';
                link.href = url;
            document.getElementsByTagName('head')[0].appendChild(link);
            var img = document.createElement('img');
            img.onerror = function() {
                if (callback) callback(link);
            }
            img.src = url;
        };

      var WebFontConfig = {
        google: {
          families: ['Roboto Slab']
        },
        active : function () {
          $(function() {
            $('.canvasArc').each(function () {
              ARC.init($(this));
            });
          });
        }
      };

      (function() {
        var wf = document.createElement('script');
        wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
                  '://ajax.googleapis.com/ajax/libs/webfont/1.4.7/webfont.js';
        wf.type = 'text/javascript';
        wf.async = 'true';
        var s = document.getElementsByTagName('script')[0];
        s.parentNode.insertBefore(wf, s);
      })();

      // Converts from degrees to radians.
      Math.rad = function (deg) {
        return deg * Math.PI / 180;
      };

      // Converts from radians to degrees.
      Math.deg = function (rad) {
        return rad * 180 / Math.PI;
      };

      // shim layer with setTimeout fallback
      window.requestAnimFrame = (function(){
        return  window.requestAnimationFrame       ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame    ||
                function( callback ){
                  window.setTimeout(callback, 1000 / 60);
                };
      })();

      var ARC = {
        steps : 100,
        cssLoaded : false,

        init : function ($obj) {
          var canvas = $obj[0];
          ctx = canvas.getContext('2d');

          var lineWidth = canvas.width * 0.04,
              radius = (canvas.width / 2) - (lineWidth / 2),
              startAngle = 0,
              endAngle = $obj.data('procent'),
              step = (endAngle - startAngle) / ARC.steps;

          ARC.arcLoop(ctx, radius, startAngle, endAngle, '#259b1f', lineWidth, step);

         loadCSS('fontello/css/aux-icons.css', function () {
            ARC.cssLoaded = true;
            ARC.text($obj);
         });

        },

        arcLoop : function (ctx, radius, startAngle, endAngle, color, lineWidth, step) {
          var nextAngle = startAngle + step;

          if (nextAngle <= endAngle) {
            //ARC.arc(ctx, radius, startAngle, nextAngle, color, lineWidth);
            ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
            ARC.arc(ctx, radius, 0, 360, '#e4e4e4', lineWidth*0.7);
            ARC.arc(ctx, radius, 0, nextAngle, color, lineWidth);

            if (ARC.cssLoaded) {
                ARC.text($(ctx.canvas));
            }

            requestAnimFrame(function () {
              ARC.arcLoop(ctx, radius, nextAngle, endAngle, color, lineWidth, step);
            });
          }
        },

        arc : function (ctx, radius, startAngle, endAngle, color, lineWidth) {

          var counterClockwise = false,
              x = ctx.canvas.width/2,
              y = ctx.canvas.height/2,
              degreeStart = -90;

          // degree2rad
          startAngle = Math.rad(startAngle + degreeStart),
          endAngle = Math.rad((endAngle*360/100) + degreeStart),

          ctx.beginPath();
          ctx.arc(x, y, radius, startAngle, endAngle, counterClockwise);
          ctx.strokeStyle = color;
          ctx.lineWidth = lineWidth;
          ctx.stroke();
        },

        text : function ($obj) { // ctx, text, size, font, posX, posY 
            var canvas = $obj[0];
                ctx = canvas.getContext('2d'),
                text = $obj.data('icon') === "" ? $obj.data('procent') + '%' : String.fromCharCode($obj.data('icon')),
                fontSize = ctx.canvas.width * 0.4,
                font = $obj.data('icon') === "" ? "'Roboto Slab'" : "'aux-icons'",
                posX = ctx.canvas.width/2, 
                posY = ctx.canvas.height/2 + fontSize/3;

          ctx.font = fontSize + "px " + font;
          ctx.textAlign = 'center';
          ctx.fillStyle = '#14497d';
          ctx.fillText(text, posX, posY);
        }

      };

    </script>
  </body>
</html>

Herausforderungen

  • callback google font
  • callback local font
  • stufen-bildung

Dynamische Grafiken

By phpiet

Dynamische Grafiken

  • 300