在 AngularJS 指令中渲染 SVG 模板 [英] Rendering SVG templates in AngularJS directives

查看:35
本文介绍了在 AngularJS 指令中渲染 SVG 模板的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在处理一个包含 SVG 和 angular.js 的大型项目,需要对 svg 指令模板的可靠支持.不幸的是,当 angular 渲染模板时,它会创建 DOM 节点,而不是 SVG 节点.我目前的工作是使用 jquery.svg 自己管理创建和删除节点,但它的局限性.示例:http://plnkr.co/edit/Xk8wM3?p=preview

我想让指令 element 成为实际的 svg 元素,而不是一些没有真正做任何事情的人造 DOM 元素.这将让我有效地使用 ng-repeat 和 angular 过滤器.

这是需要修复的 plunkr:http://plnkr.co/edit/BPvGjf?p=预览

html

<!--woot 这个作品--><形状 d="M0,0L250,0L250,250L0,250z" 填充="绿色"></shape><!--嵌套指令不起作用--><组><形状 d="M0,0L150,0L150,150L0,150z" 填充="红色"></shape><shape d="M0,0L100,0L100,100L0,100z" 填充="橙色"></shape></组><!--ng重复不起作用--><shape d="{{square.path}}" fill="{{square.color}}" ng-repeat="正方形中的正方形| orderBy:'order'"></shape></svg>

javascript

var app = angular.module('plunker', []);app.controller('MainCtrl', function($scope) {$scope.squares = [{路径:M0,0L50,0L50,50L0,50z",颜色:'蓝色',订单:2}, {路径:M0,0L75,0L75,75L0,75z",颜色:'紫色',订单:1}];});app.directive('group', function($compile) {返回 {限制:'E',转置:真实,编译:函数(tElement,tAttr,transclude){var path = makeNode('g', tElement, tAttr);tElement.append(path.cloneNode(true));返回函数(范围,元素){transclude(范围,功能(克隆,innerScope){element.append($compile(clone)(innerScope));})}}}});app.directive('shape', function() {返回 {限制:'E',编译:函数(tElement,tAttr){var path = makeNode('path', tElement, tAttr);tElement.replaceWith(path.cloneNode(true));返回函数(范围,元素){}}}})/* 使用给定的设置创建一个形状节点.*/函数makeNode(名称,元素,设置){var svg = $(element).parents('svg')[0];var parent = $(element).parent()[0];var factory = $('#factory')[0] ||$('body').append('<svg id="factory"></svg>').find('#factory')[0];var ns = 'http://www.w3.org/2000/svg';//我已经尝试使用这里的工厂来创建节点然后克隆//将其放入新的 svg,但由于 angular 节点是先创建子节点的,因此它不起作用var node = parent.ownerDocument.createElementNS(ns, name);for(设置中的var属性){var 值 = 设置[属性];if (value !== null && value !== null && !attribute.match(/\$/) &&(typeof value !== 'string' || value !== '')) {node.setAttribute(attribute, value);}}parent.appendChild(node);返回节点;}

解决方案

我已经分叉并更新了您的 plunker 以使其正常工作 这里.当有问题的节点通过 angular 与文档分离以进行处理时,您的函数makeNode"有时会抛出错误.使用 0 毫秒的超时时间可以延迟执行,使父节点可用.另外,我使用链接函数来进行所有操作,因为编译函数每个 ng-repeat 只执行一次,但我们需要它重复多次.您可以在 Angular Directive 的编译和链接之间的区别"部分下阅读有关编译和链接函数之间区别的更多信息 页.

相关代码如下:

/* 使用给定的设置创建一个形状节点.*/函数makeNode(名称,元素,设置){var ns = 'http://www.w3.org/2000/svg';var node = document.createElementNS(ns, name);for(设置中的var属性){var 值 = 设置[属性];if (value !== null && value !== null && !attribute.match(/\$/) &&(typeof value !== 'string' || value !== '')) {node.setAttribute(attribute, value);}}返回节点;}

I'm working on a large project with SVG and angular.js, and need solid support for svg directive templates. Unfortunately when angular renders the templates, it creates DOM nodes, not SVG nodes. My current work around is to manage creating and deleting the nodes myself using jquery.svg, but its coming to it limits. Example: http://plnkr.co/edit/Xk8wM3?p=preview

I would like to have the directives element be the actual svg element, not some faux DOM element that doesn't really do anything. This will let me use ng-repeat and angular filters effectively.

Here is the plunkr that needs fixing: http://plnkr.co/edit/BPvGjf?p=preview

html

<svg>
  <!--woot this one works-->
  <shape d="M0,0L250,0L250,250L0,250z" fill="green"></shape>

  <!--nesting directives doesn't work-->
  <group>
    <shape d="M0,0L150,0L150,150L0,150z" fill="red"></shape>
    <shape d="M0,0L100,0L100,100L0,100z" fill="orange"></shape>
  </group>

  <!--ng repeat doesn't work-->
  <shape d="{{square.path}}" fill="{{square.color}}" ng-repeat="square in squares | orderBy:'order'"></shape>
</svg>

javascript

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.squares = [{
    path: "M0,0L50,0L50,50L0,50z",
    color: 'blue',
    order: 2
  }, {
    path: "M0,0L75,0L75,75L0,75z",
    color: 'purple',
    order: 1
  }];
});

app.directive('group', function($compile) {
  return {
    restrict: 'E',
    transclude: true,
    compile: function(tElement, tAttr, transclude) {
      var path = makeNode('g', tElement, tAttr);

      tElement.append(path.cloneNode(true));

      return function(scope, element) {
        transclude(scope, function(clone, innerScope) {
          element.append($compile(clone)(innerScope));
        })
      }
    }
  }
});

app.directive('shape', function() {
  return {
    restrict: 'E',
    compile: function(tElement, tAttr) {
      var path = makeNode('path', tElement, tAttr);

      tElement.replaceWith(path.cloneNode(true));

      return function(scope, element) {

      }
    }
  }
})

/* Create a shape node with the given settings. */
function makeNode(name, element, settings) {
  var svg = $(element).parents('svg')[0];
  var parent = $(element).parent()[0];
  var factory = $('#factory')[0] || $('body').append('<svg id="factory"></svg>').find('#factory')[0];
  var ns = 'http://www.w3.org/2000/svg';

  // I've tried using the factory here to create the node then clone
  // it into the new svg, but since angular nodes are created child-first, it didn't work

  var node = parent.ownerDocument.createElementNS(ns, name);
  for (var attribute in settings) {
    var value = settings[attribute];
    if (value !== null && value !== null && !attribute.match(/\$/) &&
      (typeof value !== 'string' || value !== '')) {
      node.setAttribute(attribute, value);
    }
  }
  parent.appendChild(node);
  return node;
}

解决方案

I have forked and updated your plunker to make it work here. Your function 'makeNode' was throwing error sometimes when the node in question was detached from document by angular for processing. Using a timeout of 0 ms does the trick of delaying the execution just enough to make the parent node available. Also, I am using the linking function to do all manipulation because the compile function executes only once per ng-repeat but we need it repeated number of times. You can read more about the difference between compile and linking functions under 'The difference between Compile and Link' section on Angular Directive page.

Here is the relevant code:

/* Create a shape node with the given settings. */
function makeNode(name, element, settings) {
  var ns = 'http://www.w3.org/2000/svg';
  var node = document.createElementNS(ns, name);
  for (var attribute in settings) {
    var value = settings[attribute];
    if (value !== null && value !== null && !attribute.match(/\$/) &&
      (typeof value !== 'string' || value !== '')) {
      node.setAttribute(attribute, value);
    }
  }
  return node;
}

这篇关于在 AngularJS 指令中渲染 SVG 模板的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆