All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.reprezen.genflow.openapi.diagram.assets.script.chart-flow-jquery.js Maven / Gradle / Ivy

/**
 * Created with JetBrains WebStorm.
 * User: vipul-jain
 * Date: 3/1/14
 * Time: 12:47 PM
 * To change this template use File | Settings | File Templates.
 *
 * Variables
 * margin - default margin between nodes
 * padding - default padding between child's of nodes
 * transitionDuration - animation time for chart update
 * container - container that's hold the chart ( svg element )
 * svg  - svg element where out chart renders
 * width - container width
 * height - container height
 * root - root of data element ( data element )
 * rootNode - root node of data element ( svg element )
 *
 * chartGroup - the chart layer inside container which holds the all element of nodes, of flowLayout
 * chartLines - the link layer inside container which holds the extra links over the flowLayout
 *
 */

d3.custom.chart.flow = function(transitionDuration) {
    if (transitionDuration == null) transitionDuration = 300;
    // public variables with default settings
    var margin = {top:10, right:10, bottom:10, left:10}, // defaults
        padding = {top:30, right:10, bottom:10, left:10},// defaults
        chartGroup,
        chartLines,
        container,
        svg,
        width,
        height,
        root,
        rootNode,
        rootObject,
        scrollbarAffordance,
        top_padding = 13;

    /* A scale of colors for URI links. A resource can have several URI links and each of them has its own color.
     * The first element is used for the first link, the second for the second link and so on.*/
    var resourceUriLinkColors = d3.scale.ordinal().range(
    		["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"]);

    var referenceEmbedColors = d3.scale.ordinal().range(
			["#CCEBEB", "#99D6D6", "#86a9d1", "#c3d4e8", "#CCEBEB", "#99D6D6", "#86a9d1", "#c3d4e8"]);

    var flow = d3.custom.layout.flow()
        .margin(margin)
        .padding(padding)
        .nodeWidth(40) // width of node properties Kind of min width
        .nodeHeight(10) // height node properties Kind of min height
        .containerWidth(40)  // width of node container ( rect ) Kind of min width
        .containerHeight(30)
        .linkPadding(6); // height of node container ( rect ) Kind of min height

    function chart(selection) {
//      First node or data
        rootNode = selection.node();

//      set time out on resize to adjust the nodes for new height/width
        function debounce(fn, timeout) {
            var timeoutID = -1;
            return function() {
                if (timeoutID > -1) {
                    window.clearTimeout(timeoutID);
                }
                timeoutID = window.setTimeout(fn, timeout);
            }
        }

//      On window resize calculate new height and width of client view for main container
        function resize(selectedNode,isResize) {
            var domContainerWidth  = (parseInt(d3.select(rootNode).style("width"))),
                domContainerHeight = (parseInt(d3.select(rootNode).style("height"))),
                flowWidth = 0;

            if (root.height > domContainerHeight) {
                scrollbarAffordance = 0;
            } else {
                scrollbarAffordance = 0;
            }

            flowWidth = domContainerWidth - scrollbarAffordance;
            flow.width(flowWidth);

            if(isResize == undefined)isResize = true;
            chart.update(selectedNode,isResize);

            svg.transition().duration(transitionDuration)
                .attr("width", function(d) {
                    return domContainerWidth;
                })
                .attr("height", function(d) {
                    return d.height + margin.top + margin.bottom;
                })
                .select(".chartGroup")
                .attr("width", function(d) {
                    return flowWidth;
                })
                .attr("height", function(d) {
                    return d.height + margin.top + margin.bottom;
                })
                .select(".background")
                .attr("width", function(d) {
                    return flowWidth;
                })
                .attr("height", function(d) {
                    return d.height + margin.top + margin.bottom;
                });
        }

//      window resize function binding
        d3.select(window).on('resize', function() {
            debounce(resize, 50)();
        });

/**
 * This the main part of code where the chart and links layer are going to be render
 * selection - the selected element on DOM which hold the all svg elements
 * */
        selection.each(function(arg) {
            root = arg;
            container = d3.select(this);

            var i = 0;

            if (!svg) {
//              svg container
                svg = container.append("svg")
                    .attr("id", "main")
                    .attr("class", "svg chartSVG")
                    .attr("transform", "translate(0, 0)")
                    .style("shape-rendering", "auto") // shapeRendering options; [crispEdges|geometricPrecision|optimizeSpeed|auto]
                    .style("text-rendering", "auto"); // textRendering options;  [auto|optimizeSpeed|optimizeLegibility|geometricPrecision]

//                for now commenting shadow code

//                var defs = svg.append( 'defs' );
//                var filter = defs.append( 'filter' )
//                    .attr( 'id', 'dropShadow' )
//                filter.append( 'feGaussianBlur' )
//                    .attr( 'in', 'SourceAlpha' )
//                    .attr( 'stdDeviation', 2 ) // !!! important parameter - blur
//                    .attr( 'result', 'blur' );
//                filter.append( 'feOffset' )
//                    .attr( 'in', 'blur' )
//                    .attr( 'dx', 2 ) // !!! important parameter - x-offset
//                    .attr( 'dy', 2 ) // !!! important parameter - y-offset
//                    .attr( 'result', 'offsetBlur' );
//                var feMerge = filter.append( 'feMerge' );
//                feMerge.append( 'feMergeNode' )
//                    .attr( 'in", "offsetBlur' )
//                feMerge.append( 'feMergeNode' )
//                    .attr( 'in', 'SourceGraphic' );

                // this is only for debugging purposes,
                // allows to highlight svg:text using: 
                var filterDef = svg.append("defs").append("filter")
                    .attr("id", "fill_solid_yellow")
                    .attr("x", 0)
                    .attr("y", 0)
                    .attr("width", 1)
                    .attr("height", 1);
                filterDef.append("feFlood")
                    .attr("flood-color", "yellow");
                filterDef.append("feComposite")
                    .attr("in", "SourceGraphic");

//              Create arrow head marker for link
                svg.append("defs").append("marker")
                    .attr("id", "arrowhead_rlink")
                    .attr("refX", 3)
                    .attr("refY", 2)
                    .attr("markerWidth", 6)
                    .attr("markerHeight", 5)
                    .attr("orient", "auto")
                    .append("path")
                    .attr("d", "M 0,0 V 4 L6,2 Z");

//              Create circle head marker for link
                svg.append("defs").append("marker")
                    .attr("id", "markerCircle_rlink")
                    .attr("refX", 3)
                    .attr("refY", 2)
                    .attr("markerWidth", 6)
                    .attr("markerHeight", 5)
                    .attr("orient", "auto")
                    .append("circle")
                        .attr("cx", "3")
                        .attr("cy", "2")
                        .attr("r", "1.5");

//              Create arrow head marker for request response
                svg.append("defs").append("marker")
                    .attr("id", "arrowhead_msg")
                    .attr("refX", 3)
                    .attr("refY", 2)
                    .attr("markerWidth", 6)
                    .attr("markerHeight", 5)
                    .attr("orient", "auto")
                    .append("path")
                    .attr("d", "M 0,0 V 4 L6,2 Z");

//              Create circle head marker for request response
                svg.append("defs").append("marker")
                    .attr("id", "markerCircle_msg")
                    .attr("refX", 3)
                    .attr("refY", 2)
                    .attr("markerWidth", 6)
                    .attr("markerHeight", 5)
                    .attr("orient", "auto")
                    .append("circle")
                    .attr("cx", "3")
                    .attr("cy", "2")
                    .attr("r", "1.5");

//              Create horizontal line marker for URI parameter
                svg.append("defs").append("marker")
                    .attr("id", "markerH")
                    .attr("refX", 5)
                    .attr("refY", 10)
                    .attr("markerWidth", 10)
                    .attr("markerHeight", 10)
                        .append("line")
                        .attr("x1", "0")
                        .attr("y1", "10")
                        .attr("x2", "10")
                        .attr("y2", "10")
                        .style("stroke-width", "1.5")
                        .style("stroke", "black");

//              Create vertical line marker for URI parameter
                svg.append("defs").append("marker")
                    .attr("id", "markerV")
                    .attr("refX", 10)
                    .attr("refY", 5)
                    .attr("markerWidth", 10)
                    .attr("markerHeight", 10)
                        .append("line")
                        .attr("x1", "10")
                        .attr("y1", "0")
                        .attr("x2", "10")
                        .attr("y2", "10")
                        .style("stroke-width", "1.5")
                        .style("stroke", "black");

//              Init chartGroup object for nodes
                chartGroup = svg.append("svg:g")
                    .attr("class", "chartGroup");

//              Add background rectangle of container
                chartGroup.append("svg:rect")
                    .attr("class", "background");

//              Init chartLines object for links
                chartLines = svg.append('svg:g')
                    .attr('class','chartLines');

            }

            chart.resizeChart = function(a,b){
                return resize(a,b);
            };

            /*
            * Find out which nodes should be connected with links
            * reference links and URI links
            * */
            chart.getUpdatedLinkData = function(nodes){
                var extraLinkData = [];

                function resetReferenceLinkPoints(){
                    var _referenceLinks = extraLinkData.filter(function(_links){
                        return _links.type == "referenceLink";
                    });

                    for( _referenceIndex in _referenceLinks){
                        var _link = _referenceLinks[_referenceIndex];
                        var _toHorizontal = true;
                        if(_link.source_resource.x < _link.target.x ){
                            if(_link.source_resource.y == _link.target.y){
                                if(Math.abs(_link.target.x - (_link.source_resource.x+_link.source_resource.width)) > 150){
                                }else{
                                    _toHorizontal = false;
                                }
                            }
                        }
                        _link._toHorizontal = _toHorizontal;
                    }

                    var mapTargetsH = [];
                    var occurrencesH = [];
                    var mapTargetsV = [];
                    var occurrencesV = [];
                    for(var intIndex=0; intIndex<_referenceLinks.length;intIndex++){
                        var currentLink = _referenceLinks[intIndex];
                        if(currentLink._toHorizontal){
                            if(mapTargetsH.indexOf(currentLink.target) == -1){
                                mapTargetsH.push(currentLink.target);
                                occurrencesH.push(1);
                            }else{
                                occurrencesH[mapTargetsH.indexOf(currentLink.target)] += 1;
                            }
                        }else{
                            if(mapTargetsV.indexOf(currentLink.target) == -1){
                                mapTargetsV.push(currentLink.target);
                                occurrencesV.push(1);
                            }else{
                                occurrencesV[mapTargetsV.indexOf(currentLink.target)] += 1;
                            }
                        }
                    }

                    /**
                     * Calculating number of target for each resources
                     * */
                    var mapPositionH = [];
                    var mapPositionV = [];
                    var occurrencepositionH = [];
                    var occurrencepositionV = [];
                    for(var intIndex=0; intIndex<_referenceLinks.length;intIndex++){
                        var currentLink = _referenceLinks[intIndex];
                        if(currentLink._toHorizontal){
                            if(mapPositionH.indexOf(currentLink.target) == -1){
                                mapPositionH.push(currentLink.target);
                                occurrencepositionH.push(0);
                                currentLink.extra.totalTarget = occurrencesH[mapTargetsH.indexOf(currentLink.target)];
                                currentLink.extra.targetCount = 0;
                            }else{
                                occurrencepositionH[mapPositionH.indexOf(currentLink.target)] += 1;
                                currentLink.extra.totalTarget = occurrencesH[mapTargetsH.indexOf(currentLink.target)];
                                currentLink.extra.targetCount = occurrencepositionH[mapPositionH.indexOf(currentLink.target)]
                            }
                        }else{
                            if(mapPositionV.indexOf(currentLink.target) == -1){
                                mapPositionV.push(currentLink.target);
                                occurrencepositionV.push(0);
                                currentLink.extra.totalTarget = occurrencesV[mapTargetsV.indexOf(currentLink.target)];
                                currentLink.extra.targetCount = 0;
                            }else{

                                occurrencepositionV[mapPositionV.indexOf(currentLink.target)] += 1;
                                currentLink.extra.totalTarget = occurrencesV[mapTargetsV.indexOf(currentLink.target)];
                                currentLink.extra.targetCount = occurrencepositionV[mapPositionV.indexOf(currentLink.target)]
                            }
                        }
                    }
                }

                function resetURILines(){
                    function resetOneURILine(resource) {
                        var bindings = DiagramSpecifics.getURISegmentBindings(resource);
                        bindings.forEach(function(binding, idx) {
                            var nextLink = {};
                            nextLink.type = "URILink";
                            nextLink.id = resource.id + "_" + binding.matchedSegment.id;
                            nextLink.source = binding.matchedSegment;
                            nextLink.target = binding.matchedFeature;
                            nextLink.source_resource = resource;
                            nextLink.segmentBinding = binding;

                            //FIXME: this is weird place to compute it, remove it
                            nextLink.extra = {};
                            nextLink.extra.count = idx;
                            nextLink.extra.pad = 5 * idx + 5;

                            extraLinkData.push(nextLink);
                        });
                    }

                    nodes.forEach(function(d) {
                        if (d.objecttype == "ObjectResource" || d.objecttype == "CollectionResource") {
                            resetOneURILine(d);
                        }
                    });
                }

                /**
                 * Find out available ReferenceLines in chart
                 * task/ZEN-496
                 * Reference link visible in all expanded/collapsed states
                 *
                 * */
                function resetReferenceLine(){
                    var _resourceObjects = nodes.filter(function(d){
                        return d.objecttype == "ObjectResource" || d.objecttype == "CollectionResource";
                    });

                    // more than zero because it is possible external unconnected links
                    if(_resourceObjects.length > 0){
                        for(_resourceIndex in _resourceObjects){
                            var _referenceLinks = flow.getReferences(_resourceObjects[_resourceIndex],_resourceObjects);
                            for( _referenceIndex in _referenceLinks){
                                extraLinkData.push(_referenceLinks[_referenceIndex]);
                            }
                        }
                    }

                    resetReferenceLinkPoints();
                }

                function resetRequestLink(){
                    var _methodObjects = nodes.filter(function(d){
                        return d.objecttype == "Method";
                    });

                    if(_methodObjects.length > 0){
                        for(_methodIndex in _methodObjects){
                            var _method = _methodObjects[_methodIndex];
                            if(_method.children){
                                var _responses = _method.children.filter(function(_response){
                                    return _response.objecttype == "Request";
                                });
                                if(_responses.length > 0){
                                    for(_responseIndex in _responses){
                                        var _response = _responses[_responseIndex];
                                        var _linkObject = {};
                                        _linkObject.id = _method.name+"_"+_response.id;
                                        _linkObject.source = _method ;
                                        _linkObject.target = _response ;
                                        _linkObject.type = "requestLink";
                                        extraLinkData.push(_linkObject);
                                    }
                                }
                            }
                        }
                    }
                }

                function resetResponseLink(){
                    var _methodObjects = nodes.filter(function(d){
                        return d.objecttype == "Method";
                    });

                    if(_methodObjects.length > 0){
                        for(_methodIndex in _methodObjects){
                            var _method = _methodObjects[_methodIndex];
                            if(_method.children){
                                var _responses = _method.children.filter(function(_response){
                                    return _response.objecttype == "Response";
                                });
                                if(_responses.length > 0){
                                    for(_responseIndex in _responses){
                                        var _response = _responses[_responseIndex];
                                        var _linkObject = {};
                                        _linkObject.id = _method.name+"_"+_response.id;
                                        _linkObject.source = _response;
                                        _linkObject.target = _method ;
                                        _linkObject.type = "responseLink";
                                        extraLinkData.push(_linkObject);
                                    }
                                }
                            }
                        }
                    }
                }

                resetURILines();     // function to find URI links
                resetReferenceLine(); // function to find reference links
                resetRequestLink();   // function to find request links in method
                resetResponseLink();  // function to find response links in method

                return extraLinkData;
            };

            /*
            * Update links layer according to data
            * */
            chart.updateExtraLinks = function(nodes){
                var linkData = this.getUpdatedLinkData(nodes);
                var _sideLinkRef = [];

                /**
                 * Sharp     arc in link ( r = 3 )
                 *  |¯         a 3,3 0 0 0 -3,3    type 1
                 *  |_         a 3,3 0 0 0 3,3     type 2
                 *   ¯|        a 3,3 0 0 1 3,3     type 3
                 *   _|        a 3,3 0 0 1 -3,3    type 4
                 * */
                function getArc(_type,r,toDown,toLeft){
                    var arc = "a "+r+","+r+" 0 0 0 "+r+","+r+"";
                    var type = _type+"";
                    switch (type){
                        case "1":
                            if(toDown){
                                arc = "a "+r+","+r+" 0 0 0 "+ ( -1*r ) +","+r+"";
                            }else{
                                arc = "a "+r+","+r+" 0 0 1 "+ r +","+( -1*r )+"";
                            }
                        break;
                        case "2":
                            if(toLeft){
                                arc = "a "+r+","+r+" 0 0 0 "+r+","+r+"";
                            }else{
                                arc = "a "+r+","+r+" 0 0 1 "+(-1* r)+","+(-1*r)+"";
                            }

                            break;
                        case "3":
//                            arc = "a "+r+","+r+" 0 0 1 "+r+","+r+"";
                            if(toLeft){ // mean right to left
                                arc = "a "+r+","+r+" 0 0 1 "+r+","+r+"";
                            }else{
                                arc = "a "+r+","+r+" 0 0 0 "+ (-1*r)+","+(-1*r)+"";
                            }
                            break;
                        case "4":
                            if(toDown){
                                arc = "a "+r+","+r+" 0 0 1 "+ ( -1*r ) +","+r+"";
                            }else{
                                arc = "a "+r+","+r+" 0 0 0 "+ r +","+ ( -1*r)+"";
                            }
                            break;
                        default :
                            arc = "a "+r+","+r+" 0 0 0 "+r+","+r+"";
                    }
                    return arc;
                }

                function linkPassTo(resourceId){
                    var _getAdded = _sideLinkRef.filter(function(t){
                        return t.id == resourceId;
                    });

                    if(_getAdded.length > 0){
                        if(_getAdded[0].side){
                            _getAdded[0].side += 1;
                        }else{
                            _getAdded[0].side = 1;
                        }
                    }else{
                        var _tempObj = {};
                        _tempObj.id = resourceId;
                        _tempObj.side = 1;
                        _sideLinkRef.push(_tempObj);
                    }
                }

                function getSidePadding(resourceId){
                    var _getAdded = _sideLinkRef.filter(function(t){
                        return t.id == resourceId;
                    });
                    if(_getAdded.length > 0){
                        if(_getAdded[0].side){
                             if(_getAdded[0].side > 1)
                                return _getAdded[0].side*5 + 20;
                             else
                                return 25;
                        }
                    }
                    return 20;
                }

//              detect IE and it's versions for some svg capabilities check
                function detectIE() {
                    var ua = window.navigator.userAgent;
                    var msie = ua.indexOf('MSIE ');
                    var trident = ua.indexOf('Trident/');

                    if (msie > 0) {
                        // IE 10 or older => return version number
                        return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
                    }

                    if (trident > 0) {
                        // IE 11 (or newer) => return version number
                        var rv = ua.indexOf('rv:');
                        return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
                    }

                    // other browser
                    return false;
                }

                // If IE > 9 then render the all links
                if (detectIE() > 9){
                    chartLines.selectAll("g.extraLinks").remove();
                }
                var tempList = [];
                // function to draw the right path of reference links according to nods positions
                function getComputedPath(d){
                    var _path = "";
                    var x1,x2,y1,y2;
//                    return rout.getPath(d.source, d.source_resource, d.target);
                    var _marg = 10 + d.extra.pad ;

                    d.target._isTarget = true;

                    function getX2Position(node,fromleft){
                        var _target = node.target;
                        var _fragment = ( _target.width / (parseInt (node.extra.totalTarget) + 1) );
                        var _x2 = _target.x + _fragment +( _fragment * node.extra.targetCount );
                        if(!fromleft){
                            _x2 = _target.x + _target.width - ( _fragment +( _fragment * node.extra.targetCount ) );
                        }
                        return _x2;
                    }

                    x1 = d.source.x + d.source.width;
                    /**
                     * Divide height with number of outgoing link and find equal fragment
                     * */
                    if(d.isCollapsed){
                        var _fragment = ( d.source.height / (parseInt (d.total) + 1) );
                        y1 = d.source.y + _fragment +( _fragment * ( parseInt(d.extra.count) ) );
                    }else{
                        y1 = d.source.y + (d.source.height/2);
                    }

                    x2 = d.target.x;
                    var _expectedWidth = d.extra.totalTarget * flow.linkPadding();
                    var _expectedHeight = d.extra.totalTarget * flow.linkPadding();

                    if(d.source_resource.x < d.target.x ){
                        //left
                        if(d.source_resource.y == d.target.y){
                            if(Math.abs(d.target.x - (d.source_resource.x+d.source_resource.width)) > 150){
//                                x2 = d.target.x + (d.target.width * 0.05) + getSidePadding(d.target.id);
                                x2 = getX2Position(d,true);
                                y2 = d.target.y;
                                d.target._expectedWidth = _expectedWidth;
                            }else{
                                //beside
//                                y2 = d.target.y + (d.target.height/2);
                                var _fragment = ( d.target.height / (parseInt ( d.extra.totalTarget) + 1) );
                                y2 = d.target.y + _fragment +( _fragment * ( parseInt(d.extra.targetCount) ) );
                                d.target._expectedHeight = _expectedHeight;
                            }
                        }else{
                            d.target._expectedWidth = _expectedWidth;
                            if(d.source_resource.y < d.target.y){
                                //left to right source above to the target
//                                x2 = d.target.x + (d.target.width * 0.05) + getSidePadding(d.target.id);
                                x2 = getX2Position(d,true);
                                y2 = d.target.y;
                            }else{
                                //left to right source down to the target
//                                x2 = d.target.x + (d.target.width * 0.05) + getSidePadding(d.target.id);
                                x2 = getX2Position(d,true);
                                y2 = d.target.y + d.target.height;
                            }
                        }
                    }else{
                        //right
                        d.target._expectedWidth = _expectedWidth;
                        if(d.source_resource.y == d.target.y){
                            // same level
//                            x2 = d.target.x + d.target.width - ((d.target.width * 0.05) + getSidePadding(d.target.id));
                            x2 = getX2Position(d,false);
                            y2 = d.target.y ;
                        }else{
                            if(d.source_resource.y < d.target.y){
                                //right to left source above to the target
//                                x2 = d.target.x + d.target.width - ((d.target.width * 0.05) + getSidePadding(d.target.id));
                                x2 = getX2Position(d,false);
                                y2 = d.target.y;
                            }else{
                                //right to left source down to the target
//                                x2 = d.target.x + d.target.width - ((d.target.width * 0.05) + getSidePadding(d.target.id));
                                x2 = getX2Position(d,false);
                                y2 = d.target.y + d.target.height;
                            }
                        }
                    }

                    linkPassTo(d.source_resource.id);
                    linkPassTo(d.target.id);

                    /**
                     * This method will add minimum padding to root node so
                     *
                     * */

                     function addTopPadding(_padding){
                        if(rootObject._topPadding){
                            if(rootObject._topPadding > _padding){
                                rootObject._topPadding = _padding;
                            }
                        }else{
                            rootObject._topPadding = _padding;
                        }
                    }

                    /**
                     * Here is the code to separate line which are in same resource this
                     *
                     * For each new link it will come 4 px more outside than previous link
                     * Change in this code (i.e. change 4 to 5 ) also reflect change in layout js
                     * where the last padding is calculated. which inform next node that I have this much links
                     *
                     * */

 //                  var _cx = (d.source_resource.x + d.source_resource.width + 5 + (getSidePadding(d.source_resource.id) *0.5)) - 3 ;
                    var _cx = (d.source_resource.x + d.source_resource.width + 10 + ( d.extra.count * flow.linkPadding() ) );
                    _path = "M"+x1+","+y1 + "H"+ _cx ;
                    if(d.source_resource.x < d.target.x ){
                        // left to right
                        if(d.source_resource.y == d.target.y){
                            // same level
                            if(Math.abs(d.target.x - (d.source_resource.x+d.source_resource.width)) > 150){
//                                _path += "V"+ (d.source_resource.y - (getSidePadding(d.source_resource.id)*0.4 )- _marg) +"H" + (x2-getSidePadding(d.target.id));
//                                _path += "H"+x2+"V"+ y2 ;
                                var arc1 = "", arc2 = "",sp = 0;
                                if(y1 > y2){
                                    arc1 = getArc(4,3,false,true);
                                    arc2 = getArc(1,3,false,true);
                                    sp = -3;
                                }
                                var _cy = (d.source_resource.y - (getSidePadding(d.source_resource.id)*0.4 )- _marg - sp - (d.extra.count* 2) );
                                if(tempList.indexOf(_cy) > -1 ){
                                    _cy = _cy - 5;
                                    tempList.push(_cy);
                                }else{
                                    tempList.push(_cy);
                                }
                                addTopPadding(_cy);

                                _path += arc1 +"V"+ _cy + arc2 +"H" + (x2-getSidePadding(d.target.id));
                                _path += "H"+(x2)+ getArc(3,3,false,true) +"V"+ (y2) ;

                            }else{
                                //beside
//                                _path += "V"+ (y2);
                                var arc1 = "", arc2 = "", sp = 0;
                                if(Math.abs(y1-y2) > 3){
                                    if(y1 < y2){
                                        arc1 = getArc(3,3,false,true);
                                        arc2 = getArc(2,3,true,true);
                                        sp = 3;
                                    }else{
                                        arc1 = getArc(4,3,false,true);
                                        arc2 = getArc(1,3,false,true);
                                        sp = -3;
                                    }
                                }
                                _path += arc1 +"V"+ ( y2 - sp );
                                if(_cx > (x2-getSidePadding(d.target.id))){
                                    _path += arc2 +"H" + (_cx + Math.abs(sp) + 1);
                                }else{
                                    _path += arc2 +"H" + (x2-getSidePadding(d.target.id) + 4 );
                                }
                                _path += "V"+ y2 +"H"+ x2 ;
                            }
                        }else{
                            if(d.source_resource.y < d.target.y){
                                //left to right source above to the target
                                var cy = d.source_resource.y + d.source_resource.height + _marg;
                                if(cy > (y2 - (_marg/2)-(getSidePadding(d.source_resource.id)*0.1)) ){
                                    cy = (y2 - (_marg/2)-(getSidePadding(d.source_resource.id)*0.1));
                                }
                                _path += getArc(3,3,true,true) +"V"+ cy + "H" + ( x2 );
                                _path += "V"+ (y2 - (_marg/2)-(getSidePadding(d.source_resource.id)*0.1)) + "H"+ x2 + "V"+ y2;
                            }else{
                                //left to right source down to the target
                                var cy = d.source_resource.y - _marg;
                                if(cy < (y2 + (_marg/2)+(getSidePadding(d.source_resource.id)*0.1)) ){
                                    cy = ( y2 + (_marg/2)+(getSidePadding(d.source_resource.id)*0.1));
                                }
                                _path += getArc(4,3,false,true) +"V"+ cy + "H" + ( x2 );// + getSidePadding(d.target.id) );
                                _path += "V"+ y2 ;//+ "H"+x2;
                            }
                        }
                    }else{
                        // right to left
                        if(d.source_resource.y == d.target.y){
                            // same level
                            var arc1 = "", arc2 = "",sp = 0;
                            if(y1 > y2){
                                arc1 = getArc(4,3,false,false);
                                arc2 = getArc(3,3,false,false);
                                sp = -3;
                            }
                            var _cy = (d.source_resource.y - (getSidePadding(d.source_resource.id)*0.5) - sp - (d.extra.count* 2));
                            if(tempList.indexOf(_cy) > -1 ){
                                _cy = _cy - 5;
                                tempList.push(_cy);
                            }else{
                                tempList.push(_cy);

                            }
                            addTopPadding(_cy);
                            _path += arc1 +"V"+ _cy + arc2 +"H" + ( x2 + getSidePadding(d.target.id) );
                            _path += "H"+ x2 +getArc(1,3,true,false)+"V"+ y2 ;

                        }else{
                            if(d.source_resource.y < d.target.y){
                                //right to left source above to the target
                                var cy = d.source_resource.y + d.source_resource.height + _marg;
                                var arc2 = "",arc3 = "";
                                if(cy > (y2 - (_marg/2)-(getSidePadding(d.source_resource.id)*0.1)) ){
                                    cy = (y2 - (_marg/2)-(getSidePadding(d.source_resource.id)*0.1));
                                }
                                var sp = 0;
                                if( _cx > (x2 +_marg + getSidePadding(d.target.id)) ){
                                    arc2 = getArc(4,3,true,true);
                                    arc3 = getArc(1,3,true,true);
                                    sp = 3;
                                }else{
                                    arc2 = getArc(2,3,true,false);
                                    arc3 = getArc(3,3,true,false);
                                    sp = -3;
                                }
//                                _path += getArc(3,3,true,true)+ "V" + ( cy-4 )+ a2 + "H" + ( x2 +_marg + getSidePadding(d.target.id) + 3 );
//                                _path += a3 +"V"+ (y2 - (_marg/2)-(getSidePadding(d.source_resource.id)*0.1) - 3 ) + a2 +"H"+ x2 + a3 + "V"+ y2;

                                _path += getArc(3,3,true,true)+ "V" + cy +"H" + ( x2 +_marg + getSidePadding(d.target.id) + sp );
                                _path += "V"+ (y2 - (_marg/2)-(getSidePadding(d.source_resource.id)*0.1) - 3 ) + "H"+ x2 + getArc(1,3,true,true) +  "V"+ y2;
                            }else{
                                //right to left source down to the target
                                var cy = d.source_resource.y - _marg;
                                if(cy < (y2 + (_marg/2)+(getSidePadding(d.source_resource.id)*0.1)) ){
                                     cy = (y2 + (_marg/2)+(getSidePadding(d.source_resource.id)*0.1));
                                }
                                var arc2 = "",arc3 = "", sp = 0;
                                if( _cx > (x2 +_marg + getSidePadding(d.target.id)) ){
                                    arc2 = getArc(3,3,false,false);
                                    arc3 = getArc(1,3,true,true);
                                    sp = 3;
                                }else{
                                    arc2 = getArc(1,3,false,true);
                                    arc3 = getArc(3,3,true,false);
                                    sp = -3;
                                }

                                _path += getArc(4,3,false,false) +"V"+ cy  + "H" + ( x2 + _marg +getSidePadding(d.target.id) );
                                _path += "V"+ (y2 + (_marg/2)+(getSidePadding(d.source_resource.id)*0.1)) + "H"+ x2 + getArc(2,3,false,false) +"V"+ y2;
                            }
                        }
                    }

                    return _path;
                }

                function getURLPath(link){
                    //nextLink.id = resource.id + "_" + _id;
                    //nextLink.source = binding.matchedSegment;
                    //nextLink.target = binding.matchedFeature;
                    //nextLink.source_resource = resource;
                    //nextLink.segmentBinding = binding;

                    var segment = link.source;
                    var x1 = segment.x + segment.width / 2 - ViewmapUtils.ALL_LABELS_RIGHT_MARGIN / 2;
                    var y1 = segment.y + segment.height + 2;
                    var feature = link.target;
                    var x2 = feature.x - 5;
                    var y2 = feature.y + feature.height / 2;
                    var linkIndex = link.extra.count;
                    var topGap = (linkIndex + 1) * DiagramSpecifics.URI_LINK_VGAP;
                    var leftGap = (linkIndex + 1) * DiagramSpecifics.URI_LINK_HGAP;
                    var resourceX = link.source_resource.x;

                    // sharp types, see getArc
                    /*const*/var FROM_TOP_TO_LEFT = 4;
                    /*const*/var FROM_RIGHT_TO_BOTTOM = 1;
                    /*const*/var FROM_TOP_TO_RIGHT = 2;

                    /*const*/var ARC = 3;

                    return "M" + x1 + "," + y1
                        + "V" + (y1 + topGap - ARC)
                        + getArc(FROM_TOP_TO_LEFT, ARC, true, false)
                        + "H" + (resourceX + leftGap + ARC)
                        + getArc(FROM_RIGHT_TO_BOTTOM, ARC, true, false)
                        + "V" + (y2 - ARC)
                        + getArc(FROM_TOP_TO_RIGHT, ARC, true, true)
                        + "H" + x2
                        ;
                }

                function getResponsePath(d) {
                    // preconditions:
                    // d.source - response
                    // d.target - method
                    var x1 = d.source.x + d.source.width;
                    var y1 = d.source.y + (d.source.height / 2);
                    var x2 = d.target.x + d.target.width + 10;

                    var responsesMinMax = DiagramSpecifics.collectChildrenVerticalMinMax(d.target, function(ch) {
                        return ch.objecttype == 'Response';
                    });
                    var y2 = responsesMinMax ? responsesMinMax.getMiddle() : y1;

                    var arc1 = "", arc2 = "", sp = 0;
                    if (Math.abs(y1 - y2) > 5) {
                        if (y1 < y2) {
                            arc1 = getArc(3, 3, true, true);
                            arc2 = getArc(2, 3, true, true);
                            sp = 3;
                        } else {
                            arc1 = getArc(4, 3, false, true);
                            arc2 = getArc(1, 3, false, true);
                            sp = -3;
                        }
                    }

                    var mid = Math.abs(x2 - x1) / 2;
                    var _path = "M" + x1 + "," + y1 + "H" + (x1 + mid - 6) + arc1 + "V" + (y2 - sp) + arc2 + "H" + x2;
                    return _path;
                }

                function getRequestPath(d){
                    // preconditions:
                    // d.source - method
                    // d.target - request

                    var x1 = d.source.x + d.source.width + 10;
                    var x2 = d.target.x + d.target.width;
                    var y2 = d.target.y + (d.target.height / 2);
                    var y1 = y2;

                    var _path = "M"+x1+","+y1 + "H"+ (x2+margin.right) + "V" + y2 +"H"+x2;
                    return _path;
                }

                function getExternalReferenceLinkPath(d){
                    var _path,x1,x2,y1,y2;
                    x1 = d.source.x + d.source.width;
                    y1 = d.source.y + (d.source.height/2);
                    x2 = d.source.x + d.source.width + 30;
                    if(d.isCollapsed){
                        var _fragment = ( d.source.parent.height / (parseInt (d.total) + 1) );
                        y1 = d.source.parent.y + _fragment +( _fragment * ( parseInt(d.extra.count) ) );
                    }else{
                        y1 = d.source.y + (d.source.height/2);
                    }
                    y2 = y1;
                    var arc1 = "",
                        arc2 = "",
                        sp = 0;

                    if(Math.abs(y1-y2)> 5){
                        if(y1 < y2){
                            arc1 = getArc(3,3,true,true);
                            arc2 = getArc(2,3,true,true);
                            sp = 3;
                        }else{
                            arc1 = getArc(4,3,false,true);
                            arc2 = getArc(1,3,false,true);
                            sp = -3;
                        }
                    }

                    var mid = Math.abs(x2-x1)/2;
                    _path = "M"+ x1 +","+ y1 + "H"+ ( x1 + mid - 6 )+ arc1 + "V" + ( y2 - sp ) + arc2 +"H"+ x2;
                    return _path
                }
/**
 * =====================================================================
 * Init the link object which bind links to svg element
 * Drawing process is divided in 3 part  Enter , Update , Remove
 * - linkEnter ( create the links append it to element to ui )
 * - linkUpdate ( update the link portions according to reflect data, If link is already present then no need to re-render them just update it. )
 * - linkRemove ( if link is no longer exist then remove it from ui )
 *
 * Note - If you change any style attribute at linkEnter make sure that it will not override by linkUpdate
 *        because after linkEnter, linkUpdate will update all the link attributes like path and color (for URI param).
 * ======================================================================
 */
                var link = chartLines.selectAll("g.extraLinks")
                    .data(linkData, function(d) { return d.id || (d.id = ++i); });

                var linkEnter = link.enter().append("svg:g")
                    .attr("class", "extraLinks");

                function dumpPath(d, path) {
                    //switch (d.type) {
                    //    case "URILink":
                    //    case "responseLink":
                    //    case "requestLink":
                    //        return path;
                    //}
                    // console.log("Path for " + d.type + ": " + path);
                    return path;
                }

                linkEnter.each(function(d){
                    d3.select(this)
                        .append("path")
                        .attr("class",function(d){
                            if(d.type == "referenceLink") return "link";
                            if(d.type == "externalReferenceLink") return "externalLink";
                            if(d.type == "responseLink") return "responseLink";
                            if(d.type == "requestLink") return "requestLink";
                            return "urlLinks";
                        })
                        .attr("id", d.id + "-lnk")
                        .attr("marker-end", "url(#arrowhead_rlink)")
                        .attr("marker-start", "url(#markerCircle_rlink)")
                        .attr("d",function(d){
                            var _path = "";
                            if(d.type == "referenceLink"){
                                return dumpPath(d, getComputedPath(d));
                            }
                            if(d.type == "URILink"){
                                return dumpPath(d, getURLPath(d,true));
                            }
                            if(d.type == "responseLink"){
                                return dumpPath(d, getResponsePath(d));
                            }
                            if(d.type == "requestLink"){
                                return dumpPath(d, getRequestPath(d));
                            }
                            if(d.type == "externalReferenceLink"){
                                return dumpPath(d, getExternalReferenceLinkPath(d));
                            }
                            return dumpPath(d, _path);
                        });
                        if(d.type == "referenceLink"){
                            var text = d3.select(this).append("text")
                             .attr("dx",-5)
                             .attr("dy",-3)
                             .append("textPath")
                             .attr("xlink:href","#" + d.id + "-lnk")
                             .style("text-anchor","end")
                             .attr("startOffset","100%")
                             .text(d.cardinality);
                        }
                });

                linkEnter.transition()
                    .duration(transitionDuration)
                    .style("opacity", 0);

//              Update the links with animation effect
                var linkUpdate = link.transition()
                    .duration(transitionDuration)
                    .style("opacity", 1);

                linkUpdate.each(function(d){

                     //responseLink
                    d3.select(this).select(".link").transition()
                        .duration(transitionDuration)
                        .attr("marker-end", "url(#arrowhead_rlink)")
                        .attr("marker-start", "url(#markerCircle_rlink)")
                        .attr("d",function(d){
                            return dumpPath(d, getComputedPath(d));
                        });

                    d3.select(this).select(".externalLink").transition()
                        .duration(transitionDuration)
                        .attr("marker-end", "url(#arrowhead_msg)")
                        .attr("marker-start", "url(#markerCircle_msg)")
                        .attr("d",function(d){
                            return dumpPath(d, getExternalReferenceLinkPath(d));
                        });

                    d3.select(this).select(".urlLinks")
                        .style("stroke",function(d){
                            return resourceUriLinkColors(d.extra.count);
                        })
                        .transition()
                        .duration(transitionDuration)

                        .attr("marker-end", "url(#markerV)")
                        .attr("marker-start", "url(#markerH)")
                        .attr("d",function(d){
                            return dumpPath(d, getURLPath(d,false));
                        });

                    d3.select(this).select(".responseLink").transition()
                        .duration(transitionDuration)
                        .attr("marker-end", "url(#arrowhead_msg)")
                        .attr("marker-start", "url(#markerCircle_msg)")
                        .attr("d",function(d){
                            return dumpPath(d, getResponsePath(d));
                        });

                    d3.select(this).select(".requestLink").transition()
                        .duration(transitionDuration)
                        .attr("marker-end", "url(#arrowhead_msg)")
                        .attr("marker-start", "url(#markerCircle_msg)")
                        .attr("d",function(d){
                            return dumpPath(d, getRequestPath(d));
                        });

                });

//              Exit links
                link.exit().transition()
                    .duration(transitionDuration)
                    .style("opacity", 1e-6)
                    .remove();
            };

            /**
             *  Chart update method called on resize and render
             *  source - selected node.
             *  isResize - is called from resize, Because on resize node may change the position
             * */
            chart.update = function(source,isResize) {
                if(!source) source = root;
                /**
                 * Generate the nodes from data flow will help to generates each node separately from data object.
                 * */
                var nodes = flow(root);
                rootObject = nodes[0];


                /**
                 * function for container color according to data objecttype
                 * */

//                function color(d) {
//                	var light_blue = "#dae8f5";
//                    var blue = "#c6dbef";
//                    var dark_blue = "#b2cfea";
//                    var color = dark_blue;
//                    switch (d.objecttype){
//	                    case "ObjectResource":  case "CollectionResource":
//	                    	color = light_blue;
//	                        break;
//	                    case "DataType":  case "Method":
//	                    	color = blue;
//	                        break;
//	                    default :
//                    }
//
//                    return color;
//                }

                /**
                 * Toggle children on click.
                 * Only allow those element which have child to collapse/expand
                 * */
                function click(d) {
                    if(d != root &&(d.objecttype != "Response" && d.objecttype != "Request")){
                        if (d.children) {
                            d._children = d.children;
                            d.children = null;
                        } else {
                            d.children = d._children;
                            d._children = null;
                        }
                        resize(d,false);
                    }
                }

                function clickSelection(d) {
                    if (d.objecttype === 'Method') {
                        chartChangeSelection(d.parent.id + "." + d.name + "." + d.type, d.objecttype);
                    } else {
                        chartChangeSelection(d.id, d.objecttype);
                    }
                    svg.selectAll('.selected').classed('selected', false);
                    d3.select(this).classed('selected', true);
                }


                /**
                 * First searches children of 'host' for the first matched 'childFilter'.
                 * Only when one is found, executes the 'pathSelector' to find or create a svg:path
                 * and updates its "d" attribute to place the port as follows:
                 * - horizontally: at the right side of the 'host'
                 * - vertically: at the center of the child's visuals.
                 *
                 * @return d3-selection for svg:path or null
                 */
                function relocateRequestResponsePortCenteredAt(host, pathSelector, childFilter) {
                    var minTopMaxBottom = DiagramSpecifics.collectChildrenVerticalMinMax(host, childFilter);
                    if (!minTopMaxBottom) {
                        return null;
                    }

                    var anchorMiddle = minTopMaxBottom.getMiddle();
                    var result = pathSelector()
                        .attr("d", function (d) {
                            var w = 20, h = 15, _r = 3;

                            var x1 = d.width - 1;
                            //we need host-local coordinates since path is child of host' svg:g
                            var anchorMiddleLocal = anchorMiddle - d.y;
                            var y1 = anchorMiddleLocal - h / 2;

                            var path = "M" + x1 + "," + y1
                                + "h" + (w - _r)
                                + "a" + _r + "," + _r + " 0 0 1 " + _r + "," + _r
                                + "v" + (h - 2 * _r)
                                + "a" + _r + "," + _r + " 0 0 1 " + (_r*-1) + "," + _r
                                + "h" + (_r - w);
                            return path;
                        });
                    return result;
                }

                /**
                 * =====================================================================
                 * Init the node object which bind nodes to svg element
                 * Drawing process is divided in 3 part  Enter , Update , Remove
                 * - nodeEnter ( create the node append it to element to ui )
                 * - nodeUpdate ( update the node portions according to reflect data, If link is already present then no need to re-render them just update it. )
                 * - nodeRemove ( if ndoe is no longer exist then remove it from ui )
                 *
                 * Note - If you change any style attribute at nodeEnter make sure that it will not override by nodeUpdate
                 *        because after nodeEnter, nodeUpdate will update all the link attributes like color (for rect container fill).
                 * ======================================================================
                 */

                var node = chartGroup.selectAll("g.node")
                    .data(nodes, function(d) { return d.id || (d.id = ++i); });

                var nodeEnter = node.enter().append("svg:g")
                    .attr("class", "node")
                    .attr("transform", function(d) {
                        return "translate(" + source.x + "," + source.y + ")";
                    })
                    .style("opacity", 1e-6);

                /**
                 * Enter any new nodes at the parent's previous position.
                 * append rectangle to node
                 *
                 * */
                nodeEnter.each(function(d) {
                    /**
                     * return for root node we don't want to show main container.
                     * */
                    if(d == root){
                        return;
                    }
                    /**
                     * Append rectangle for each node
                     * */
                    if (d.children
                            || d._children
                            || d.objecttype == "Response"
                            || d.objecttype == "Request"
                            || d.objecttype == "ReferenceEmbed"
                            || ((d.objecttype == "DataType" || d.objecttype == "ReferenceLink")  && (!d.children && !d._children))) {

                        d3.select(this).append("svg:rect")
                            .attr("anchorId", d.anchorId)
                            .attr("class", DiagramSpecifics.getContainerBackgroundClass)
                            .attr("height", function(d) { return d.height; })
                            .attr("width", function(d) { return d.width; })
                            .attr("rx", 2)
                            .attr("ry", 2);

                            d3.select(this).select('rect.method').on("click", clickSelection);
                            d3.select(this).select('rect.resource').on("click", clickSelection);
                            d3.select(this).select('rect.dataType').on("click", clickSelection);

                        if(d.objecttype == "ReferenceEmbed"){
                            d3.select(this).select('rect').style('fill',function(){
                                   return referenceEmbedColors(d.embedLevel);
                            });
                        }

                        /**
                         *  Add request/response Port on method container
                         * */
                        if(d.objecttype == "Method"){
                            var d3this = d3.select(this);
                            relocateRequestResponsePortCenteredAt(d,
                                function() {
                                    return d3this
                                        .append("path")
                                        .attr("class", "requestPort");
                                },
                                function (f) {
                                    return f.objecttype == "Request";
                                });
                            relocateRequestResponsePortCenteredAt(d,
                                function() {
                                    return d3this
                                        .append("path")
                                        .attr("class", "responsePort");
                                },
                                function (f) {
                                    return f.objecttype == "Response";
                                });
                        }
                    }

                });

                /**
                 * Append header separator, header text , header image of container
                 * */
                nodeEnter.each(function(d) {
                    if(d == root){
                        return;
                    }
                    if (d.children || d._children) {
                        // draw a horizonal line for containers to separate the header and contents
                        if(d.objecttype != "Response" && d.objecttype != "Request" ){
                            //FIXME: revisit, I never seen this line anyway
                            d3.select(this).append("line")
                                .attr("class", "separator")
                                .style("stroke-opacity",function(d){
                                    return d._children ? "0" : "0.5";
                                })
                                .attr("x1","0")
                                .attr("y1",function(d){
                                    if(d.objecttype == "ObjectResource"  || d.objecttype == "CollectionResource")return 30;
                                    return 20;
                                })
                                .attr("x2", function(d){return d.width;})
                                .attr("y2",function(d){
                                    if(d.objecttype == "ObjectResource"  || d.objecttype == "CollectionResource")return 30;
                                    return 20;
                                });

                            d.viewmap.applyToDom(this);

                            var expanderBlock = d3.select(this).select(".expander-group");
                            expanderBlock.attr("pointer-events", "all");

                            expanderBlock.append("rect")
                            	.attr("class", "expander-clicks-capture")
                            	.style("visibility", "hidden")
                                .attr("x", 0)
                                .attr("y", 0)
                                .attr("width", 12)//FIXME: hardcoded value should match the one from viewmap
                                .attr("height", 16)
                            ;

                            expanderBlock.append("path")
                                .attr("class", "expander")
                                .attr("d", "M 0 0 L 6 6 L 0 6 z")
                                .attr("transform", function(d) {
                                    return d._children ? "translate(6,14)rotate(225)" : "translate(5,8)rotate(315)";
                                });
						}

                    } else {
                    	// non-containers
                        d.viewmap.applyToDom(this);
                    }
                });

                /**
                 * Transition nodes to their new position.
                 * */
                nodeEnter.transition()
                    .duration(transitionDuration)
                    .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
                    .style("opacity", 1);

                var nodeUpdate = node.transition()
                    .duration(transitionDuration);

                nodeUpdate.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
                    .style("opacity", 1);

                /**
                 * On update node ( collapse/expand ) change header separator and image
                 * */
                nodeUpdate.each(function(d) {
                    if (d.children || d._children) {
                        d3.select(this).select(".expander-group").on("click", click);
                        d3.select(this).select(".expander").transition()
                            .duration(transitionDuration)
                            .attr("transform", function(d) {
                                //FIXME: translate value depends on insets because we don't have a group
                                return d._children ? "translate(6,14)rotate(225)" : "translate(5,8)rotate(315)";
                            });

                        d3.select(this).select(".separator").transition()
                            .duration(transitionDuration)
                            .style("stroke-opacity",function(d){
                                return d._children ? "0" : "0.5";
                            })
                            .attr("x1","0")
                            .attr("y1",function(d){
                                if(d.objecttype == "ReferenceLink" && d.linkRelation && d.linkRelation.length > 0 )return 30;
                                if(d.objecttype == "ObjectResource" || d.objecttype == "CollectionResource")return 30;
                                return 20;
                            })
                            .attr("x2", function(d){return d.width;})
                            .attr("y2",function(d){
                                if(d.objecttype == "ReferenceLink" && d.linkRelation && d.linkRelation.length > 0 )return 30;
                                if(d.objecttype == "ObjectResource" || d.objecttype == "CollectionResource")return 30;
                                return 20;
                            });

                        var requestPort = d3.select(this).selectAll(".requestPort");
                        requestPort.transition()
                            .duration(transitionDuration)
                            .style("fill-opacity",function(d){
                                return d._children ? 0 : 1;
                            })
                            .style("stroke-width",function(d){
                                return d._children ? "0" : "1.5";
                            })
                            .style("stroke-opacity",function(d){
                                return d._children ? "0" : "0.5";
                            });

                        relocateRequestResponsePortCenteredAt(d,
                            function() {return requestPort; },
                            function(f) { return f.objecttype == "Request"; });

                        var responsePort = d3.select(this).selectAll(".responsePort");
                        responsePort.transition()
                            .duration(transitionDuration)
                            .style("fill-opacity",function(d){
                                return d._children ? 0 : 1;
                            })
                            .style("stroke-width",function(d){
                                return d._children ? "0" : "1.5";
                            })
                            .style("stroke-opacity",function(d){
                                return d._children ? "0" : "0.5";
                            });

                        relocateRequestResponsePortCenteredAt(d,
                            function() {return responsePort; },
                            function(f) { return f.objecttype == "Response"; });
                    }

                });

                nodeUpdate.select(".background")
                    .attr("height", function(d) { return d.height; })
                    .attr("width", function(d) { return d.width; });

                // Transition exiting nodes to the parent's new position.
                node.exit().transition()
                    .duration(transitionDuration)
                    .attr("transform", function(d) { return "translate(" + source.x + "," + source.y + ")"; })
                    .style("opacity", 1e-6)
                    .remove();

                /*
                *  Update Extra links layer when resize will take delay so node take
                *  it's position properly
                * */
                if(isResize){
                    var _this = this;
                    this.updateExtraLinks(nodes);
                    setTimeout(function(){
                        _this.updateExtraLinks(nodes);
                    },transitionDuration);
                }else{
                    this.updateExtraLinks(nodes);
                }

            };

            /**
             * first resize call with all data element
             * */
            resize(root,true); /** First attemp to create chart */
            chart.update(flow.updateNodesFromSettings(root),true);  /** Update chart according to visibility control */
            /**
             * Last resize after everything setup
             * */
            resize(rootObject,false);


        });
    }

    chart.width = function(value) {
        if (!arguments.length) return width;
        width = parseInt(value);
        return this;
    };

    chart.height = function(value) {
        if (!arguments.length) return height;
        height = parseInt(value);
        return this;
    };

    chart.margin = function(_) {
        if (!arguments.length) return margin;
        margin.top    = typeof _.top    != 'undefined' ? _.top    : margin.top;
        margin.right  = typeof _.right  != 'undefined' ? _.right  : margin.right;
        margin.bottom = typeof _.bottom != 'undefined' ? _.bottom : margin.bottom;
        margin.left   = typeof _.left   != 'undefined' ? _.left   : margin.left;
        return chart;
    };

    chart.updateSetting = function(){
        chart.resizeChart(flow.updateNodesFromSettings(root),false);
    };

    return chart;
};




© 2015 - 2025 Weber Informatics LLC | Privacy Policy