在指令Angular.js更新SVG模板 [英] Angular.js updating SVG templates in directives

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

问题描述

前段时间我问了一下<一个href=\"http://stackoverflow.com/questions/19568226/angular-js-rendering-svg-templates-in-directives\">Angular.js在指令渲染SVG模板,我在那里更换DOM节点模板时,与SVG节点的角度做。我得到的回答了我的一个反应,但我意识到,我失去了所有的数据绑定的角度。

请参阅Plunkr(点击更新): http://plnkr.co/edit/ HjOpqc?p = preVIEW

我如何更换SVG这些节点DOM节点,并留下我的角度绑定完好?我试着使用$编译,使其工作(就像我跟普通的HTML完成),但它只是不工作。

code:

  VAR svgNS ='http://www.w3.org/2000/svg';
app.directive('路径',ngSvg('路径'));
app.directive('G',ngSvg('G'));函数ngSvg(类型){
  返回函数($超时,$编译){
    返回{
      限制:'E',
      链接:功能(范围,EL,ATTR){
        //跳过的节点,如果他们已经SVG
        如果(EL [0] .namespaceURI === svgNS){
          返回;
        }        //我希望code的块下面的工作,
        //但它不与NG-重复        //变种newAttr = {};
        // _.each(EL [0] .attributes,功能(AT){
        // newAttr [at.nodeName] = at.value;
        //});        // VAR路径= makeNode(类型,萨尔瓦多,newAttr);
        // VAR父= path.cloneNode(真);        // $编译(父)(范围);        //变种孩子= el.children();
        // $(父).append(儿童);        // $超时(函数(){
        // el.replaceWith(父);
        //})
        //这个工程的渲染,但不更新SVG元素
        //当点击更新
        $超时(函数(){
          变种newAttr = {};
          _.each(EL [0] .attributes,功能(AT){
            newAttr [at.nodeName] = at.value;
          });          VAR路径= makeNode(类型,萨尔瓦多,newAttr);
          VAR父= path.cloneNode(真);
          变种孩子= el.children();
          $(父).append(儿童);
          el.replaceWith(父);
        });
      }
    }
  }
}/ *创建具有给定设置的形状节点。 * /
功能makeNode(名称,元素,设置){
  // VAR NS ='http://www.w3.org/2000/svg';
  VAR节点=与Document.createElementNS(svgNS,名);
  对(在设置var属性){
    VAR值=设置[属性]
    如果(价值== NULL和放大器;!&安培;价值== NULL和放大器;!&安培;!attribute.match(/ \\ $ /)及和放大器;
      (typeof运算值!=='串'||价值!=='')){
      node.setAttribute(属性值);
    }
  }
  返回节点;
}


解决方案

此问题解决在1.3角,这里是与你所期望从角度指令的行为,一些自定义的SVG指令的实现。现在有一个特殊要求是指令的声明如下: templateNamespace:SVG

另请注意,我重写一些保留的属性,例如 X 中关于<$ C 高度和$ C>&LT; RECT /&GT; 。为了对这些保留更多的控制,你可以利用 NG-ATTR 这样'&LT;矩形NG-ATTR-WIDTH ={{ngWidth}} /&GT;

的jsfiddle链接

下面是一个自定义&LT; RECT /&GT; &LT;圆/&GT;

  app.directive('ngRect',[功能(){
    返回{
        templateNamespace:'SVG',
        更换:真实,
        模板:'&LT;矩形NG-ATTR-WIDTH ={{ngWidth}}NG-ATTR-HEIGHT ={{ngHeight}}NG-ATTR-X ={{NGX}}NG-ATTR-Y ={{NGY}}NG点击=ngRectClick()/&GT;,
        范围: {
            ngHeight':'=',
            ngWidth':'='
        },
        链接:功能(范围,ELEM,ATTRS){
            scope.ngRectClick =功能(){
                的console.log(ELEM);
            }
        }
    }
}]);app.directive('ngCircle',[功能(){
    返回{
        templateNamespace:'SVG',
        更换:真实,
        模板:'&LT;圈NG-ATTR-CX ={{ngCx}}NG-ATTR-CY ={{ngCy}}NG-ATTR-R ={{NGR}}NG-ATTR填充={{ngFill}}NG点击=ngCircleClick()/&GT;,
        范围: {
            ngCx':'=',
            ngCy':'=',
            NGR':'=',
            ngFill':'='
        },
        链接:功能(范围,ELEM,ATTRS){
            scope.ngCircleClick =功能(){
                的console.log(ELEM);
            }
        }
    }
}]);

A while ago I asked about "Angular.js rendering SVG templates in directives", where I was replacing the DOM nodes that angular makes when rendering templates, with SVG nodes. I got a response that answered it for me, but I realized that I lost all the databindings from angular.

See Plunkr (click update): http://plnkr.co/edit/HjOpqc?p=preview

How do I replace these DOM nodes with SVG nodes, and leave my angular bindings intact? I tried using $compile to make it work (as I've done with regular html), but its just not working.

code:

var svgNS = 'http://www.w3.org/2000/svg';
app.directive('path', ngSvg('path'));
app.directive('g', ngSvg('g'));

function ngSvg(type) {
  return function($timeout, $compile) {
    return {
      restrict: 'E',
      link: function(scope, el, attr) {
        //skip nodes if they are already svg
        if (el[0].namespaceURI === svgNS) {
          return;
        }

        // I would expect the chunk of code below to work,
        // but it does not with ng-repeat

        // var newAttr = {};
        // _.each(el[0].attributes, function(at) {
        //   newAttr[at.nodeName] = at.value;
        // });

        // var path = makeNode(type, el, newAttr);
        // var parent = path.cloneNode(true);

        // $compile(parent)(scope);

        // var children = el.children();
        // $(parent).append(children);

        // $timeout(function() {
        //   el.replaceWith(parent);
        // })


        // this works for rendering, but does not update the svg elements
        // when update is clicked
        $timeout(function() {
          var newAttr = {};
          _.each(el[0].attributes, function(at) {
            newAttr[at.nodeName] = at.value;
          });

          var path = makeNode(type, el, newAttr);
          var parent = path.cloneNode(true);


          var children = el.children();
          $(parent).append(children);
          el.replaceWith(parent);
        });
      }
    }
  }
}

/* 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(svgNS, 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;
}

解决方案

This issue is solved in Angular 1.3 and here is an implementation of some custom svg directives with the behaviors you would expect from an Angular directive. There is now a special requirement is on the directive declaration as follows templateNamespace: 'svg'

Also notice I am overriding some reserved attributes, for example, x and height in regards to <rect/>. To retain more control over these you can leverage ng-attr as such '<rect ng-attr-width="{{ ngWidth }}" />

JSFiddle Link

Here is a custom <rect/> and <circle/>

app.directive('ngRect', [function () {
    return {
        templateNamespace: 'svg',
        replace: true,
        template: '<rect ng-attr-width="{{ ngWidth }}" ng-attr-height="{{ ngHeight }}" ng-attr-x="{{ ngX }}" ng-attr-y="{{ ngY }}" ng-click="ngRectClick()"/>',
        scope: {
            'ngHeight': '=',
            'ngWidth': '='
        },
        link: function (scope, elem, attrs) {
            scope.ngRectClick = function() {
                console.log(elem);
            }
        }
    }
}]);

app.directive('ngCircle', [function () {
    return {
        templateNamespace: 'svg',
        replace: true,
        template: '<circle ng-attr-cx="{{ ngCx }}" ng-attr-cy="{{ ngCy }}" ng-attr-r="{{ ngR }}" ng-attr-fill="{{ ngFill }}" ng-click="ngCircleClick()"/>',
        scope: {
            'ngCx': '=',
            'ngCy': '=',
            'ngR': '=',
            'ngFill': '='
        },
        link: function (scope, elem, attrs) {
            scope.ngCircleClick = function() {
                console.log(elem);
            }
        }
    }
}]);

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

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