RaphaëlJS,无痛编码,& Stinky Browsers(IE,大多数)

时间:2010-01-26 07:59:40

标签: jquery svg raphael

需要一些关于此问题的最佳方法的建议:

我已经疯狂地爱上了RaphaëlJS,因为它已经让我和我的编码实现了SVG,因为它已经成功地将IE带入了折叠。

但是,我不喜欢为我要在页面上呈现的每个SVG图形添加​​.js文件。

所以,我在互联网上四处寻找,看看我是否能找到更“动态”的东西,我发现:(以下是我在这里找到的编辑后的代码版本:http://groups.google.com/group/raphaeljs/msg/ce59df3d01736a6f)< / p>

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);

从本质上讲,这允许我只用.svg图形编写一个普通的图像标签,jQuery插件会自动用Raphaël渲染的版本替换它。

这适用于非SVG兼容的浏览器,如IE,但在实际已经支持SVG图形的现代浏览器中,图像标签按原样工作(没有Raphaël),因此当Raphaël加载时,它会卸载现有图像,然后在Raphaël版本中淡出...基本上创造了一个闪烁。我试图通过淡化新版本来淡化这一点,但我仍然面临旧的显示,隐藏,然后再次显示的问题。

我需要一种方法来协调IE等有问题的浏览器中的所需行为以及现代的,符合标准的浏览器(例如Safari 4和Firefox 3)中的不良行为。但是,我想以一种我不喜欢的方式执行此操作不得不显着改变我编码的方式(为什么我首先使用插件)。

我知道SVG仍然有点尖端,但有没有人对我如何解决这个问题有任何想法?

免责声明:如果可能的话,我想远离浏览器定位......我正在寻找一个可管理且功能强大的工作流程解决方案,而不是浏览器黑客。

第2免责声明:我不想要基于Flash的解决方案;我希望尽可能“原生”,并且我认为javascript比Flash更重要。 (这就是为什么我对Raphaël如此兴奋,因为我可以远离Flash)。

2 个答案:

答案 0 :(得分:0)

您是否尝试过svgweb

如果没有本机支持,将触发Flash插件来呈现SVG。

答案 1 :(得分:0)

是的,我想出了这个......(使用Ruby on Rails,顺便说一下)

  1. 将SVG图片导出到public/images/svg/
  2. 运行rake svg:parse:to_json(我的rake任务来源)
  3. 使用JSON路径数据重绘Raphaël图形。
  4. 仅使用<span class="svg">name_of_svg_file</span>调用我的SVG图形(默认情况下使用CSS隐藏span并使用下面的修改后的jQuery插件重绘)。
  5. 这意味着我从Illustrator到HTML的工作流程非常干净(在我的Capistrano部署过程中,我的rake任务激活)。这满足了我在我的问题中概述的需求,因为这几乎在我迄今为止测试过的每个浏览器中都是快速无闪烁的(Raphaël支持),不需要Flash,并且每个SVG只编写一行代码graphic(带有图形名称的<span>标签)。

    欢迎重构。

    ToDo:目前,如果用户将javascript变为关闭,则无法替换。我认为一个简单的<noscript>块可能会帮助我...


    <强> 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);
    

    使用SVG调用所有页面

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