From: Jordan Augé Date: Tue, 3 Dec 2013 16:35:05 +0000 (+0100) Subject: added draft maddash plugin X-Git-Tag: myslice-0.3-0~96^2~1 X-Git-Url: http://git.onelab.eu/?p=myslice.git;a=commitdiff_plain;h=0feaf648c801631483b4889b7b00c1d6b01fb253 added draft maddash plugin --- diff --git a/plugins/maddash/__init__.py b/plugins/maddash/__init__.py new file mode 100644 index 00000000..0447ff4d --- /dev/null +++ b/plugins/maddash/__init__.py @@ -0,0 +1,40 @@ +from unfold.plugin import Plugin + +class MadDash (Plugin): + + # set checkboxes if a final column with checkboxes is desired + # pass columns as the initial set of columns + # if None then this is taken from the query's fields + # latitude,longitude, zoom : the starting point + def __init__ (self, query = None, query_all = None, **settings): + Plugin.__init__ (self, **settings) + self.query=query + self.query_all = query_all + self.query_all_uuid = query_all.query_uuid if query_all else None + + def template_file (self): + return "maddash.html" + + def template_env (self, request): + env={} + return env + + def requirements (self): + reqs = { + 'js_files' : [ + 'http://d3js.org/d3.v3.min.js', + 'js/jquery.tipsy.js', + 'js/buffer.js', 'js/maddash.js', + 'js/manifold.js', 'js/manifold-query.js', + 'js/spin.presets.js', 'js/spin.min.js', 'js/jquery.spin.js', + 'js/unfold-helper.js', + ], + 'css_files' : [ + 'css/maddash.css', + 'css/tipsy.css', + ], + } + return reqs + + # the list of things passed to the js plugin + def json_settings_list (self): return ['plugin_uuid','query_uuid', 'query_all_uuid'] diff --git a/plugins/maddash/static/css/maddash.css b/plugins/maddash/static/css/maddash.css new file mode 100644 index 00000000..93ece291 --- /dev/null +++ b/plugins/maddash/static/css/maddash.css @@ -0,0 +1,37 @@ +#maddash__maddash { + height: 600px; +} + +.grid-container{float:left;overflow:hidden;margin-right:10px;} +.gcol{position:absolute;top:0px;} +.gactive{background:#3c3c3c; fill:#3c3c3c} +.grow{overflow:hidden;clear:both;z-index:1;position:relative;} +.grow-heading{float:left;margin:1px 0px;} +.gtext{font-family:verdana;font-size:10px;fill:#242424} +.gactive .gtext {fill:#fff;font-size:11px;} +.gcell{float:left;cursor:pointer;background:none;} +.shadow { +/* -moz-box-shadow: 0 0 30px 5px #000; + -webkit-box-shadow: 0 0 30px 5px #000; +*/ border:1px solid #fff; +} +.ggrid{float:left;position:relative;} +.gleft{float:left;clear:both} +.gtop{} +.gsubcell{float:left;} +rect{fill:none;} +.tooltip{text-align:left;font-size:12px;} +.tooltip .top-tip{padding-bottom:2px;border-bottom:1px solid #fff} +.tooltip .bottom-tip{padding-top:2px;} +.legends{ + background-color:#fff7fb; + border:1px solid #d0d1e6; + margin: 5px 5px 5px 5px; + font-size:11px; + float: left; + min-width: 97%; + +} +.legend{float:left;margin: 4px 10px 4px 10px;} +.lsymbol{float:left;width:13px;height:13px;margin-right:3px;} +.ltext{float:left;line-height:13px;font-style:normal;color:#252525} diff --git a/plugins/maddash/static/css/tipsy.css b/plugins/maddash/static/css/tipsy.css new file mode 100644 index 00000000..ae04cd9c --- /dev/null +++ b/plugins/maddash/static/css/tipsy.css @@ -0,0 +1,12 @@ +.tipsy { padding: 5px; font-size: 10px; position: absolute; z-index: 100000; } + .tipsy-inner { padding: 5px 8px 4px 8px; background-color: #3c3c3c; color: white; max-width: 200px; text-align: center;} + .tipsy-inner { border-radius: 3px; -moz-border-radius:3px; -webkit-border-radius:3px; } + .tipsy-arrow { position: absolute; background: url('tipsy.gif') no-repeat top left; width: 9px; height: 5px; } + .tipsy-n .tipsy-arrow { top: 0; left: 50%; margin-left: -4px; } + .tipsy-nw .tipsy-arrow { top: 0; left: 10px; } + .tipsy-ne .tipsy-arrow { top: 0; right: 10px; } + .tipsy-s .tipsy-arrow { bottom: 0; left: 50%; margin-left: -4px; background-position: bottom left; } + .tipsy-sw .tipsy-arrow { bottom: 0; left: 10px; background-position: bottom left; } + .tipsy-se .tipsy-arrow { bottom: 0; right: 10px; background-position: bottom left; } + .tipsy-e .tipsy-arrow { top: 50%; margin-top: -4px; right: 0; width: 5px; height: 9px; background-position: top right; } + .tipsy-w .tipsy-arrow { top: 50%; margin-top: -4px; left: 0; width: 5px; height: 9px; } \ No newline at end of file diff --git a/plugins/maddash/static/img/tipsy.gif b/plugins/maddash/static/img/tipsy.gif new file mode 100644 index 00000000..74eebae2 Binary files /dev/null and b/plugins/maddash/static/img/tipsy.gif differ diff --git a/plugins/maddash/static/js/.maddash.js.swp b/plugins/maddash/static/js/.maddash.js.swp new file mode 100644 index 00000000..e8559a97 Binary files /dev/null and b/plugins/maddash/static/js/.maddash.js.swp differ diff --git a/plugins/maddash/static/js/jquery.tipsy.js b/plugins/maddash/static/js/jquery.tipsy.js new file mode 100644 index 00000000..2eb567a3 --- /dev/null +++ b/plugins/maddash/static/js/jquery.tipsy.js @@ -0,0 +1,198 @@ +// tipsy, facebook style tooltips for jquery +// version 1.0.0a +// (c) 2008-2010 jason frame [jason@onehackoranother.com] +// releated under the MIT license + +(function($) { + + function fixTitle($ele) { + if ($ele.attr('title') || typeof($ele.attr('original-title')) != 'string') { + $ele.attr('original-title', $ele.attr('title') || '').removeAttr('title'); + } + } + + function Tipsy(element, options) { + this.$element = $(element); + this.options = options; + this.enabled = true; + fixTitle(this.$element); + } + + Tipsy.prototype = { + show: function() { + var title = this.getTitle(); + if (title && this.enabled) { + var $tip = this.tip(); + + $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title); + $tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity + $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body); + + var pos = $.extend({}, this.$element.offset(), { + width: this.$element[0].offsetWidth, + height: this.$element[0].offsetHeight + }); + + var actualWidth = $tip[0].offsetWidth, actualHeight = $tip[0].offsetHeight; + var gravity = (typeof this.options.gravity == 'function') + ? this.options.gravity.call(this.$element[0]) + : this.options.gravity; + + var tp; + switch (gravity.charAt(0)) { + case 'n': + tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}; + break; + case 's': + tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2}; + break; + case 'e': + tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset}; + break; + case 'w': + tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset}; + break; + } + + if (gravity.length == 2) { + if (gravity.charAt(1) == 'w') { + tp.left = pos.left + pos.width / 2 - 15; + } else { + tp.left = pos.left + pos.width / 2 - actualWidth + 15; + } + } + + $tip.css(tp).addClass('tipsy-' + gravity); + + if (this.options.fade) { + $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity}); + } else { + $tip.css({visibility: 'visible', opacity: this.options.opacity}); + } + } + }, + + hide: function() { + if (this.options.fade) { + this.tip().stop().fadeOut(function() { $(this).remove(); }); + } else { + this.tip().remove(); + } + }, + + getTitle: function() { + var title, $e = this.$element, o = this.options; + fixTitle($e); + var title, o = this.options; + if (typeof o.title == 'string') { + title = $e.attr(o.title == 'title' ? 'original-title' : o.title); + } else if (typeof o.title == 'function') { + title = o.title.call($e[0]); + } + title = ('' + title).replace(/(^\s*|\s*$)/, ""); + return title || o.fallback; + }, + + tip: function() { + if (!this.$tip) { + this.$tip = $('
').html('
'); + } + return this.$tip; + }, + + validate: function() { + if (!this.$element[0].parentNode) { + this.hide(); + this.$element = null; + this.options = null; + } + }, + + enable: function() { this.enabled = true; }, + disable: function() { this.enabled = false; }, + toggleEnabled: function() { this.enabled = !this.enabled; } + }; + + $.fn.tipsy = function(options) { + + if (options === true) { + return this.data('tipsy'); + } else if (typeof options == 'string') { + return this.data('tipsy')[options](); + } + + options = $.extend({}, $.fn.tipsy.defaults, options); + + function get(ele) { + var tipsy = $.data(ele, 'tipsy'); + if (!tipsy) { + tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options)); + $.data(ele, 'tipsy', tipsy); + } + return tipsy; + } + + function enter() { + var tipsy = get(this); + tipsy.hoverState = 'in'; + if (options.delayIn == 0) { + tipsy.show(); + } else { + setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn); + } + }; + + function leave() { + var tipsy = get(this); + tipsy.hoverState = 'out'; + if (options.delayOut == 0) { + tipsy.hide(); + } else { + setTimeout(function() { if (tipsy.hoverState == 'out') tipsy.hide(); }, options.delayOut); + } + }; + + if (!options.live) this.each(function() { get(this); }); + + if (options.trigger != 'manual') { + var binder = options.live ? 'live' : 'bind', + eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus', + eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur'; + this[binder](eventIn, enter)[binder](eventOut, leave); + } + + return this; + + }; + + $.fn.tipsy.defaults = { + delayIn: 0, + delayOut: 0, + fade: false, + fallback: '', + gravity: 'n', + html: false, + live: false, + offset: 0, + opacity: 0.8, + title: 'title', + trigger: 'hover' + }; + + // Overwrite this method to provide options on a per-element basis. + // For example, you could store the gravity in a 'tipsy-gravity' attribute: + // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' }); + // (remember - do not modify 'options' in place!) + $.fn.tipsy.elementOptions = function(ele, options) { + return $.metadata ? $.extend({}, options, $(ele).metadata()) : options; + }; + + $.fn.tipsy.autoNS = function() { + return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n'; + }; + + $.fn.tipsy.autoWE = function() { + return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w'; + }; + +})(jQuery); \ No newline at end of file diff --git a/plugins/maddash/static/js/maddash.js b/plugins/maddash/static/js/maddash.js new file mode 100644 index 00000000..110eec13 --- /dev/null +++ b/plugins/maddash/static/js/maddash.js @@ -0,0 +1,583 @@ +/** + * MyPlugin: MadDash + * Version: 0.1 + * Description: Template for writing new plugins and illustrating the different + * possibilities of the plugin API. + * This file is part of the Manifold project + * Requires: js/plugin.js + * URL: http://www.myslice.info + * Author: Jordan Augé + * Copyright: Copyright 2012-2013 UPMC Sorbonne Universités + * License: GPLv3 + */ +var SVG='http://www.w3.org/2000/svg'; +var instance = this; +var colorscale = d3.scale.category10().range(["green", "yellow", "red", "orange", "gray"]); + +/* XXX */ +/** + * Class: MaDDashGrid + * Description: Widget that displays grid of checks. Uses + * d3 and jQuery to draw the grid. + * Parameters: + * parentId: id string of the container element + * legendId: id string of the legend element + */ + +(function($){ + + var MadDash = Plugin.extend({ + + /** XXX to check + * @brief Plugin constructor + * @param options : an associative array of setting values + * @param element : + * @return : a jQuery collection of objects on which the plugin is + * applied, which allows to maintain chainability of calls + */ + init: function(options, element) { + // Call the parent constructor, see FAQ when forgotten + this._super(options, element); + + + /* Member variables */ + //this.canvas = this.id('canvas'); + this._legend = this.id('legend'); //legendId; + this._labels = Array( + 'un', 'deux', 'trois', 'quatre' + ) + + this._cellsize = 13; + this._cellpadding = 2; + this._text_block_size = 130; + + this._map_elements = {}; + this._num_elements = 0; + + this._max_width_elements = 50; + this._max_height_elements = 30; + + this._buffer_key_list = new Buffer(this._process_key_list, this); + this._buffer_records = new Buffer(this._process_records, this); + + /* Pointers */ + this._canvas = d3.select("#" + options.plugin_uuid + '__canvas') + .style("width", this._max_width_elements * (this._cellsize + 2*this._cellpadding) + 110 + this._text_block_size) + .style("height", this._max_height_elements * (this._cellsize + 2*this._cellpadding) + 110 + this._text_block_size) + this._left_element = null; + this._top_element = null; + this._row_element = Array(); + this._grid_element = null; + + + + /* Buffered input */ +// this._buffer = Array(); +// this._update_interval = 1000; /* ms to wait, 1000 = 1 second */ +// setInterval(function(){ +// var tmp = buffer; /* Switch the buffer out quickly so we aren't scrambled +// if you addToBuffer in the middle of this */ +// buffer = Array(); +// $thisdocument.getElementById(htmlId).innerHTML = tmp.join(""); +// //document.getElementById(htmlId).innerHTML = tmp.join(""); +// }, wait); +// +//addToBuffer = function(html){ +// buffer.push(html); +//}; + + /* Plugin events */ + + /* Setup query and record handlers */ + + // Explain this will allow query events to be handled + // What happens when we don't define some events ? + // Some can be less efficient + this.listen_query(options.query_uuid); + this.listen_query(options.query_all_uuid, 'all'); + + /* GUI setup and event binding */ + // call function + this._display_legends(); + this._init_top(); + this._init_left(); + this._init_grid(); + //this._test(); + + }, + + _test: function() + { + data = { + "name":"OWAMP", + "statusLabels":[ + "Loss is 0",null,"Loss is greater than 0","Unable to retrieve data","Check has not yet run" + ], + "lastUpdateTime":1385376538, + "rows":[ + {"name":"200.128.79.100","uri":"/maddash/grids/OWAMP/200.128.79.100"}, + {"name":"ata.larc.usp.br","uri":"/maddash/grids/OWAMP/ata.larc.usp.br"}, + {"name":"mon-lt.fibre.cin.ufpe.br","uri":"/maddash/grids/OWAMP/mon-lt.fibre.cin.ufpe.br"} + ], + "columnNames":[ + "200.128.79.100","ata.larc.usp.br","mon-lt.fibre.cin.ufpe.br" + ], + "checkNames": ["Loss","Loss Reverse"], + "grid": [ + [ + /* First line */ + null, + [{ + "message":" No one-way delay data returned for direction where src=200.128.79.100 dst=ata.larc.usp.br", + "status":3, + "prevCheckTime":1385376238, + "uri":"/maddash/grids/OWAMP/200.128.79.100/ata.larc.usp.br/Loss" + },{ + "message":" No one-way delay data returned for direction where src=ata.larc.usp.br dst=200.128.79.100", + "status":2,"prevCheckTime":1385376178, + "uri":"/maddash/grids/OWAMP/200.128.79.100/ata.larc.usp.br/Loss+Reverse" + }],[{ + "message":" Loss is 100.000% ", + "status":2, + "prevCheckTime":1385374877, + "uri":"/maddash/grids/OWAMP/200.128.79.100/mon-lt.fibre.cin.ufpe.br/Loss" + },{ + "message":" Loss is 100.000% ", + "status":2, + "prevCheckTime":1385375498, + "uri":"/maddash/grids/OWAMP/200.128.79.100/mon-lt.fibre.cin.ufpe.br/Loss+Reverse" + }] + ],[ + /* Second line */ + [{ + "message":" Unable to contact MA. Please check that the MA is running and the URL is correct.", + "status":3, + "prevCheckTime":1385376037, + "uri":"/maddash/grids/OWAMP/ata.larc.usp.br/200.128.79.100/Loss" + }, { + "message":" Unable to contact MA. Please check that the MA is running and the URL is correct.", + "status":3, + "prevCheckTime":1385376117, + "uri":"/maddash/grids/OWAMP/ata.larc.usp.br/200.128.79.100/Loss+Reverse" + }], + null, + [{ + "message":" Unable to contact MA. Please check that the MA is running and the URL is correct.", + "status":3, + "prevCheckTime":1385376117, + "uri":"/maddash/grids/OWAMP/ata.larc.usp.br/mon-lt.fibre.cin.ufpe.br/Loss" + }, { + "message":" Unable to contact MA. Please check that the MA is running and the URL is correct.", + "status":3, + "prevCheckTime":1385376017, + "uri":"/maddash/grids/OWAMP/ata.larc.usp.br/mon-lt.fibre.cin.ufpe.br/Loss+Reverse" + }] + ],[ + /* Third line */ + [{ + "message":" Loss is 100.000% ", + "status":2, + "prevCheckTime":1385376478, + "uri":"/maddash/grids/OWAMP/mon-lt.fibre.cin.ufpe.br/200.128.79.100/Loss" + },{ + "message":" Loss is 100.000% ", + "status":2, + "prevCheckTime":1385375958, + "uri":"/maddash/grids/OWAMP/mon-lt.fibre.cin.ufpe.br/200.128.79.100/Loss+Reverse" + }], [{ + "message":" No one-way delay data returned for direction where src=mon-lt.fibre.cin.ufpe.br dst=ata.larc.usp.br", + "status":3, + "prevCheckTime":1385376538, + "uri":"/maddash/grids/OWAMP/mon-lt.fibre.cin.ufpe.br/ata.larc.usp.br/Loss" + },{ + "message":" No one-way delay data returned for direction where src=ata.larc.usp.br dst=mon-lt.fibre.cin.ufpe.br", + "status":3, + "prevCheckTime":1385376358, + "uri":"/maddash/grids/OWAMP/mon-lt.fibre.cin.ufpe.br/ata.larc.usp.br/Loss+Reverse" + }], + null + ] + ] + } + this._render(data); + }, + + /* ------------------------------------------------------------------ */ + /* Accessors */ + /* ------------------------------------------------------------------ */ + + setClickHandler: function(f) + { + this._handleClick = f; + }, + + setCellSize: function(value) + { + this._cellSize = value; + }, + + setCellPadding: function(value) + { + this._cellPadding = value; + }, + + setTextBlockSize: function(value) + { + this._textBlockSize = value; + }, + + + + + /* PLUGIN EVENTS */ + // on_show like in querytable + + + /* GUI EVENTS */ + + // a function to bind events here: click change + // how to raise manifold events + + + /* GUI MANIPULATION */ + + /* XXX */ + + + /* TEMPLATES */ + + // see in the html template + // How to load a template, use of mustache + + /* QUERY HANDLERS */ + + // How to make sure the plugin is not desynchronized + // He should manifest its interest in filters, fields or records + // functions triggered only if the proper listen is done + + // no prefix + + on_filter_added: function(filter) + { + + }, + + // ... be sure to list all events here + + /* RECORD HANDLERS */ + on_all_new_record: function(record) + { + var key_value = record['hrn']; + if (!(this._map_elements.hasOwnProperty(key_value))) { + /* Add the key_value to the buffer to be drawn */ + this._buffer_key_list.add(key_value); + /* Assign coordinates */ + this._map_elements[key_value] = this._num_elements++; + } + /* Add the record to the buffer to be drawn */ + this._buffer_records.add(record); + }, + + /* INTERNAL FUNCTIONS */ + + _render: function(data) + { + //TODO: Set title + //d3.select("#dashboard_name").html(dashboard.name + " Dashboard"); + // XXX OLD XXX d3.select("#" + this.parent).html(""); + //this.elmt().html('') + + this.display_component(data); + }, + + _init_left: function() + { + var self = this; + this._left_element = this._canvas.append("div") + .attr("class", "gleft") + .style("overflow-y", "scroll") + .style("height", "400px") + .append("svg:svg") + .attr("width", self._text_block_size) + .attr("height", self._max_height_elements * (self._cellsize + 2*self._cellpadding) + 1000) + + }, + + _process_left: function(key_list) + { + var self = this; + + this._left_element = this._left_element + .selectAll(".rname") + .data(key_list) + .enter() + .append("g") + .attr("class", function(d,i){return "grow" + i}) + .attr("transform", function(d,i){return "translate(0,"+(i*(self._cellsize+2*self._cellpadding))+")"}) + + this._left_element.append("svg:rect") + .attr("class", function(d,i){return "grow" + i}) + .attr("x",0).attr("y",0) + .attr("width",this._text_block_size).attr("height",(this._cellsize+2*this._cellpadding)) + + this._left_element.append("svg:text") + .attr("class", "gtext") + .attr("transform", "translate("+ (this._text_block_size-5) +",0)") + .text(function(d,i){return d}) //strdata.rows[i].name}) + .attr("text-anchor", "end") + .attr("dy", "1.1em") + + // XXX Let's generate fake records to create all rows + var records = Array(); + for(var i = 0; i < key_list.length; i++) { + for(var j = 0; j < key_list.length; j++) { + records.push({ + 'source': key_list[i], + 'destination': key_list[j], + 'value': Math.floor(Math.random()*4) /* 0 1 2 3 */ + }); + } + } + + // Create the rows + this._row_element = this._grid_element.selectAll(".grow") + .data(key_list) + .enter() + .append("div") + .attr("class", function(d,i){return "grow grow" + i}) + .style("width", "100%") + .style("z-index", 1000) + // jordan + .style('position', 'absolute') +/* + var cells = this._row_element.selectAll('.gcell') + .data(records) //function(d,r){ return d.map(function(d,i){ return {celldata:d, row:r}}) }, function(d) { return d['source'] + '--' + d['destination']; }) + .enter() + .append("div") + .attr("class", "gcell") + .style("height", self._cellsize +"px") + .style("width", self._cellsize +"px") + .style("margin", (self._cellpadding) +"px") + + .on("mouseover", function(d,i){ + selected_row = d.row; // We could find the row from the _map_elements + selected_col = i; + if(d.celldata){ + d3.select(this).style("margin", (self._cellpadding-1) +"px"); + d3.select(this).classed("shadow", true); + } + this._canvas.selectAll(".gcol"+ i).classed("gactive", true); + this._canvas.selectAll(".grow"+ d.row).classed("gactive", true); + }) + .on("mouseout", function(d,i){ + // d3.select(this).classed("shadow", false); + // d3.select(this).style("background-color", color.brighter()); + d3.select(this).style("margin", (self._cellpadding) +"px"); + d3.select(this).classed("shadow", false); + this._canvas.selectAll(".gcol"+ i).classed("gactive", false); + this._canvas.selectAll(".grow"+ d.row).classed("gactive", false); + }) +*/ + }, + + _init_top: function() + { + var self = this; + this._top_element = this._canvas.append("div") + .attr("class", "gtop") + .style("margin-left", self._text_block_size + "px") + .style("float", "left") + .style("overflow-x", "scroll") + .style("width", "960px") + .append("svg:svg") + .attr("height", self._text_block_size) + .attr("width", self._max_width_elements * (self._cellsize + 2*self._cellpadding) + 90 + 1000) + + }, + + + _process_top: function(key_list) + { + var self = this; + + this._top_element = this._top_element + .selectAll(".rname") + .data(key_list) + .enter() + .append("g") + .attr("class", function(d,i){return "gcol" + i}) + .attr("transform", function(d,i){ return "translate("+(i*(self._cellsize+2*self._cellpadding))+",0)"}) + + this._top_element.append("svg:rect") + .attr("class", function(d,i){return "gcol" + i}) + .attr("x",0).attr("y",0) + .attr("transform", "rotate(45,0,"+ self._text_block_size +") translate (-0.5,3)") + .attr("height",self._text_block_size).attr("width",(self._cellsize+self._cellpadding)) + //.attr("transform", "rotate(35,"+ (this._cellsize+this._cellpadding)/2 + "," + this._text_block_size/2 + ")") + + + this._top_element.append("svg:text") + .attr("class", "gtext") + .attr("text-anchor", "start") + .attr("dy", "1.5em") + .attr("dx", "1em") + .attr("transform", "rotate(-45,0,"+ self._text_block_size +") translate(0,"+ (self._text_block_size-5) + ")") + .text(function(d,i){return d}) + + // Create the columns... + var cols = this._grid_element.selectAll(".gcol") + .data(key_list) + .enter() + .append("div") + .attr("class", function(d,i){return "gcol gcol" + i}) + .style("width", (self._cellsize+2*self._cellpadding) + "px") + .style("height", "100%") + .style("left", function(d,i){return (i*(self._cellsize+2*self._cellpadding)) + "px"}) + }, + + _process_key_list: function() + { + console.log("process key list"); + var key_list = this._buffer_key_list.get(); + this._process_top(key_list); + this._process_left(key_list); + console.log("process key list done"); + }, + + _display_legends: function() + { + // Color scale = the number of different statuses + colorscale.domain(d3.range(0, this._labels.length)); + + // Labels + var legendsdata = this._labels + .map(function(d,i){ return {label:d, color:colorscale(i)} }) + //.filter(function(d,i){return d.label === null ? false : true}) + + // Clear and redraw legend + d3.select("#"+this._legend).html("") + + var legends = d3.select("#"+this._legend) + .selectAll(".legend") + .data(legendsdata) + .enter() + .append("div").attr("class", "legend"); + legends.append("div") + .attr("class", "lsymbol") + .style("background", function(d,i){return d.color}) + .style("display", function(d,i){return d.label === null ? "none" : "block"}) + legends.append("div") + .attr("class", "ltext") + .text(function(d,i){return d.label}) + .style("display", function(d,i){return d.label === null ? "none" : "block"}) + }, + + _init_grid: function() + { + this._grid_element = this._canvas + .style("width", this._ncols * (this._cellsize + 2*this._cellpadding) + 110 + this._text_block_size) + .append("div") + .attr("class", "ggrid") + // jordan + .style('top', '165px') + .style('left', '145px') + .style('float', 'none') + .style('width', '2000px') + .style('height', '1000px') + + }, + + _process_records: function() + { + var self = this; + var records = this._buffer_records.get(); + console.log("processing records"); + + // XXX Let's generate fake records instead... NxN + var _records = Array(); + for(var i = 0; i < records.length; i++) { + for(var j = 0; j < records.length; j++) { + if (Math.random() < 0.2) { /* one out of 5 */ + _records.push({ + 'source': records[i]['hrn'], + 'destination': records[j]['hrn'], + 'value': Math.floor(Math.random()*4) /* 0 1 2 3 */ + }) + } + } + } + + // + + // Rows and columns have been created + + var color = ""; + var selected_row = 0; + var selected_col = 0; + var cells = this._row_element.selectAll(".gcell") + /* Not sure to understand this part of the code */ + //uses data.grid initially... this is not good anymore + .data(_records, function(d) { return d['source'] + '--' + d['destination']; }) + .style("background", function(d,i){ + return colorscale(parseInt(d.value)); + }) + + // Associate a tooltip to each cell thanks to tipsy + /* + this.elmt().find(".gcell").each(function(i,d){ + var data = d3.select(this).data()[0]; + if(data.celldata!=null){ + var html = "
" + (data.celldata[0]? data.celldata[0].message : "") + "
" + (data.celldata[1]? data.celldata[1].message : "") + "
"; + $(this).tipsy({ + html :true, + opacity: 0.9, + title : function(){ + return html + }}) + } + }) + */ + + // This seems to create the coloured subcells + var temp = cells.selectAll(".gsubcell") + .data(function(d,i){return d.celldata===null? [] : d.celldata }) + .enter() + .append("div"); + temp + .style("height", this._cellsize/2 +"px") + .style("background", function(d,i){ + return colorscale(parseInt(d.status)); + }) + .on("click", function(d,i){ //CHANGE FROM PORTAL + var that = this; + if(d!=null && d.uri!=null && self.handleClick != null){ + self.handleClick(d); + } + }) + console.log("processing records done"); + }, + + display_component: function(data) + { + this._display_grid_container(data); + }, + + _handleClick: function(d) + { + var uri = d.uri; + $.getJSON(uri, function(data) { + var href = data['history'][0].returnParams.graphUrl.replace("https", "http"); + window.open( href, "Graph", "menubar=0,location=0,height=700,width=700" ); + }) + + } + + + }); + + /* Plugin registration */ + $.plugin('MadDash', MadDash); + + // TODO Here use cases for instanciating plugins in different ways like in the pastie. + +})(jQuery); diff --git a/plugins/maddash/templates/maddash.html b/plugins/maddash/templates/maddash.html new file mode 100644 index 00000000..8e678e91 --- /dev/null +++ b/plugins/maddash/templates/maddash.html @@ -0,0 +1,5 @@ +
+
+
+
+