2

自定义小部件的 PDF 导出不适用于 icCube 报告。服务器引擎版本为 5.0.3,报告为 5.0.3 (6:2163)。

我们在日志中没有看到任何错误消息,该过程仍然停留在 Monitoring -> Active Requests 选项卡中。

包含的报告基于 icCube 演示销售模式。

小部件代码:

FishboneChart.js:

test = {
    module : {}
}

test.module.FishboneChart = (function (_super) {

    __extends(FishboneChart, _super);

    function FishboneChart(container, options) {
        _super.call(this, container, options);

        this.options = options;
        this.container = container;

        var chartContainer = $("<div class='ic3w-fishbone-chart'></div>");
        var contentContainer = $("<div class='ic3w-fishbone-chart-content'></div>");

        var ct = $(this.container);
        ct.append(chartContainer);
        chartContainer.append(contentContainer);
    };

    $.extend(FishboneChart.prototype, {

        buildInHtml : function (gviTable) {

            var chartData = buildChartDataJson(gviTable);
            renderFishboneChart(chartData);
        }
    });

    return FishboneChart;

})(viz.GviChartBase);

test.module.FishboneChartAdapterFactory = (function (_super) {
    __extends(FishboneChartAdapterFactory, _super);

    function FishboneChartAdapterFactory() {
        _super.call(this, "test.module.FishboneChartAdapter");
    }

    FishboneChartAdapterFactory.prototype.getId = function () {
        return 'testFishboneChart';
    };

    FishboneChartAdapterFactory.prototype.getMenuGroupName = function () {
        return "testMenu"
    };

    FishboneChartAdapterFactory.prototype.getTag = function () {
        return "testFishboneChart"
    };

    return FishboneChartAdapterFactory;

})(ic3.WidgetAdapterFactory);

test.module.FishboneChartAdapter = (function (_super) {
    __extends(FishboneChartAdapter, _super);

    function FishboneChartAdapter(context) {
        _super.call(this, context);

        this.classID = "test.module.FishboneChartAdapter";
    }

    FishboneChartAdapter.prototype.reportTypeName = function () {
        return 'Test fishbone-chart';
    };

    FishboneChartAdapter.prototype.getWidgetGroupName = function() {
        return 'chart';
    };

    FishboneChartAdapter.prototype.getNameForCssClass  = function() {
        return 'test-chart';
    };

    FishboneChartAdapter.prototype.gutsMeta = function () {
        return [
            {
                name: 'title',
                type: 'text'
            }
        ]
    };

    FishboneChartAdapter.prototype.createWidget = function (options, container) {
        return new test.module.FishboneChart(container, options);
    };

    return FishboneChartAdapter;

})(ic3.ChartAdapter);


var initializeFishbone = function(d3){
    "use strict";
    d3.fishbone = function(){

        var _margin = 50,
            _marginRoot = 20,
            _marginTail = 100,
            _marginTop = 30,
            _nodes,
            _links,
            _node,
            _link,
            _root,
            _arrowId = function(d){ return "arrow"; },
            _children = function(d){ return d.children; },
            _label = function(d){ return d.name; },
            _perNodeTick = function(d){},
            _linkScale = d3.scale.log()
                .domain([1, 5])
                .range([20, 10]),
            _chartSize = getChartSize(),
            _force = d3.layout.force()
                .gravity(0)
                .size([
                    _chartSize.width,
                    _chartSize.height
                ])
                .linkDistance(_linkDistance)
                .chargeDistance([10])
                .on("tick", _tick);

        var fb1 = function($){

            _links = [];
            _nodes = [];

            _build_nodes($.datum());

            _force
                .nodes(_nodes)
                .links(_links);

            _link = $.selectAll(".link")
                .data(_links);

            _link.enter().append("line");

            _link
                .attr({
                    "class": function(d){ return "link link-" + d.depth; },
                    "marker-end": function(d){
                        return d.arrow ? "url(#" + _arrowId(d) + ")" : null;
                    }
                });

            _link.exit().remove();

            _node = $.selectAll(".node").data(_nodes);
            _node.enter().append("g")
                .attr({
                    "class": function(d){ return "node" + (d.root ? " root" : ""); }
                })
                .append("text");

            _node.select("text")
                .attr({
                    "class": function(d){ return "label-" + d.depth; },
                    "text-anchor": function(d){
                        return !d.depth ? "start" : d.horizontal ? "end" : "middle";
                    },
                    dy: function(d){
                        return d.horizontal ? ".35em" : d.region === 1 ? "1em" : "-.2em";
                    }
                })
                .text(_label);

            _node.exit().remove();
            _node
                .call(_force.drag)
                .on("mousedown", function(){ d3.event.stopPropagation(); });

            _root = $.select(".root").node();
        };

        function _arrow($){
            var defs = $.selectAll("defs").data([1]);

            defs.enter().append("defs");
            defs.selectAll("marker#" + _arrowId())
                .data([1])
                .enter().append("marker")
                .attr({
                    id: _arrowId(),
                    viewBox: "0 -5 10 10",
                    refX: 10,
                    refY: 0,
                    markerWidth: 10,
                    markerHeight: 10,
                    orient: "auto"
                })
                .append("path")
                .attr({d: "M0,-5L10,0L0,5"});
        }

        function _build_nodes(node){

            _nodes.push(node);

            var cx = 0;
            var between = [node, node.connector],
                nodeLinks = [{
                    source: node,
                    target: node.connector,
                    arrow: true,
                    depth: node.depth || 0
                }],
                prev,
                childLinkCount;

            if(!node.parent){
                _nodes.push(prev = {tail: true});
                between = [prev, node];
                nodeLinks[0].source = prev;
                nodeLinks[0].target = node;
                node.horizontal = true;
                node.vertical = false;
                node.depth = 0;
                node.root = true;
                node.totalLinks = []
            }else{
                node.connector.maxChildIdx = 0;
                node.connector.totalLinks = [];
            }

            node.linkCount = 1;

            (_children(node) || []).forEach(function(child, idx){
                child.parent = node;
                child.depth = (node.depth || 0) + 1;
                child.childIdx = idx;
                child.region = node.region ? node.region : (idx & 1 ? 1 : -1);
                child.horizontal = !node.horizontal;
                child.vertical = !node.vertical;

                if(node.root && prev && !prev.tail){
                    _nodes.push(child.connector = {
                        between: between,
                        childIdx: prev.childIdx
                    })
                    prev = null;
                }else{
                    _nodes.push(prev = child.connector = {between: between, childIdx: cx++});
                }

                nodeLinks.push({
                    source: child,
                    target: child.connector,
                    depth: child.depth
                });

                childLinkCount = _build_nodes(child);
                node.linkCount += childLinkCount;
                between[1].totalLinks.push(childLinkCount);
            });

            between[1].maxChildIdx = cx;

            Array.prototype.unshift.apply(_links, nodeLinks);

            return node.linkCount;
        }


        function _linePosition($){
            $.attr({
                x1: function(d){ return d.source.x; },
                y1: function(d){ return d.source.y; },
                x2: function(d){ return d.target.x; },
                y2: function(d){ return d.target.y; }
            })
        }


        function _nodePosition($){
            $.attr("transform", function(d){
                return "translate(" + d.x + "," + d.y + ")";
            })
        }


        function _linkDistance(d){
            return (d.target.maxChildIdx + 1) * _linkScale(d.depth === 0 ? 1 : d.depth);
        }


        function _tick(e){

            var k = 6 * e.alpha,
                size = _force.size(),
                width = size[0],
                height = size[1],
                a,
                b;

            _nodes.forEach(function(d){
                if(d.root){ d.x = width - (_marginRoot + _root.getBBox().width); }
                if(d.tail){ d.x = _marginTail; d.y = height / 2; }

                if(d.depth === 1){
                    d.y = d.region === -1 ? _marginTop : (height - _marginTop);
                    d.x -= 10 * k;
                }

                if(d.vertical){ d.y += k * d.region; }

                if(d.depth){ d.x -= k; }

                if(d.between){
                    a = d.between[0];
                    b = d.between[1];

                    d.x = b.x - (1 + d.childIdx) * (b.x - a.x) / (b.maxChildIdx + 1);
                    d.y = b.y - (1 + d.childIdx) * (b.y - a.y) / (b.maxChildIdx + 1);
                }

                _perNodeTick(d);
            });

            _node.call(_nodePosition);
            _link.call(_linePosition);
        }

        fb1.links = function(){ return _links; };
        fb1.nodes = function(){ return _nodes; };
        fb1.force = function(){ return _force; };

        fb1.defaultArrow = _arrow;

        fb1.margin = function(_){
            if(!arguments.length){ return _margin; }
            _margin = _;
            return my;
        };

        fb1.children = function(_){
            if(!arguments.length){ return _children; }
            _children = _;
            return my;
        };

        fb1.label = function(_){
            if(!arguments.length){ return _label; }
            _label = _;
            return my;
        };

        fb1.perNodeTick = function(_){
            if(!arguments.length){ return _perNodeTick; }
            _perNodeTick = _;
            return my;
        };

        return fb1;
    };
};

var getChartSize = function() {
    var chart = $('.ic3w-fishbone-chart');
    return {
        width : chart.width() || 0,
        height : chart.height() || 0
    };
};

var renderFishboneChart = function(chartData) {

    if (!d3.fishbone) {
        initializeFishbone(d3);
    }

    d3.selectAll('.ic3w-fishbone-chart-content svg').remove();

    var fishbone = d3.fishbone();
    d3.select('.ic3w-fishbone-chart-content')
        .append("svg")
        .attr(getChartSize())
        .datum(chartData)
        .call(fishbone.defaultArrow)
        .call(fishbone);

    fishbone.force().start();
};

var buildChartDataJson = function(gviTable) {

    var rowCount = gviTable.getRowCount();
    var colCount = gviTable.getColumnCount();

    var currentLevel, levelDepthStr;
    var currentBranch = [];
    for (var i = 0; i < colCount; i++) {
        levelDepthStr = gviTable.getPropertyForColumnHeader(i, 0, "a_ld");
        currentLevel = parseInt(levelDepthStr);

        if (!isNaN(currentLevel)) {

            var currentEl = {
                name: gviTable.getColumnLabel(i),
                children: []
            };

            if (currentLevel <= currentBranch.length - 1) {
                removeElements(currentBranch, currentLevel);
            }

            currentBranch[currentLevel] = currentEl;

            if (currentLevel != 0) {
                var parent = currentBranch[currentLevel - 1];
                parent.children.push(currentEl);
            }
        }
    }

    return currentBranch.length > 0 ? currentBranch[0] : {};
};

var removeElements = function(array, targetLength) {

    if (array) {
        while (array.length > targetLength) {
            array.pop();
        }
    }
};

FishBonePlugin.js:

ic3globals.plugins.push(
{
    name: "Fishbone Chart",

    loadCSS: function (options) {
        var root = options.rootLocal + "plugins/";
        ic3css(root + 'Fishbone.css');
    },

    loadJS: function (options) {
        var root = options.rootLocal + "plugins/";

        var deps = ['FishboneChart'];

        $script(root + 'FishboneChart.js', deps[0]);

        $script.ready(deps, function () { /* asynchronous callback */
            options.callback && options.callback();
        });

    },

    registerWidgetFactories: function (manager) {
        manager.addWidgetFactory(new test.module.FishboneChartAdapterFactory());
    },

    registerBabylonTags: function (babylon) {
    }
});

鱼骨.css:

.ic3w-fishbone-chart {
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

.ic3w-fishbone-chart-content *{
    font-family: "Gill Sans", "Gill Sans MT";
}


.ic3w-fishbone-chart-content .label-0 {
    font-size: 2em;
}

.ic3w-fishbone-chart-content .label-1 {
    font-size: 1.5em;
    fill: #111;
}

.ic3w-fishbone-chart-content .label-2 {
    font-size: 1em;
    fill: #444;
}

.ic3w-fishbone-chart-content .label-3 {
    font-size: .9em;
    fill: #888;
}

.ic3w-fishbone-chart-content .label-4 {
    font-size: .8em;
    fill: #aaa;
}

.ic3w-fishbone-chart-content .link-0 {
    stroke: #000;
    stroke-width: 2px;
}

.ic3w-fishbone-chart-content .link-1 {
    stroke: #333;
    stroke-width: 1px;
}

.ic3w-fishbone-chart-content .link-2, .ic3w-fishbone-chart-content .link-3, .ic3w-fishbone-chart-content .link-4 {
    stroke: #666;
    stroke-width: .5px;
}

报告代码:

{"classID":"ic3.ReportGuts","guts_":{"ic3Version":13,"schemaName":"Sales","cubeName":"Sales","layout":{"classID":"ic3.FixedLayout","guts_":{"ic3Version":13,"grid":10,"boxes":[{"classID":"ic3.FixedLayoutBox","guts_":{"ic3Version":13,"header":"widget-0 ( widgetGroup.testMenu/testFishboneChart )","behaviour":"Fixed Box","noPrint":false,"position":{"top":0,"left":170,"width":1380,"height":820},"widgetAdapterUid":"w1","zIndex":2001,"ic3_uid":"ic3-164"}}]}},"widgetMgr":{"classID":"ic3.WidgetAdapterContainerMgr","guts_":{"ic3Version":13,"items":[{"classID":"test.module.FishboneChartAdapter","guts_":{"ic3Version":13,"navigationGuts":{"classID":"ic3.NavigationStrategy","guts_":{"ic3Version":13,"menuVisibility":{"back":true,"axisXChange":"All","axisYChange":"All","filter":"All","reset":true,"widget":true,"others":"All"},"maxAxisMemberCount":25}},"ic3_name":"widget-0","ic3_uid":"w1","ic3_eventMapper":{"classID":"ic3.EventWidgetMapper","guts_":{"__ic3_widgetEventsDescription":{}}},"ic3_mdxBuilderUid":"m1","__ic3_widgetTypeName":"widgetGroup.testMenu/testFishboneChart"}}]}},"constantMgr":{"classID":"ic3.ConstantsMgr","guts_":{"ic3Version":13}},"cssMgr":{"classID":"ic3.CssMgr","guts_":{}},"javascriptMgr":{"classID":"ic3.ReportJavascriptMgr","guts_":{"ic3Version":13,"js":"/**                                                                      \n * A function called each time an event is generated.                    \n *                                                                       \n * @param context the same object is passed between consumeEvent calls.  \n *                Can be used to store information.                      \n *        {                                                              \n *          $report   : jQuery context of the report container           \n *          fireEvent : a function( name, value ) triggering an event    \n *        }                                                              \n *                                                                       \n * @param event the event information                                    \n *                                                                       \n          {                                                              \n *          name  : as specified in the 'Events' tab                     \n *          value : (optional) actual event value                        \n *          type  : (optional) e.g., ic3selection                        \n *        }                                                              \n *                                                                       \n * Check the 'Report Event Names' menu for the list of available events. \n */                                                                      \n                                                                       \nfunction consumeEvent( context, event ) {                                \n  if (event.name == 'ic3-report-init') {                                 \n      \n      ic3globals.plugins.push(\n        {\n            name: \"Fishbone Chart\",\n\n            loadCSS: function (options) {\n            },\n\n            loadJS: function (options) {\n            },\n\n            registerWidgetFactories: function (manager) {\n                console.log('korte1');\n                manager.addWidgetFactory(new test.module.FishboneChartAdapterFactory());\n            },\n\n            registerBabylonTags: function (babylon) {\n            }\n        });\n  }                                                                      \n}"}},"calcMeasureMgr":{"classID":"ic3.CalcMeasureMgr","guts_":{"measures":[]}},"mdxQueriesMgr":{"classID":"ic3.MdxQueriesContainerMgr","guts_":{"mdxQueries":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[{"classID":"ic3.QueryBuilderWidget","guts_":{"mdxWizard":{"classID":"ic3.QueryBuilderWizardForm","guts_":{"rows":[],"cols":[{"classID":"ic3.QueryBuilderHierarchyForm","guts_":{"hierarchy":{"name":"Geography","uniqueName":"[Customers].[Geography]"},"type":"membersOf","membersOf":"all members"}}],"filters":[],"nonEmptyOnRows":false,"nonEmptyOnColumns":false}},"mdxFlat":{"classID":"ic3.QueryBuilderFlatMdxForm","guts_":{"useMdxStatement":false}},"ic3_name":"mdx Query-0","ic3_uid":"m1"}}]}},"mdxFilter":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[]}},"actionBuilders":{"classID":"ic3.BaseContainerMgr","guts_":{"ic3Version":13,"items":[]}}}}}}

谢谢,巴林特·鲁萨

4

1 回答 1

0
  1. 小部件适配器代码需要两个额外的功能(内部错误的解决方法):

    FishboneChartAdapter.prototype.hasNavigation = function()
    {
        return false;
    };
    
    FishboneChartAdapter.prototype.getNavigationMenuItems = function()
    {
        return [];
    };  
    
  2. isRendered应该修改方法,因为图表的布局是动态计算的。我建议使用简单setTimeout到启发式超时,但您可以实施自定义检查。

鱼骨图:

    test.module.FishboneChart = (function (_super) {

        __extends(FishboneChart, _super);

        function FishboneChart(container, options) {
            _super.call(this, container, options);

            this.options = options;
            this.container = container;
            this.rendered = false;

            var chartContainer = $("<div class='ic3w-fishbone-chart'></div>");
            var contentContainer = $("<div class='ic3w-fishbone-chart-content'></div>");

            var ct = $(this.container);
            ct.append(chartContainer);
            chartContainer.append(contentContainer);
        };

        $.extend(FishboneChart.prototype, {

            buildInHtml: function (gviTable) {

                var chartData = buildChartDataJson(gviTable);
                renderFishboneChart(chartData);

                var self = this;
                // wait until layout is stabilized
                setTimeout(function(){self.rendered = true;}, 10000);
            },
            isRendered: function () {
                return this.rendered;
            }
        });

        return FishboneChart;

    })(viz.GviChartBase);
于 2015-10-09T16:37:16.880 回答