javascript 在 AngularJS 指令中渲染 SVG 模板

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19568226/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 16:00:05  来源:igfitidea点击:

Rendering SVG templates in AngularJS directives

javascriptangularjssvg

提问by Jason More

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

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

I would like to have the directives elementbe 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.

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

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

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

html

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

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

采纳答案by Nitesh Kumar Anand

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

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

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