From f37e7823cff594f8e93d79479124176d36da0bf2 Mon Sep 17 00:00:00 2001 From: Marcus Poeckelmann <marcus.poeckelmann@informatik.uni-halle.de> Date: Fri, 10 Mar 2023 17:39:30 +0100 Subject: [PATCH] v2.4: added scaling of rectangles (e.g. in respect to amount of text in segments) --- README | 2 +- catview.css | 2 +- catview.js | 183 ++++++++++++++++++++++++++++++------------ demo/data.js | 2 +- demo/demo_bottom.html | 17 +++- demo/demo_left.html | 17 +++- demo/demo_right.html | 17 +++- demo/demo_top.html | 15 +++- 8 files changed, 195 insertions(+), 60 deletions(-) diff --git a/README b/README index 4efccce..02fb1ce 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ Thank you for using CATview - the Colored & Aligned Texts view. -This is version 2.31. +This is version 2.4. For information about the features and usage of CATview, please visit: https://catview.uzi.uni-halle.de diff --git a/catview.css b/catview.css index 4d5e55f..3cac177 100644 --- a/catview.css +++ b/catview.css @@ -37,7 +37,7 @@ } #CATview .search_result { - fill: yellow; + fill: yellow !important; /*fill: #dcdc00; // darker for sw-print*/ } diff --git a/catview.js b/catview.js index 1cf0dc1..7abbf6f 100644 --- a/catview.js +++ b/catview.js @@ -23,7 +23,7 @@ */ // CATview - the Colored & Aligned Texts view -// version 2.31 +// version 2.4 const CATview = new function() { this.debug = false; @@ -32,7 +32,7 @@ const CATview = new function() { if(CATview.debug) console.log('CATview.initialize'); - CATview.version = '2.3'; + CATview.version = '2.4'; // id of the parent container that will include CATview CATview.parent_id = 'CATview'; @@ -101,22 +101,29 @@ const CATview = new function() { // data CATview.names = []; // array with witnesses names (number of rows) - CATview.edges = []; // array with alignment edges (number of columns) - contains arrays with one entry for each row + CATview.edges = []; // array with alignment edges (number of columns) - contains an array for each column (edge) with an entry for each column (witness), i.e. + // -1: no segment for the witness + // value within [0.0, 1.0]: segment, which will be colored according to CATview.scale_color CATview.search_results = []; // array with column ids to be highlighted as search results - CATview.remaining_edges = []; // array with supposed edges that could not be aligned - entries: [distance, [ [[row, col], [row, col]]+ ]] - CATview.extra_segments = []; // same structure as edges - will be displayed faded out (gray dotted without filling) + CATview.remaining_edges = []; // TODO deprecated: array with supposed edges that could not be aligned - entries: [distance, [ [[row, col], [row, col]]+ ]] + CATview.extra_segments = []; // additional segments that will be displayed in a faded out fashion (gray dotted without filling) + // entries are triples with [index of edge, index of witness, color value (within [0.0, 1.0])] CATview.edge_names = []; // array of the edges' names, displayed on mouse over // scales to map the elements to the available pixels - CATview.scale_edges = [0.5,1]; //null; // map [from, to] + CATview.scale_edges = null; // map [from, to] CATview.scale_names = null; // map the names CATview.scale_edges_original = null; // map [0, n-1] // a scale for the color CATview.scale_color = d3.scaleLinear().domain([0, 1]).range(["#C1C1E9", "#0000A3"]); CATview.equality_color = '#d9d9d9'; CATview.use_equality_color = true; - //CATview.color = d3.scaleLinear().domain([0, 1]).range(["#b8b8b8", "#000"]); - //CATview.color = d3.scaleLinear().domain([0, 1]).range(["#7CCF7C", "c0c"]); + + // for scaling of rectangles + CATview.rect_scaling_enabled = false; // if true, use CATview.rect_scaling to define the size for all rectangles + CATview.rect_scaling_minimum = 0.2; // defines the smallest possible size for a rectangle + CATview.rect_scaling_mode = 'default'; // defines the placement after scaling: 'default' (on bottom) | 'middle' (centered) | 'inverted' (on top) + CATview.rect_scaling = null; // same structure as edges - defines the size of rectangles CATview.drag_enabled = false; // is drag'n'drop allowed CATview.drag_callback = null; // called after a successful name swap @@ -382,7 +389,6 @@ const CATview = new function() { // add containers for different groups of content CATview.content.append("g").attr("class", "search_results_background"); CATview.content.append("g").attr("class", "alignment"); - CATview.content.append("g").attr("class", "search_results_foreground"); CATview.content.append("g").attr("class", "remaining_edges"); //CATview.content.append("g").attr("class", "brush"); @@ -393,7 +399,6 @@ const CATview = new function() { // append the brush, if it was enabled prior the call of draw_svg CATview.draw_brush(); - // todo may also draw search result here // append box to display an edges name on hover CATview.edge_name = d3.select("#CATview").append("div").attr("class", "edge-name" + " edge-name-" + CATview.orientation); @@ -949,10 +954,10 @@ const CATview = new function() { CATview.click_on_edge_callback(d[0], d[1]); }) .attr('cursor', 'pointer') - .attr("width", CATview.rect_width) - .attr("height", CATview.rect_height) + .attr("width", function(d){ return CATview.scaled_rect_width(d[1], d[0]); }) + .attr("height", function(d){ return CATview.scaled_rect_height(d[1], d[0]); }) //.attr("ry", rect_corner) // rounded Corners - .attr(CATview.vertical == true ? "x" : "y", function(d) { return CATview.scale_names(CATview.drag_order_name2pos[d[0]])}) + .attr(CATview.vertical == true ? "x" : "y", function(d) { return CATview.scaled_position(d[1], d[0]); }) .attr("style", function(d) { return CATview.rect_stroke + CATview.rect_border + "fill: " + (parseFloat(d[2]) == 0.0 && CATview.use_equality_color ? CATview.equality_color : CATview.scale_color(parseFloat(d[2]))); @@ -1153,10 +1158,10 @@ const CATview = new function() { .attr("class", "rect-segment extra") .on("click", function(d){CATview.click_on_edge_callback(segment[1], segment[0]);} ) .attr('cursor', 'pointer') - .attr("width", CATview.rect_width - 1) - .attr("height", CATview.rect_height - 2) + .attr("width", function(d){ return CATview.scaled_rect_width(segment[0], segment[1]) - 1;}) + .attr("height", function(d){ return CATview.scaled_rect_height(segment[0], segment[1]) - 2;}) .attr(CATview.vertical == true ? "x" : "y", function(d) { - return CATview.scale_names(CATview.drag_order_name2pos[segment[1]]) + 1 + return CATview.scaled_position(segment[0], segment[1]) + 1; }) .attr("style", function(d) { return 'fill:transparent; stroke-width:2; stroke-dasharray:3,1; stroke:' + @@ -1186,7 +1191,10 @@ const CATview = new function() { if(CATview.content){ CATview.content.select(".search_results_background").selectAll('rect').remove(); - CATview.content.select(".search_results_foreground").selectAll('rect').remove(); + let segments = document.querySelectorAll('.search_result'); + for (let i = 0; i < segments.length; i++) { + segments[i].classList.remove('search_result') + } if(CATview.search_results){ @@ -1194,27 +1202,14 @@ const CATview = new function() { // draw highlight-rectangles over the segment-rectangles // first filter the hits according to the zoom let hits = CATview.search_results.filter(function(d){return (CATview.from <= d[0] + 1 && d[0] +1 <= CATview.to)}); + if(hits.length > 0) { - // reformat the hits into pairs (wit, edge) - hits = hits.map(function (d) { return d[1].map( - function (d2) { return [d[0] + 1, d2]}) }).reduce( - function (a, b) { return a.concat(b);}); - - CATview.content.select(".search_results_foreground").selectAll("rect") - .data(hits) - .enter().append("rect") - .attr('class', 'search_result') - .on("click", function (d) {CATview.click_on_edge_callback(d[1], d[0] - 1);}) - .attr('cursor', 'pointer') - .attr("width", CATview.rect_width) - .attr("height", CATview.rect_height) - .attr("x", function (d) {return CATview.vertical == true ? - (CATview.scale_names(CATview.drag_order_name2pos[d[1]]) - CATview.rect_width / 2) : (CATview.scale_edges(d[0]) - CATview.rect_width / 2); - }) - .attr("y", function (d) {return CATview.vertical == true ? - (CATview.scale_edges(d[0]) - CATview.rect_height / 2) : (CATview.scale_names(CATview.drag_order_name2pos[d[1]]) - CATview.rect_height / 2); - }) - .attr("data-segment-index", function(d){return (d[0]-1) + "_" + d[1] }); + hits.forEach(function(edge){ + edge[1].forEach(function(name_idx){ + let seg = document.querySelector('[data-segment-index="' + edge[0] + '_' + name_idx + '"]') + if(seg !== null) seg.classList.add("search_result") + }); + }); } } else{ @@ -1252,6 +1247,93 @@ const CATview = new function() { return false; }; + + // public methods for rectangle scaling + this.set_rect_scaling = function(_rect_scaling){ + if(CATview.debug) + console.log('CATview.set_rect_scaling'); + // TODO validation + this.rect_scaling = _rect_scaling; + return true; + } + this.enable_rect_scaling = function(_mode){ + if(CATview.debug) + console.log('CATview.enable_rect_scaling'); + + CATview.rect_scaling_enabled = true; + if(_mode === 'middle' ) + CATview.rect_scaling_mode = 'middle'; + else if (_mode === 'inverted') + CATview.rect_scaling_mode = 'inverted'; + else + CATview.rect_scaling_mode = 'default'; + CATview.refresh_content(CATview.from, CATview.to); + return true; + } + this.disable_rect_scaling = function(){ + if(CATview.debug) + console.log('CATview.disable_rect_scaling'); + + CATview.rect_scaling_enabled = false; + CATview.refresh_content(CATview.from, CATview.to); + return true; + } + this.toggle_rect_scaling = function(){ + if(CATview.debug) + console.log('CATview.toggle_rect_scaling'); + + if(CATview.rect_scaling_enabled) + return CATview.disable_rect_scaling(); + else + return CATview.enable_rect_scaling(CATview.rect_scaling_mode); + } + // internal methods to define the dimensions and positioning of rectabgles in respect to rectangle scaling + this.scaled_rect_width = function(_egde_idx, _name_idx){ + if(!CATview.rect_scaling_enabled || !CATview.vertical || CATview.rect_scaling === null){ + // return the default width on disabled scaling or horizontal orientation + return CATview.rect_width; + } + + let scaling = CATview.rect_scaling[_egde_idx][_name_idx]; // individual scaling of the segment/rectangle + + let minimal_size = CATview.rect_width * CATview.rect_scaling_minimum; // fixed minimal size of the rectangle + let addable_size = CATview.rect_width - minimal_size; // variable size available to add + return Math.round(minimal_size + scaling * addable_size); + } + this.scaled_rect_height = function(_egde_idx, _name_idx){ + if(!CATview.rect_scaling_enabled || CATview.vertical || CATview.rect_scaling === null){ + // return the default height on disabled scaling or vertical orientation + return CATview.rect_height; + } + + let scaling = CATview.rect_scaling[_egde_idx][_name_idx]; // individual scaling of the segment/rectangle + + let minimal_size = CATview.rect_height * CATview.rect_scaling_minimum; // fixed minimal size of the rectangle + let addable_size = CATview.rect_height - minimal_size; // variable size available to add + return Math.round(minimal_size + scaling * addable_size); + } + this.scaled_position = function(_egde_idx, _name_idx){ + if(!CATview.rect_scaling_enabled || CATview.rect_scaling_mode == 'inverted'){ + // the default value if scaling was disabled or on inverted mode + return CATview.scale_names(CATview.drag_order_name2pos[_name_idx]); + } + + if(CATview.vertical){ + let scaled = CATview.scaled_rect_width(_egde_idx, _name_idx) + if(CATview.rect_scaling_mode === 'middle') + scaled = (scaled + CATview.rect_width) / 2.0; + // the original posittion + maximal size - used size + return CATview.scale_names(CATview.drag_order_name2pos[_name_idx]) + CATview.rect_width - scaled + }else{ + // get the scaled size + let scaled = CATview.scaled_rect_height(_egde_idx, _name_idx) + if(CATview.rect_scaling_mode === 'middle') + scaled = (scaled + CATview.rect_height) / 2.0; + // the original posittion + maximal size - used size + return CATview.scale_names(CATview.drag_order_name2pos[_name_idx]) + CATview.rect_height - scaled + } + } + // callback to switch the order of edges this.invert_edges_axis = function(){ if(CATview.debug) @@ -1657,6 +1739,14 @@ const CATview = new function() { index, 0); }; + // add a tool that toggles the rectangle scaling + this.add_tool_toggle_rect_scaling = function(index){ + return CATview.add_tool( + (CATview.vertical ? 'f036' : 'f038'), + function(){CATview.toggle_rect_scaling()}, + index, + (CATview.vertical ? 0 : 90 )); + }; //todo remove and set the identifiers of the witnesses this.set_names = function(names){ @@ -1745,16 +1835,15 @@ const CATview = new function() { return true; }; + this.set_color_scale = function(_from, _to, _border){ - this.set_color_scale = function(from, to, border){ - - if(from == null) from = "#c1c1e9"; - if(to == null) to = "#0000a3"; - if(border == null) border = "#2f2f86"; + if(_from === null || _from === undefined) _from = "#c1c1e9"; + if(_to === null || _to === undefined) _to = "#0000a3"; + if(_border === null || _border === undefined) _border = "#2f2f86"; - CATview.scale_color = d3.scaleLinear().domain([0, 1]).range([from, to]); + CATview.scale_color = d3.scaleLinear().domain([0, 1]).range([_from, _to]); - CATview.rect_border = "stroke: " + border + ";"; + CATview.rect_border = "stroke: " + _border + ";"; return CATview.refresh_content(); }; @@ -1776,12 +1865,6 @@ const CATview = new function() { return true; }; - // parse a vaue to float and set precision to avoid rounding errors - this.to_float = function(_value){ - return parseFloat(_value); - return parseFloat(parseFloat(_value).toFixed(5)); - } - // todo // - may: method to set search_mode → toggle_search_mode(_mode) // - may: method to zoom → zoom_to(_factor) diff --git a/demo/data.js b/demo/data.js index fb160f4..96a7ad7 100644 --- a/demo/data.js +++ b/demo/data.js @@ -235,7 +235,7 @@ var example = '<table width="100%">' + ' <tr class="edge">' + ' <td class="segment">Aenean molestie sit amet nibh non blandit. Praesent lobortis nisi eget vulputate sodales.</td>' + ' <td class="segment">Aenean molestie sit amet nibh non blandit. Praesent lobortis nisi eget vulputate sodales.</td>' + - ' <td class="segment">Aenean molestie sit amet nibh non blandit. Praesent lobortis nisi eget vulputate sodales.<span class="variant">Integer sed consectetur leo.</span></td>' + + ' <td class="segment">Aenean molestie sit amet nibh non blandit. Praesent lobortis nisi eget vulputate sodales. <span class="variant">Integer sed consectetur leo.</span></td>' + ' </tr>' + ' <tr class="edge">' + ' <td class="segment"><em>missing</em></td>' + diff --git a/demo/demo_bottom.html b/demo/demo_bottom.html index 1aa9682..7ea9250 100644 --- a/demo/demo_bottom.html +++ b/demo/demo_bottom.html @@ -81,8 +81,21 @@ "Duis at…", "Ut varius…", "Quisque tincidunt…", "Curabitur ac…", "Vivamus vulputate…", "Aliquam sagittis…", "Nunc ut…", "Curabitur placerat…", "Aenean molestie…", "Donec quis…", "Aliquam sagittis…", "Duis nunc…", "Pellentesque habitant…", "Tincidunt dignissim…", "Nullam non…" ]); - CATview.enable_drag(); - CATview.add_tool_invert_names_axis(); // invert-names-axis tool + let max = 32; + CATview.set_rect_scaling([ + [8/max, 8/max, 8/max], [26/max, 26/max, 26/max], [7/max, 11/max, 11/max], [17/max, 21/max, 25/max], [16/max, 16/max, 21/max], + [22/max, 22/max, 22/max], [-1, -1, 16/max], [-1, 16/max, 23/max], [-1, -1, 12/max], [20/max, 20/max, 32/max], + [17/max, 14/max, 14/max], [21/max, 21/max, 21/max], [19/max, 19/max, 19/max], [19/max, 19/max, 19/max], [-1, 10/max, 10/max], + [13/max, 13/max, 13/max], [8/max, 8/max, 8/max], [7/max, 7/max, 7/max], [24/max, 24/max, 24/max], [8/max, 8/max, 8/max], + [7/max, 7/max, 7/max], [10/max, 10/max, 10/max], [22/max, 22/max, 22/max], [10/max, 10/max, 21/max], [13/max, 19/max, 19/max], + [-1, 7/max, 10/max], [10/max, 10/max, 21/max], [-1, 18/max, 18/max], [16/max, 16/max, 21/max], [14/max, 14/max, 14/max], + [20/max, 20/max, 20/max], [7/max, 7/max, 7/max], [20/max, 20/max, 20/max], [14/max, 14/max, 14/max], [4/max, 10/max, 10/max], + [20/max, 20/max, 20/max], [-1, 28/max, 28/max], [7/max, 14/max, 14/max], [11/max, 15/max, 15/max], [12/max, 16/max, 20/max], + [-1, 14/max, 14/max], [-1, 11/max, 21/max], [17/max, 17/max, 17/max], [13/max, 13/max, 17/max], [-1, 20/max, 20/max], + [-1, 14/max, 14/max], [-1, 14/max, 14/max], [17/max, 17/max, 17/max], [8/max, 8/max, 8/max], [4/max, 4/max, 4/max]]); + CATview.enable_drag('insert'); + CATview.add_tool_toggle_rect_scaling(); // toggle individual scaling of rectangles + CATview.rect_scaling_mode = 'middle'; // place scaled rectangles in the middle CATview.add_tool_invert_edges_axis(); // invert-edges-axis tool CATview.add_tool_toggle_search_mode(); // switch-highlight-mode-of-search-results tool CATview.add_tool_toggle_brush(); // enable/disable-brush tool diff --git a/demo/demo_left.html b/demo/demo_left.html index 5e0eabb..1dca725 100644 --- a/demo/demo_left.html +++ b/demo/demo_left.html @@ -82,8 +82,21 @@ "Duis at…", "Ut varius…", "Quisque tincidunt…", "Curabitur ac…", "Vivamus vulputate…", "Aliquam sagittis…", "Nunc ut…", "Curabitur placerat…", "Aenean molestie…", "Donec quis…", "Aliquam sagittis…", "Duis nunc…", "Pellentesque habitant…", "Tincidunt dignissim…", "Nullam non…" ]); - CATview.enable_drag(); - CATview.add_tool_invert_names_axis(); // invert-names-axis tool + let max = 32; + CATview.set_rect_scaling([ + [8/max, 8/max, 8/max], [26/max, 26/max, 26/max], [7/max, 11/max, 11/max], [17/max, 21/max, 25/max], [16/max, 16/max, 21/max], + [22/max, 22/max, 22/max], [-1, -1, 16/max], [-1, 16/max, 23/max], [-1, -1, 12/max], [20/max, 20/max, 32/max], + [17/max, 14/max, 14/max], [21/max, 21/max, 21/max], [19/max, 19/max, 19/max], [19/max, 19/max, 19/max], [-1, 10/max, 10/max], + [13/max, 13/max, 13/max], [8/max, 8/max, 8/max], [7/max, 7/max, 7/max], [24/max, 24/max, 24/max], [8/max, 8/max, 8/max], + [7/max, 7/max, 7/max], [10/max, 10/max, 10/max], [22/max, 22/max, 22/max], [10/max, 10/max, 21/max], [13/max, 19/max, 19/max], + [-1, 7/max, 10/max], [10/max, 10/max, 21/max], [-1, 18/max, 18/max], [16/max, 16/max, 21/max], [14/max, 14/max, 14/max], + [20/max, 20/max, 20/max], [7/max, 7/max, 7/max], [20/max, 20/max, 20/max], [14/max, 14/max, 14/max], [4/max, 10/max, 10/max], + [20/max, 20/max, 20/max], [-1, 28/max, 28/max], [7/max, 14/max, 14/max], [11/max, 15/max, 15/max], [12/max, 16/max, 20/max], + [-1, 14/max, 14/max], [-1, 11/max, 21/max], [17/max, 17/max, 17/max], [13/max, 13/max, 17/max], [-1, 20/max, 20/max], + [-1, 14/max, 14/max], [-1, 14/max, 14/max], [17/max, 17/max, 17/max], [8/max, 8/max, 8/max], [4/max, 4/max, 4/max]]); + CATview.enable_drag('insert'); + CATview.add_tool_toggle_rect_scaling(); // toggle individual scaling of rectangles + CATview.rect_scaling_mode = 'middle'; // place scaled rectangles in the middle CATview.add_tool_invert_edges_axis(); // invert-edges-axis tool CATview.add_tool_toggle_search_mode(); // switch-highlight-mode-of-search-results tool CATview.add_tool_toggle_brush(); // enable/disable-brush tool diff --git a/demo/demo_right.html b/demo/demo_right.html index 4d751e5..87f4b29 100644 --- a/demo/demo_right.html +++ b/demo/demo_right.html @@ -82,8 +82,21 @@ "Duis at…", "Ut varius…", "Quisque tincidunt…", "Curabitur ac…", "Vivamus vulputate…", "Aliquam sagittis…", "Nunc ut…", "Curabitur placerat…", "Aenean molestie…", "Donec quis…", "Aliquam sagittis…", "Duis nunc…", "Pellentesque habitant…", "Tincidunt dignissim…", "Nullam non…" ]); - CATview.enable_drag(); - CATview.add_tool_invert_names_axis(); // invert-names-axis tool + let max = 32; + CATview.set_rect_scaling([ + [8/max, 8/max, 8/max], [26/max, 26/max, 26/max], [7/max, 11/max, 11/max], [17/max, 21/max, 25/max], [16/max, 16/max, 21/max], + [22/max, 22/max, 22/max], [-1, -1, 16/max], [-1, 16/max, 23/max], [-1, -1, 12/max], [20/max, 20/max, 32/max], + [17/max, 14/max, 14/max], [21/max, 21/max, 21/max], [19/max, 19/max, 19/max], [19/max, 19/max, 19/max], [-1, 10/max, 10/max], + [13/max, 13/max, 13/max], [8/max, 8/max, 8/max], [7/max, 7/max, 7/max], [24/max, 24/max, 24/max], [8/max, 8/max, 8/max], + [7/max, 7/max, 7/max], [10/max, 10/max, 10/max], [22/max, 22/max, 22/max], [10/max, 10/max, 21/max], [13/max, 19/max, 19/max], + [-1, 7/max, 10/max], [10/max, 10/max, 21/max], [-1, 18/max, 18/max], [16/max, 16/max, 21/max], [14/max, 14/max, 14/max], + [20/max, 20/max, 20/max], [7/max, 7/max, 7/max], [20/max, 20/max, 20/max], [14/max, 14/max, 14/max], [4/max, 10/max, 10/max], + [20/max, 20/max, 20/max], [-1, 28/max, 28/max], [7/max, 14/max, 14/max], [11/max, 15/max, 15/max], [12/max, 16/max, 20/max], + [-1, 14/max, 14/max], [-1, 11/max, 21/max], [17/max, 17/max, 17/max], [13/max, 13/max, 17/max], [-1, 20/max, 20/max], + [-1, 14/max, 14/max], [-1, 14/max, 14/max], [17/max, 17/max, 17/max], [8/max, 8/max, 8/max], [4/max, 4/max, 4/max]]); + CATview.enable_drag('insert'); + CATview.add_tool_toggle_rect_scaling(); // toggle individual scaling of rectangles + CATview.rect_scaling_mode = 'middle'; // place scaled rectangles in the middle CATview.add_tool_invert_edges_axis(); // invert-edges-axis tool CATview.add_tool_toggle_search_mode(); // switch-highlight-mode-of-search-results tool CATview.add_tool_toggle_brush(); // enable/disable-brush tool diff --git a/demo/demo_top.html b/demo/demo_top.html index 7661647..cef85f3 100644 --- a/demo/demo_top.html +++ b/demo/demo_top.html @@ -82,8 +82,21 @@ "Duis at…", "Ut varius…", "Quisque tincidunt…", "Curabitur ac…", "Vivamus vulputate…", "Aliquam sagittis…", "Nunc ut…", "Curabitur placerat…", "Aenean molestie…", "Donec quis…", "Aliquam sagittis…", "Duis nunc…", "Pellentesque habitant…", "Tincidunt dignissim…", "Nullam non…" ]); + let max = 32; + CATview.set_rect_scaling([ + [8/max, 8/max, 8/max], [26/max, 26/max, 26/max], [7/max, 11/max, 11/max], [17/max, 21/max, 25/max], [16/max, 16/max, 21/max], + [22/max, 22/max, 22/max], [-1, -1, 16/max], [-1, 16/max, 23/max], [-1, -1, 12/max], [20/max, 20/max, 32/max], + [17/max, 14/max, 14/max], [21/max, 21/max, 21/max], [19/max, 19/max, 19/max], [19/max, 19/max, 19/max], [-1, 10/max, 10/max], + [13/max, 13/max, 13/max], [8/max, 8/max, 8/max], [7/max, 7/max, 7/max], [24/max, 24/max, 24/max], [8/max, 8/max, 8/max], + [7/max, 7/max, 7/max], [10/max, 10/max, 10/max], [22/max, 22/max, 22/max], [10/max, 10/max, 21/max], [13/max, 19/max, 19/max], + [-1, 7/max, 10/max], [10/max, 10/max, 21/max], [-1, 18/max, 18/max], [16/max, 16/max, 21/max], [14/max, 14/max, 14/max], + [20/max, 20/max, 20/max], [7/max, 7/max, 7/max], [20/max, 20/max, 20/max], [14/max, 14/max, 14/max], [4/max, 10/max, 10/max], + [20/max, 20/max, 20/max], [-1, 28/max, 28/max], [7/max, 14/max, 14/max], [11/max, 15/max, 15/max], [12/max, 16/max, 20/max], + [-1, 14/max, 14/max], [-1, 11/max, 21/max], [17/max, 17/max, 17/max], [13/max, 13/max, 17/max], [-1, 20/max, 20/max], + [-1, 14/max, 14/max], [-1, 14/max, 14/max], [17/max, 17/max, 17/max], [8/max, 8/max, 8/max], [4/max, 4/max, 4/max]]); CATview.enable_drag('insert'); - CATview.add_tool_invert_names_axis(); // invert-names-axis tool + CATview.add_tool_toggle_rect_scaling(); // toggle individual scaling of rectangles + CATview.rect_scaling_mode = 'middle'; // place scaled rectangles in the middle CATview.add_tool_invert_edges_axis(); // invert-edges-axis tool CATview.add_tool_toggle_search_mode(); // switch-highlight-mode-of-search-results tool CATview.add_tool_toggle_brush(); // enable/disable-brush tool -- GitLab