From 830bcbfd15e4ab2ede73435ae2bce97a07885e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20P=C3=B6ckelmann?= <marcus.poeckelmann@informatik.uni-halle.de> Date: Thu, 25 May 2023 18:59:01 +0200 Subject: [PATCH] v2.6: added methods to set the zoom as well as to zoom in and out --- README | 2 +- catview.js | 118 ++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/README b/README index 7aeb9ee..3ca7298 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ Thank you for using CATview - the Colored & Aligned Texts view. -This is version 2.5.2 +This is version 2.6 For information about the features and usage of CATview, please visit: https://catview.uzi.uni-halle.de diff --git a/catview.js b/catview.js index 18a9fd0..e7cf2e9 100644 --- a/catview.js +++ b/catview.js @@ -22,7 +22,7 @@ SOFTWARE. */ -// CATview - the Colored & Aligned Texts view - version 2.5.2 +// CATview - the Colored & Aligned Texts view - version 2.6 const CATview = new function() { this.debug = false; @@ -31,7 +31,7 @@ const CATview = new function() { if(CATview.debug) console.log('CATview.initialize'); - CATview.version = '2.5.2'; + CATview.version = '2.6'; // id of the parent container that will include CATview CATview.parent_id = 'CATview'; @@ -98,6 +98,8 @@ const CATview = new function() { CATview.to_pixel = 0; CATview.scale = 1; // current zooming factor CATview.translate = 0; // current translation for zoomed-in excerpt + CATview.zoom_step = 0.25; // steps by which to increase/decrease zoom in zoom_in/_out() + CATview.zoom_button_clicked = false; // data CATview.names = []; // array with witnesses names (number of rows) @@ -617,9 +619,9 @@ const CATview = new function() { if(!CATview.drag_do_end) return; - let old_pos = CATview.drag_old_pos - let new_pos = CATview.drag_new_pos - let objects = {} + let old_pos = CATview.drag_old_pos; + let new_pos = CATview.drag_new_pos; + let objects = {}; // get all name objects for(let pos = 0; pos < CATview.names.length; pos++){ objects[pos] = d3.select("g.axis.names-axis>text[current=\"" + pos + "\"]"); @@ -950,7 +952,7 @@ const CATview = new function() { .enter().append("g") .attr("class", "row_witness") .attr("transform", function(d) { return "translate(" + - (CATview.vertical == true ? (-CATview.rect_width/2 + ", " + (CATview.scale_edges(parseInt(d[1]))-(CATview.rect_height/2))) : + (CATview.vertical === true ? (-CATview.rect_width/2 + ", " + (CATview.scale_edges(parseInt(d[1]))-(CATview.rect_height/2))) : (CATview.scale_edges(parseInt(d[1]))-(CATview.rect_width/2)) + ", " + (-CATview.rect_height/2)) + ")"; }) .on('mouseenter', function(d, i){CATview.show_edge_name(i)}) @@ -965,10 +967,10 @@ const CATview = new function() { .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.scaled_position(d[1], 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]))); + (parseFloat(d[2]) === 0.0 && CATview.use_equality_color ? CATview.equality_color : CATview.scale_color(parseFloat(d[2]))); }) .attr("data-segment-index", function(d) { return d[1] + "_" + d[0];}) .on("mouseenter", function(d){ CATview.show_rect_linking(d[1]+"_"+d[0]); }) @@ -1028,12 +1030,12 @@ const CATview = new function() { let offset_x = "50%"; let anchor_y = "top"; let offset_y = document.getElementById("CATview").offsetTop + CATview.height_svg + 'px'; - let transform = "translate(-50%, 0)" + let transform = "translate(-50%, 0)"; switch(CATview.orientation) { case 'left': offset_x = CATview.width_svg + 'px'; - offset_y = "50%" - transform = "translate(0, -50%)" + offset_y = "50%"; + transform = "translate(0, -50%)"; break; case 'bottom': anchor_y = "bottom"; @@ -1043,8 +1045,8 @@ const CATview = new function() { case 'right': anchor_x = "right"; offset_x = CATview.width_svg + 'px'; - offset_y = "50%" - transform = "translate(0, -50%)" + offset_y = "50%"; + transform = "translate(0, -50%)"; break; default: // top } @@ -1148,7 +1150,7 @@ const CATview = new function() { return true; }; this.toggle_display_extra_segments = function(_toggle){ - if(_toggle != null && typeof(_toggle) == "boolean") + if(_toggle != null && typeof(_toggle) === "boolean") CATview.display_extra_segments = !_toggle; CATview.display_extra_segments = !CATview.display_extra_segments; @@ -1173,7 +1175,7 @@ const CATview = new function() { .attr('cursor', 'pointer') .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) { + .attr(CATview.vertical === true ? "x" : "y", function(d) { return CATview.scaled_position(segment[0], segment[1]) + 1; }) .attr("style", function(d) { @@ -1271,7 +1273,7 @@ const CATview = new function() { // TODO validation this.rect_scaling = _rect_scaling; return true; - } + }; this.enable_rect_scaling = function(_mode){ if(CATview.debug) console.log('CATview.enable_rect_scaling'); @@ -1285,7 +1287,7 @@ const CATview = new function() { 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'); @@ -1293,7 +1295,7 @@ const CATview = new function() { 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'); @@ -1302,7 +1304,7 @@ const CATview = new function() { 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){ @@ -1315,7 +1317,7 @@ const CATview = new function() { 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 @@ -1327,7 +1329,7 @@ const CATview = new function() { 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 @@ -1348,7 +1350,7 @@ const CATview = new function() { // the original posittion + maximal size - used size return CATview.scale_names(CATview.drag_order_name2pos[_name_idx]) + CATview.rect_height - scaled } - } + }; // public methods for rectangle linking @@ -1358,7 +1360,7 @@ const CATview = new function() { // TODO validation this.rect_linking_data = _data; return true; - } + }; this.enable_rect_linking = function(){ if(CATview.debug) console.log('CATview.enable_rect_linking'); @@ -1366,7 +1368,7 @@ const CATview = new function() { CATview.rect_linking_enabled = true; return true; - } + }; this.disable_rect_linking = function(){ if(CATview.debug) console.log('CATview.disable_rect_linking'); @@ -1374,7 +1376,7 @@ const CATview = new function() { CATview.rect_linking_enabled = false; CATview.hide_rect_linking(); return true; - } + }; this.toggle_rect_linking = function(){ if(CATview.debug) console.log('CATview.toggle_rect_linking'); @@ -1383,7 +1385,7 @@ const CATview = new function() { return CATview.disable_rect_linking(); else return CATview.enable_rect_linking(); - } + }; // internal methods for rectangle linking this.show_rect_linking = function(_idx) { if(CATview.debug) @@ -1393,7 +1395,7 @@ const CATview = new function() { return false; CATview.rect_linking_data.forEach( function (group){ - if(group.indexOf(_idx) != -1){ + if(group.indexOf(_idx) !== -1){ group.forEach( function (group_member) { // add the 'rect_linked' class to highlight all segments in the group, including the one hovered let seg = document.querySelector('[data-segment-index="' + group_member + '"]'); @@ -1401,7 +1403,7 @@ const CATview = new function() { }); } }); - } + }; this.hide_rect_linking = function(){ if(CATview.debug) console.log('CATview.hide_rect_linking'); @@ -1411,7 +1413,7 @@ const CATview = new function() { for (let i = 0; i < segments.length; i++) { segments[i].classList.remove('rect_linked'); } - } + }; // callback to switch the order of edges this.invert_edges_axis = function(){ @@ -1471,6 +1473,35 @@ const CATview = new function() { return true; }; + this.set_zoom = function(_factor) { + if (CATview.zoom.scaleExtent()[0] <= _factor && _factor <= CATview.zoom.scaleExtent()[1]){ + CATview.zoom.scaleTo(CATview.content, _factor); + } + }; + + this.zoom_in = function() { + CATview.zoom_button_clicked = true; + if (CATview.scale+CATview.zoom_step <= CATview.zoom.scaleExtent()[1]){ + CATview.zoom.scaleTo(CATview.content, CATview.scale+CATview.zoom_step); + } + else { + // we hit a boundary, might as well set scale to the boundary + // sometimes mixed scaling with mouse wheel and buttons causes the zoom-step to be + // too large so it would exceed the boundary. In that case clip to the boundary + CATview.zoom.scaleTo(CATview.content, CATview.zoom.scaleExtent()[1]); + } + }; + + this.zoom_out = function() { + CATview.zoom_button_clicked = true; + if (CATview.scale-CATview.zoom_step >= CATview.zoom.scaleExtent()[0]){ + CATview.zoom.scaleTo(CATview.content, CATview.scale-CATview.zoom_step); + } + else{ + CATview.zoom.scaleTo(CATview.content, CATview.zoom.scaleExtent()[0]); + } + }; + // callback with functionality for scaling and translation of the content this.zooming = function () { if(CATview.debug) @@ -1490,7 +1521,17 @@ const CATview = new function() { // calculate the change of the size let delta_size = (current_size / new_scale) - (current_size / CATview.scale); // distribute the change of the size among the left/top and right/bottom site due to the relative mouse center - scale_from = delta_size * ((CATview.vertical === true ? d3.mouse(this)[1] : d3.mouse(this)[0]) / current_size); + + // simulate central mouse position in case of zoom button clicks + if (CATview.zoom_button_clicked){ + var art_mouse_x = CATview.width_content/2; + var art_mouse_y = CATview.height_content/2; + scale_from = delta_size * ((CATview.vertical === true ? art_mouse_y : art_mouse_x) / current_size); + CATview.zoom_button_clicked = false; + } + else{ + scale_from = delta_size * ((CATview.vertical === true ? d3.mouse(this)[1] : d3.mouse(this)[0]) / current_size); + } scale_to = delta_size - scale_from; } else if(CATview.display_brush === false){ @@ -1856,11 +1897,24 @@ const CATview = new function() { // add a tool that toggles the rectangle scaling this.add_tool_toggle_rect_scaling = function(index){ return CATview.add_tool( - (CATview.vertical ? 'f036' : 'f038'), + 'f037', // (CATview.vertical ? 'f036' : 'f038'), function(){CATview.toggle_rect_scaling()}, index, (CATview.vertical ? 0 : 90 )); }; + this.add_tool_zoom_in = function(index){ + return CATview.add_tool('f00e', // f067 + function(){CATview.zoom_in();}, + index, + 0); + }; + this.add_tool_zoom_out = function(index){ + return CATview.add_tool('f010', // f068 + function(){CATview.zoom_out();}, + index, + 0); + }; + //todo remove and set the identifiers of the witnesses this.set_names = function(names){ @@ -1972,7 +2026,7 @@ const CATview = new function() { // enable/disable console output to debug this.toggle_debug = function(debug){ - if(debug != null && typeof(debug) == "boolean") + if(debug != null && typeof(debug) === "boolean") CATview.debug = !debug; CATview.debug = !CATview.debug; -- GitLab