Гибкая упакованная пузырьковая диаграмма

Можно ли создать упакованную пузырьковую диаграмму во Flex, как в следующем примере?

пример упакованной пузырьковой диаграммы

Источник: http://blog.tiger.com.pl/wp-content/uploads/2013/06/bubble2.jpg

Я гуглил это и ничего не нашел. Если нет родного способа сделать это, кто-то может подсказать, как я мог бы нарисовать это сам?

1 ответ

Что ж, после поиска и поиска я нашел библиотеку flare, здесь вы можете увидеть пример того, что я искал, в Layout/Bubbles. Но все было сделано в ActionScript 3. Затем я начал создавать свой собственный класс для использования во Flex и получил его. Вот код класса, который я написал.

package classes
{
    import flare.animate.FunctionSequence;
    import flare.animate.Transition;
    import flare.animate.TransitionEvent;
    import flare.animate.Transitioner;
    import flare.display.TextSprite;
    import flare.query.methods.add;
    import flare.query.methods.div;
    import flare.query.methods.mul;
    import flare.util.Shapes;
    import flare.util.Strings;
    import flare.vis.Visualization;
    import flare.vis.controls.DragControl;
    import flare.vis.controls.ExpandControl;
    import flare.vis.controls.HoverControl;
    import flare.vis.controls.IControl;
    import flare.vis.controls.TooltipControl;
    import flare.vis.data.Data;
    import flare.vis.data.DataList;
    import flare.vis.data.DataSprite;
    import flare.vis.data.NodeSprite;
    import flare.vis.events.SelectionEvent;
    import flare.vis.events.TooltipEvent;
    import flare.vis.operator.OperatorSwitch;
    import flare.vis.operator.encoder.PropertyEncoder;
    import flare.vis.operator.label.Labeler;
    import flare.vis.operator.layout.CircleLayout;
    import flare.vis.operator.layout.CirclePackingLayout;
    import flare.vis.operator.layout.DendrogramLayout;
    import flare.vis.operator.layout.ForceDirectedLayout;
    import flare.vis.operator.layout.IcicleTreeLayout;
    import flare.vis.operator.layout.IndentedTreeLayout;
    import flare.vis.operator.layout.Layout;
    import flare.vis.operator.layout.NodeLinkTreeLayout;
    import flare.vis.operator.layout.RadialTreeLayout;

    import flash.display.DisplayObjectContainer;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.text.TextFormat;
    import flash.text.TextFormatAlign;

    import mx.core.Container;
    import mx.core.UIComponent;
    import mx.core.mx_internal;
    import mx.events.ResizeEvent;


    public class PackedBubblesChart extends UIComponent {
        public static const DEFAULT_FLEX_SERIES_COLORS:Array = [
            0xe48701, 0xa5bc4e, 0x1b95d9, 0xcaca9e,
            0x6693b0, 0xf05e27, 0x86d1e4, 0xe4f9a0,
            0xffd512, 0x75b000, 0x0662b0, 0xede8c6,
            0xcc3300, 0xd1dfe7, 0x52d4ca, 0xc5e05d,
            0xe7c174, 0xfff797, 0xc5f68f, 0xbdf1e6,
            0x9e987d, 0xeb988d, 0x91c9e5, 0x93dc4a,
            0xffb900, 0x9ebbcd, 0x009797, 0x0db2c2
        ];
        // Constructor
        public function PackedBubblesChart() {
            addEventListener(Event.ADDED_TO_STAGE, addedToStage);
            addEventListener(Event.REMOVED_FROM_STAGE, removedFromStage);
        }

        protected function addedToStage(event: Event) : void {          
            (this.parent as Container).addEventListener(ResizeEvent.RESIZE, resizeBubbleChart);
            tryRender();
        }

        protected function removedFromStage(event: Event) : void {          
            clearNodes();
            (this.parent as Container).removeEventListener(ResizeEvent.RESIZE, resizeBubbleChart);          
        }

        protected function clearNodes() : void {
            if(vis) {
                for each(var sprite : DataSprite in _nodesInformation.nodes) {                  
                    sprite.parent.removeChild(sprite);                  
                }
                vis = null;                 
            }
        }

        protected function resizeBubbleChart(event:ResizeEvent) : void {
            _bounds = new Rectangle(0, 0, parent.width, parent.height);
            tryRender();
        }

        private var _init:Boolean = false;
        private var _bounds:Rectangle;

        public var labelField : String = "label";
        public var valueField : String = "value";

        public function get bounds():Rectangle { return _bounds; }
        public function set bounds(b:Rectangle):void {
            _bounds = b;
            resize();
        }

        private var _dataProvider : Array = [];
        private var _nodesInformation : Data = new Data();
        private var _nodeDefaultFormat : Object = 
            {
                name: "Bubbles",
                op: new CirclePackingLayout(8, false, "depth"),
                nodes:{
                        shape: Shapes.CIRCLE,
                        fillColor: 0x11aaaaaa,
                        lineColor: 0xdddddddd,
                        lineWidth: 4,                               
                        alpha: 1,
                        visible: true               
                },
                edges: {alpha:0, visible:false},
                ctrl: new DragControl(NodeSprite),
                canStraighten: true
            }

        public function get dataProvider() : Array {
            return _dataProvider;
        }

        public function set dataProvider(info : Array) : void {
            /*
            if(vis && _dataProvider && _dataProvider.length > 0) {
                for each(var sprite : DataSprite in _nodesInformation.nodes) {                  
                    sprite.parent.removeChild(sprite);                  
                }
                vis = null;
            }
            */
            _dataProvider = info;
            tryRender();
        }

        protected function tryRender() : void {
            if(parent) _bounds = new Rectangle(0,0,parent.width, parent.height);
            if(_dataProvider && _dataProvider.length > 0 && _bounds) {
                clearNodes();
                _nodesInformation = createNodes(_dataProvider.length);
                _nodesInformation.nodes.setProperties(_nodeDefaultFormat.nodes);
                var index : uint = 0;
                for each(var item : Object in _dataProvider) {
                    var labelText : String = item[labelField];
                    var valueNumber : Number = item[valueField];
                    _nodesInformation.nodes[index].data.label = labelText;
                    _nodesInformation.nodes[index].buttonMode = true;
                    _nodesInformation.nodes[index].size = item[valueField];
                    _nodesInformation.nodes[index].props.value = valueNumber;
                    _nodesInformation.nodes[index].props.name =labelText;
                    _nodesInformation.nodes[index].props.name_value = labelText+"\n("+valueNumber+")";
                    _nodesInformation.nodes[index].fillColor =  0xff000000 + DEFAULT_FLEX_SERIES_COLORS[index % 28];
                    index++;
                }
                _nodesInformation.nodes.sortBy("props.value");

                // create the visualization
                vis = new Visualization(_nodesInformation);
                vis.bounds = bounds;
                vis.operators.add(_nodeDefaultFormat.op);
                vis.setOperator("nodes", new PropertyEncoder(_nodeDefaultFormat.nodes, "nodes"));                        
                vis.operators.add(new Labeler("props.name_value", Data.NODES,new TextFormat("Arial",12,0,true,null,null,null,null, TextFormatAlign.CENTER),null));
                vis.controls.add(new TooltipControl(DataSprite, null,
                    function(evt:TooltipEvent):void {
                        var d:DataSprite = evt.node;                    
                        TextSprite(evt.tooltip).htmlText = Strings.format(_tipText, d.props.name, d.props.value);
                    }
                ));
                init();
            }           
        }
        public static function createNodes(n:uint):Data {
            var g:Data = new Data();
            for (var i:uint=0; i < n; i++) {
                var node:NodeSprite = g.addNode();
                node.data.label = String(i);
            }
            return g;
        }

        public function set toolTipFormat(value : String) : void {
            _tipText = value;
        }
        private var _tipText:String = "<b>Label</b>: {0}<br/><b>Value</b>: {1}";

        private var vis:Visualization;
        private var os:OperatorSwitch;
        private var shape:String = null;

        public function init():void {           
            vis.controls.add(new HoverControl(NodeSprite,
                // by default, move highlighted items to front
                HoverControl.MOVE_AND_RETURN,
                // highlight node border on mouse over
                function(e:SelectionEvent):void {
                    e.node.lineWidth = 10;
                    e.node.lineColor = 0x88ff0000;
                },
                // remove highlight on mouse out
                function(e:SelectionEvent):void {
                    e.node.lineWidth = 4;
                    e.node.lineColor = _nodeDefaultFormat.nodes.lineColor;
                }));

            vis.controls.add(_nodeDefaultFormat.ctrl);
            vis.update();
            addChild(vis);
        }

        public function resize():void
        {
            if (vis) {
                vis.bounds = bounds;
                vis.update();
            }
        }

    }
}

И вот пример приложения того, что использовать его в Flex

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                minWidth="955" minHeight="600" creationComplete="init(event)" layout="vertical"
                verticalAlign="middle">
    <mx:Script>
        <![CDATA[
            import classes.PackedBubblesChart;

            import mx.events.FlexEvent;
            import mx.events.ResizeEvent;
            protected var companies : Array = [];
            protected var otherCompanies : Array = [];

            protected var bubbleChart : PackedBubblesChart = new PackedBubblesChart();
            protected function init(event:FlexEvent):void {
                companies.push({company_name:"Sunray Management Group", count:92});
                companies.push({company_name:"Chevron", count:145});
                companies.push({company_name:"Nabors", count:35});
                companies.push({company_name:"Milicom", count:23});
                companies.push({company_name:"gNostos", count:200});
                companies.push({company_name:"Cisco", count:43});
                otherCompanies.push({company_name:"Chevron", count:145});
                otherCompanies.push({company_name:"Nabors", count:35});
                otherCompanies.push({company_name:"Milicom", count:23});
                otherCompanies.push({company_name:"gNostos", count:200});
                companies.push({company_name:"Sunray Management Group", count:92});
                companies.push({company_name:"Chevron", count:145});
                companies.push({company_name:"Nabors", count:35});
                companies.push({company_name:"Milicom", count:23});
                companies.push({company_name:"gNostos", count:200});
                companies.push({company_name:"Cisco", count:43});
                otherCompanies.push({company_name:"Chevron", count:145});
                otherCompanies.push({company_name:"Nabors", count:35});
                otherCompanies.push({company_name:"Milicom", count:23});
                otherCompanies.push({company_name:"gNostos", count:200});
                companies.push({company_name:"Sunray Management Group", count:92});
                companies.push({company_name:"Chevron", count:145});
                companies.push({company_name:"Nabors", count:35});
                companies.push({company_name:"Milicom", count:23});
                companies.push({company_name:"gNostos", count:200});
                companies.push({company_name:"Cisco", count:43});
                otherCompanies.push({company_name:"Chevron", count:145});
                otherCompanies.push({company_name:"Nabors", count:35});
                otherCompanies.push({company_name:"Milicom", count:23});
                otherCompanies.push({company_name:"gNostos", count:200});
                companies.push({company_name:"Sunray Management Group", count:92});
                companies.push({company_name:"Chevron", count:145});
                companies.push({company_name:"Nabors", count:35});
                companies.push({company_name:"Milicom", count:23});
                companies.push({company_name:"gNostos", count:200});
                companies.push({company_name:"Cisco", count:43});
                otherCompanies.push({company_name:"Chevron", count:145});
                otherCompanies.push({company_name:"Nabors", count:35});
                otherCompanies.push({company_name:"Milicom", count:23});
                otherCompanies.push({company_name:"gNostos", count:200});

                bubbleChart.labelField = "company_name";
                bubbleChart.valueField = "count";
                bubbleChart.toolTipFormat = "<b>Company</b>: {0}<br/><b>Count</b>: {1}";
                bubbleChart.dataProvider = companies;
                canvas.addChild(bubbleChart);
            }

            protected function button_clickHandler(event:MouseEvent):void {             
                if(bubbleChart.dataProvider == companies) bubbleChart.dataProvider  = otherCompanies;
                else bubbleChart.dataProvider  = companies;
            }

        ]]>
    </mx:Script>
    <mx:Canvas id="canvas" width="100%" height="100%">

    </mx:Canvas>
    <mx:Button label="New data provider" click="button_clickHandler(event)"/>

</mx:Application>

Ну, я отвечаю на свой вопрос, потому что думаю, что это может быть полезно для других людей. Извините за мой английский.

это был результат... Ах, Бьютифул. Спасибо Flare людям.

Другие вопросы по тегам