简体   繁体   中英

In nested directive, why is my child directive getting the attributes of the parent directive?

I am using AngularJS+D3 for creating a interactive drawing tool. I am new to both. I have a framecontainer directive which contains frames. Each frame is a svg group containing a rectangle and drag-handles. Framecontainer handles all the interaction including adding new frames. Each frame can contain more frame. In the link function of Framecontainer directive, I compile a new frame and append it for adding new frame. Now, when I add a frame for the first time using $compile, it adds the frame as expected. However, when I drag the newly added frame, it seems to get its attribute like width and height from the parent DOM element. The drag-function is taking the values of the parent DOM element. Why is this happening?

This is the drag function:

var dragmove=function(d) {
                    if (scope.moveable==="true") {
                        console.log("COMES HERE TOO!");
                         d.x = Math.max(0, Math.min(w - width, d3.event.x));
                        d.y = Math.max(0, Math.min(h - height, d3.event.y));
                        d3.select(dragrect[0].parentNode).attr("transform","translate("+ d.x+","+ d.y+")");
                        translatex= d.x;
                        translatey= d.y;

                    }
                }    

moveable is set at the beginning of the link function by reading the attribute. Outside this dragmove function, the values are as they should be. However, inside this function the value seems to be of the parent DOM element. So, scope.moveable has false even though I set it to true and outside the function the value is true. Also, the frame directive requires the Framecontainer directive and uses its controller.

Here is my frames directive:

app.directive('frames',function($compile){
return{
    restrict:'E',
    priority:20,
    scope:{

    },
    replace:true,
    require:'^^framecontainer',
    template:"<g><rect id='{{surfaceID}}' class='drawarea' ng-Dblclick='popDialog()' fill-opacity='1' ng-attr-x='{{x}}' ng-attr-y='{{y}}' ng-attr-height='{{rectheight}}' ng-attr-width='{{rectwidth}}' stroke-width='3' cursor='move' stroke='{{strokecolor}}' ng-attr-fill={{rectfill}} ></rect>"
    + "<rect ng-attr-height='{{handlerheightr}}' class='dragr' opacity='0' ng-attr-x='{{handlerxr}}' ng-attr-y='{{handleryr}}' ng-attr-width='{{handlerwidthr}}' cursor='ew-resize'  fill='#773326' ></rect>"
    + "<rect ng-attr-height='{{handlerheightl}}' class='dragl' opacity='0' ng-attr-x='{{handlerxl}}' ng-attr-y='{{handleryl}}' ng-attr-width='{{handlerwidthl}}' cursor='ew-resize'  fill='#773326'></rect>"
    + "<rect ng-attr-height='{{handlerheightt}}' class='dragt' opacity='0' ng-attr-x='{{handlerxt}}' ng-attr-y='{{handleryt}}' ng-attr-width='{{handlerwidtht}}' cursor='ns-resize'  fill='#773326'></rect>"
    + "<rect ng-attr-height='{{handlerheightb}}' class='dragb' opacity='0' ng-attr-x='{{handlerxb}}' ng-attr-y='{{handleryb}}' ng-attr-width='{{handlerwidthb}}' cursor='ns-resize'  fill='#773326'></rect>"
    +"</g>",

    compile:function(s,e) {
        return {
            post: function postLink(scope, element, attr, controller) {
                var dragbarw = 10;
                scope.surfaceID=attr.id;
                scope.rectheight = attr.height;
                scope.rectwidth = attr.width;
                scope.strokecolor = attr.stroke;
                scope.rectfill = attr.fill;
                scope.x = attr.x;
                scope.y = attr.y;
                scope.handlerheightr = attr.height;

                scope.handlerwidthr=dragbarw;
                scope.handlerheightl = scope.rectheight;

                scope.handlerwidthl=dragbarw;
                scope.handlerheightt=dragbarw;
                scope.handlerheightb=dragbarw;
                scope.handlerwidtht=scope.rectwidth;
                scope.handlerwidthb=scope.rectwidth;

                scope.moveable=attr.mv;

                var w = 800;
                var h = 500;
                var width = scope.rectwidth;
                var height=scope.rectheight;
                var translatex,translatey;


                var dragrect = d3.select(element[0]).selectAll('.drawarea').attr("width","300");
                var entireContents=d3.select(element[0]).select('*');
                d3.select(element[0]).data([{x:0, y: 0}]);
                var dragbarleft=d3.select(element[0]).select(".dragl");
                var dragbartop=d3.select(element[0]).select(".dragt");
                var dragbarright=d3.select(element[0]).select(".dragr");
                var dragbarbottom=d3.select(element[0]).select(".dragb");

                // Selector and deselector
                var select = function () {
                    controller.addToSelection('#'+d3.select(this).attr("id"));
                    //controller.addToSelection(this);
                    d3.select(this).attr('stroke-dasharray', '5 5')
                        .on('click', deselect);

                };
                var deselect = function () {
                    controller.popFromSelection('#'+d3.select(this).attr("id"));
                    d3.select(this).attr('stroke-dasharray', '')
                        .on('click', select);
                };

                d3.select(element[0]).select('.drawarea').on('click', select);
                function rdragresize(d) {

                    var dragx = Math.max(d.x + (dragbarw / 2), Math.min(w, d.x + width + d3.event.dx));
                    width = dragx - d.x;
                    dragbarright.attr("x", function (d) {
                        return dragx;
                    });
                    dragrect.attr("width", width);
                    dragbarright.attr("x", dragx);
                    dragbartop
                        .attr("width", width - dragbarw)
                    dragbarbottom
                        .attr("width", width - dragbarw)
                }
                function ldragresize(d) {
                    var oldx = d.x;
                    //Max x on the right is x + width - dragbarw
                    //Max x on the left is 0 - (dragbarw/2)
                    d.x = Math.max(0, Math.min(d.x + width - (dragbarw / 2), d3.event.x));
                    width = width + (oldx - d.x);
                    dragbarleft
                        .attr("x", function(d) { return d.x - (dragbarw / 2)-translatex; });
                    dragrect
                        .attr("x", function(d) { return d.x-translatex; })
                        .attr("width", width);
                    dragbartop
                        .attr("x", function(d) { return d.x + (dragbarw/2)-translatex; })
                        .attr("width", width - dragbarw)
                    dragbarbottom
                        .attr("x", function(d) { return d.x + (dragbarw/2)-translatex; })
                        .attr("width", width - dragbarw)

                }
                function tdragresize(d){
                    var oldy = d.y;
                    d.y = Math.max(0, Math.min(d.y + height - (dragbarw / 2), d3.event.y));
                    height = height + (oldy - d.y);
                    dragbartop
                        .attr("y", function(d) { return d.y - (dragbarw / 2)-translatey; });

                    dragrect
                        .attr("y", function(d) { return d.y-translatey; })
                        .attr("height", height);

                    dragbarleft
                        .attr("y", function(d) { return d.y + (dragbarw/2)-translatey; })
                        .attr("height", height - dragbarw);
                    dragbarright
                        .attr("y", function(d) { return d.y + (dragbarw/2)-translatey; })
                        .attr("height", height - dragbarw);
                }
                var bdragresize=function(d){

                    var dragy = Math.max(d.y + (dragbarw/2), Math.min(h, d.y + height + d3.event.dy));

                    //recalculate width
                    height = dragy - d.y;

                    //move the right drag handle
                    dragbarbottom
                        .attr("y", function(d) { return dragy - (dragbarw/2) });

                    //resize the drag rectangle
                    //as we are only resizing from the right, the x coordinate does not need to change
                    dragrect
                        .attr("height", height);
                    dragbarleft
                        .attr("height", height - dragbarw);
                    dragbarright
                        .attr("height", height - dragbarw);
                }

                var dragmove=function(d) {
                    if (scope.moveable==="true") {
                        console.log("COMES HERE TOO!");
                         d.x = Math.max(0, Math.min(w - width, d3.event.x));
                        d.y = Math.max(0, Math.min(h - height, d3.event.y));
                        d3.select(dragrect[0].parentNode).attr("transform","translate("+ d.x+","+ d.y+")");
                        translatex= d.x;
                        translatey= d.y;

                    }
                }

                scope.popDialog=function()
                {


                    var newText=angular.element('<editabletext x="'+(scope.x+scope.rectwidth/2-scope.rectwidth/10)+'" y="'+scope.y+scope.rectheight/5+'" height="'+scope.rectheight/5+'" width="'+scope.rectwidth/5+'" text="Hello!!"></editabletext>');
                    element.append(newText);
                    $compile(newText)(scope);

                }

                function stopPropagation()
                {
                    d3.event.sourceEvent.stopPropagation();

                }


                var dragr = d3.behavior.drag().origin(Object).on("drag", rdragresize).on("dragstart",stopPropagation);
                var dragl=d3.behavior.drag().origin(Object).on("drag",ldragresize).on("dragstart",stopPropagation);
                var dragt=d3.behavior.drag().origin(Object).on("drag",tdragresize).on("dragstart",stopPropagation);
                var dragb=d3.behavior.drag().origin(Object).on("drag",bdragresize).on("dragstart",stopPropagation);
                var drag=d3.behavior.drag().origin(Object).on("drag",dragmove);

                console.log("ATTR-MV outside the drag function: "+attr.mv);

                d3.select(dragrect[0].parentNode).call(drag);
                dragbarleft.call(dragl);
                dragbarright.call(dragr);
                dragbartop.call(dragt);
                dragbarbottom.call(dragb);
            }
        }
    },

    controller:function($scope,$element)
    {
        this.getHeight=function()
        {
            return $scope.height;

        }

        this.getWidth=function()
        {
            return $scope.rectwidth;

        }

        this.getPosition=function()
        {

            return {x:scope.x,y:scop.y};

        }



        //$scope.$watch('fillFromParent',function(){ if ($scope.fillFromParent)$scope.rectfill=$scope.fillFromParent;});


    }
};});    

Here is the frame container directive:

app.directive('framecontainer',function($compile){
return{
    restrict:'A',
    scope:{
        split:'=',
        mergeq:'=',
        fillparam:'@',
        perform:'='
    },
    priority:1,
    replace:true,
    transclude:false,
    template:'<svg><frames id ="maing" stroke="#bada55" x="0" y="0"  resize height="500" width="765" fill="#006600" mv="false"   dialog="poptextdialog()"> </frames></svg>',
    link:function(scope,element,attr)
    {
        scope.$watch('perform',function(){

            var newFrame;
            var curWidth;
            var curHeight;
            var curX,curY;
            var newFrame;
            var frameID=0;

            function getRectCor(x,y,width,height)
            {
                return {x:(parseFloat(x)-parseFloat(width)/2),y:(parseFloat(y)-parseFloat(height)/2)};
            }

            if (scope.perform) {
                switch (scope.perform.action) {
                    case 0:
                        angular.forEach(scope.selectionStack,function(value,i){

                            curWidth=100;
                            curHeight=100;

                            curX=10;
                            curY=10;


                            newFrame=angular.element('<frames data-mv="true" data-stroke="#bada55" data-x="'+curX+'" data-y="'+curY+'"   data-height="'+curHeight+'" data-width="'+curWidth+'" data-fill="#FFFFFF" id="elem'+frameID+'" ></frames>');
                            frameID=frameID+1;
                            console.log("value is "+value);

                            $(value).append(newFrame);
                            $compile(newFrame)(scope.$new(true));
                        });

                        break;

                }
            }
        });


        var firstFrame='<g frame id ="maing" stroke="#bada55" x="0" y="0"  resize height="500" width="765" fill="#006600" mv="true"   dialog="poptextdialog()"> </g>';
        element.append(firstFrame);
        $compile(firstFrame)(scope);

    },
    controller:function($scope,$element)
    {
        $scope.selectionStack=[];
        var indexSelectionStack;

        this.addToSelection=function(s){
            $scope.selectionStack.push(s);
            console.log($scope.selectionStack);
        };

        this.popFromSelection=function(s){
            var index=$scope.selectionStack.indexOf(s)
            if (index>-1){
                $scope.selectionStack.splice(index,1);
            }
        };

        $scope.$watch('fillparam',function(){
            angular.forEach($scope.selectionStack,function(value,index){
                d3.select(value).select("rect").attr("fill",$scope.fillparam);

            });

        });




    }
};});

Sorry for the humongous post and the super-meshy code. I am new to both AngularJS and d3.

The issue is solved. Though it might not be a general problem, I thought it would help someone in the future to post an answer. The bug was quite trivial. The drag event was bubbling up to the top-most parent frame. So, changing the drag function to call to following solved the problem:

var drag=d3.behavior.drag().origin(Object).on("drag",dragmove).on("dragstart",stopPropagation);    

stopPropagation function prevents the drag event from bubbling up the DOM. Thank you everyone for pointing me in the right direction!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM