RaphaëlJS, codage sans douleur, et Stinky navigateurs (IE, la plupart du temps)

StackOverflow https://stackoverflow.com/questions/2138119

  •  22-09-2019
  •  | 
  •  

Question

Vous avez besoin d'un conseil sur la meilleure approche à ce problème:

Je suis tombé follement amoureux de RaphaëlJS , comme elle l'a fait réalisable SVG pour moi et mon codage depuis il a réussi à mettre IE dans le pli.

Cependant, je n'aime pas avoir à inclure un fichier .js pour chaque graphique SVG Je veux rendre sur la page.

Alors, je poussé autour sur Internet pour voir si je pouvais trouver quelque chose qui était plus « dynamique », et je trouve ceci: (le ci-dessous est que je trouve ici ma version modifiée du code: http://groups.google.com/group/raphaeljs/msg/ce59df3d01736a6f )

function parseXML(xml) { 
  if (window.ActiveXObject && window.GetObject) { 
    var dom = new ActiveXObject('Microsoft.XMLDOM'); 
    dom.loadXML(xml); 
    return dom; 
  } 
  if (window.DOMParser) {
    return new DOMParser().parseFromString(xml, 'text/xml');
    throw new Error('No XML parser available');
  }
}

(function($) {

  $.fn.render_raphaels = function(options) {
    var defaults, options, counter, img_path, doc, root, vb, dims, img, node, path, atts, container, new_svg, inline;
    defaults = {};
    options = $.extend(defaults, options);

    counter = 0;
    inline = false;
    // find all the img's that point to SVGs
    $('img[src*="\.svg"]').each(function() {
      $(this).fadeOut(1000);
      img_path = $(this).attr('src');
      if (!$(this).attr('id')) new_svg = true;
      if ($(this).hasClass('inline')) inline = true;
      container = jQuery('<div/>', {
        id: $(this).attr('id') ? $(this).attr('id') : 'svg-' + (counter + 1),
        'class': $(this).attr('class') ? $(this).attr('class') : 'svg'
      }).hide().insertBefore($(this));

      $.get(img_path, null, function(doc) { 

        doc = parseXML(doc);
        root = $(doc).find('svg')[0];
        dims = [root.getAttribute('width'), root.getAttribute('height')];

        if(new_svg) container.css({ width: dims[0], height: dims[1] });
        if(inline) container.css('display', 'inline-block');

        img = Raphael(container.attr('id'), parseInt(dims[0]), parseInt(dims[1]));

        $(root).find('path').each(function() {
          node = this;
          path = img.path($(this).attr('d'));


          $(['stroke-linejoin','stroke','stroke-miterlimit','stroke-width','fill','stroke-linecap']).each(function() { 
            if($(node).attr(this.toString())) {
              path.attr(this, $(node).attr(this.toString()));
            } else {
              path.attr(this, 0);
            }
          });


          if($(node).attr('style')) {
            atts = $(node).attr('style').split(';');
            for(var i=0; i < atts.length; i++) { 
              bits = atts[i].split(':');
              path.attr(bits[0],bits[1]);
            }
          }

        });

      }, 'text');

      $(this).remove(); // removes the original image after the new one has been redrawn
      container.fadeIn(2000);
    });

  };

})(jQuery);

En substance, cela me permet d'écrire juste une balise image normale avec le graphique .svg, et le plugin jQuery remplacera automatiquement avec la version rendue Raphaël.

Cela fonctionne très bien dans les navigateurs non compatibles avec SVG, comme IE, mais dans les navigateurs modernes qui prennent en charge effectivement déjà graphiques SVG, la balise d'image fonctionne comme-est (sans Raphaël), de sorte que lorsque les charges Raphaël, il décharge l'image existante, puis se fane dans la version Raphaël ... créant essentiellement un scintillement. J'ai essayé de minimiser l'importance de ce par la décoloration dans la nouvelle version, mais je suis toujours confronté au problème que l'ancien montre, est caché, puis réapparaît.

Je besoin d'un moyen de concilier le comportement souhaité dans les navigateurs IE et problématiques comme le comportement indésirable dans les navigateurs modernes, conformes aux standards tels Safari 4 et Firefox 3. Mais, je veux faire cela d'une manière que je don « t doivent changer de manière significative le code I façon (pourquoi j'utilise le plug-in en premier lieu).

Je sais que SVG est encore un peu d'avant-garde, mais que quelqu'un a des idées sur la façon dont je peux contourner cela?

AVERTISSEMENT:. Si possible, je voudrais rester loin de ciblage des navigateurs ... Je suis à la recherche d'une solution de workflow gérable et fonctionnel, pas un hack navigateur

DISCLAIMER 2ND: Je ne veux pas une solution basée sur Flash; Je veux être comme « native » que possible, et je considère javascript pour être beaucoup plus que Flash. (Voilà pourquoi je suis tellement excité à propos de Raphaël, parce que je peux rester loin de Flash).

Était-ce utile?

La solution 2

Droit, je suis venu avec cette ... (en utilisant Ruby on Rails, btw)

  1. Exporter graphiques SVG à public/images/svg/
  2. Exécuter rake svg:parse:to_json (ma source de tâche Rake ci-dessous)
  3. Redessiner le graphique Raphaël en utilisant les données de chemin JSON.
  4. Appelez mon graphique SVG en utilisant seulement <span class="svg">name_of_svg_file</span> (cachant la durée par défaut à l'aide CSS et redessiner en utilisant le plugin jQuery modifié ci-dessous).

Cela signifie que mon flux de travail d'Illustrator vers HTML est très propre (je mon feu de tâche râteau pendant mon Capistrano déploiement). Cela répond à mes besoins décrits dans ma question que cela rend aussi rapidement et sans scintillement dans presque tous les navigateurs, je l'ai testé dans la mesure (que Raphaël soutient), ne nécessite pas Flash, et consiste à écrire une seule ligne de code par SVG graphique (la balise <span> avec le nom du graphique).

Refactorings bienvenue.

ToDo: En ce moment, si l'utilisateur a le javascript tourné off , il n'y a pas de remplacement. Je pense que d'un simple bloc de <noscript> pourrait me aider là-bas ...


parse_svg.rake

require 'hpricot' # >= 0.8.2
require 'json/pure'

namespace :svg do
  namespace :parse do
    desc "Parse all SVG graphics in '/public/images/svg' into JSON libraries in '/public/javascripts/raphael/svg-js/' usable by Raphaël"
    task :to_json do
      FileList['public/images/svg/*.svg'].each do |svg|
        name = File.basename(svg).split('.')[0]
        doc = open(svg) { |f| Hpricot.XML(f) } # parse the SVG
        js = {} # container
        js[:name] = name
        js[:width] = doc.at('svg')['width'].to_i
        js[:height] = doc.at('svg')['height'].to_i
        js[:paths] = [] # all paths
        doc.search("/svg/g//path").each do |p|
          path = {} # our path hash
          path[:path] = p['d'].gsub(/(?:[\r\n\t])+/, ',')
          path[:stroke_width] = p['stroke-width'] || 0
          path[:stroke] = p['stroke'] || 0
          path[:fill] = p['fill'] || 0
          js[:paths] << path
        end
        File.open("public/javascripts/raphael/svg-js/#{name}.js", 'w') { |f| f.write(js.to_json) }
      end
      puts "Done!"
    end
  end
end

render_raphaels.jquery.js

(function($) {
  $.fn.render_raphaels = function(options) {
    var defaults, options, name, container, raphael;
    defaults = {
      span_id: 'svg-ref'
    };
    options = $.extend(defaults, options);
    // find all the spans that point to SVGs, based on default or passed-in identifier
    $('span.'+options.span_id).each(function() {
      name = $(this).text();
      $.getJSON('/javascripts/raphael/svg-js/' + name + '.js', function(data) {
        paper = Raphael(document.getElementById(data.name), data.width, data.height);
        for (var p in data.paths) {
          paper.path(data.paths[p].path).attr({
            fill: data.paths[p].fill,
            stroke: data.paths[p].stroke,
            'stroke-width': data.paths[p].stroke_width
          });
        }
      });
      // remove the span
      $(this).remove();
    });
  };
})(jQuery);

appel à toutes les pages avec SVGs

$.fn.render_raphaels({ span_id: 'svg' });

Autres conseils

Avez-vous essayé svgweb ?

S'il n'y a pas de support natif, un plug-in flash sera déclenché pour rendre le SVG.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top