Skip to content

Commit f0ec795

Browse files
authored
Merge pull request #651 from Rdornier/align-to-grid
More compliant align to grid
2 parents b2a55df + 308a3b2 commit f0ec795

1 file changed

Lines changed: 193 additions & 31 deletions

File tree

src/js/models/figure_model.js

Lines changed: 193 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -742,53 +742,171 @@
742742
});
743743
},
744744

745-
align_grid: function(gridGap) {
745+
align_grid: function(gridGap) {
746746
var sel = this.getSelected(),
747-
top_left = this.get_top_left_panel(sel),
748-
top_x = top_left.get('x'),
749-
top_y = top_left.get('y'),
747+
top = this.get_top_panel(sel),
748+
left = this.get_left_panel(sel),
749+
right = this.get_right_panel(sel),
750+
bottom = this.get_bottom_panel(sel),
751+
left_x = left.get('x'),
752+
right_x = right.get('x') + right.get('width'),
753+
top_y = top.get('y'),
754+
bottom_y = bottom.get('y') + bottom.get('height'),
750755
grid = [],
751-
row = [top_left],
752-
next_panel = top_left;
753-
754-
// populate the grid, getting neighbouring panel each time
755-
while (next_panel) {
756-
c = next_panel.get_centre();
757-
next_panel = this.get_panel_at(c.x + next_panel.get('width'), c.y, sel);
756+
row = [],
757+
next_panel,
758+
c = {'x': left_x + left.get('width')/2, 'y': top_y + top.get('height')/2};
759+
760+
// loop over the rows, starting by the top panel row
761+
while(c.y < bottom_y){
762+
row = []
763+
// loop over the columns, starting by the left panel column
764+
while(c.x < right_x){
765+
next_panel = this.get_panel_at(c.x , c.y, sel);
766+
767+
// if a panel doesn't exist at the current position c
768+
// just go to the next position until it reaches the selection boundaries
769+
if (next_panel) {
770+
row.push(next_panel);
771+
c = next_panel.get_centre();
772+
}else{
773+
next_panel = next_panel == undefined ? left : next_panel
774+
}
775+
c = {'x': c.x + next_panel.get('width'), 'y': c.y}
776+
}
758777

759-
// if next_panel is not found, reached end of row. Try start new row...
760-
if (typeof next_panel == 'undefined') {
778+
// check that there is effecitvely a panel in the current row
779+
if(row.length == 0){
780+
c = {'x': left_x + left.get('width')/2, 'y': c.y + left.get('height')}
781+
}else{
782+
c = {'x': left_x + left.get('width')/2, 'y': c.y + row[0].get('height')}
761783
grid.push(row);
762-
// next_panel is below the first of the current row
763-
c = row[0].get_centre();
764-
next_panel = this.get_panel_at(c.x, c.y + row[0].get('height'), sel);
765-
row = [];
766-
}
767-
if (next_panel) {
768-
row.push(next_panel);
769-
}
784+
}
770785
}
771786

772-
var spacer = top_left.get('width')/20;
787+
// get the row id of the most left panel
788+
var left_panel_row = 0;
789+
grid.forEach((row, i) => {
790+
if (row.some(panel => panel.cid === left.cid)) {
791+
left_panel_row = i;
792+
}
793+
});
794+
795+
// define the spacer between images
796+
var spacer = left.get('width')/20;
773797
if (!isNaN(parseFloat(gridGap))) {
774798
spacer = parseFloat(gridGap);
775799
}
776-
var new_x = top_x,
777-
new_y = top_y,
778-
max_h = 0;
779-
for (var r=0; r<grid.length; r++) {
780-
row = grid[r];
800+
801+
var new_x = left_x,
802+
new_y = left.get('y'),
803+
max_h = 0,
804+
ref_row = grid[left_panel_row],
805+
last_panel_width = 0,
806+
reference_grid = {};
807+
808+
// start aligning the row with the most left panel
809+
// This row is considered as a reference to align
810+
// the rest of the panels
811+
var global_index = 0
812+
for (var c = 0; c < ref_row.length; c++) {
813+
let panel = ref_row[c];
814+
var current_x = panel.get('x')
815+
var gap = Math.floor(Math.abs(current_x - new_x) / last_panel_width)
816+
for(var i = 0; i < gap; i++){
817+
reference_grid[global_index] = new_x
818+
new_x = new_x + spacer + last_panel_width;
819+
global_index++
820+
}
821+
panel.save({'x':new_x, 'y':new_y});
822+
reference_grid[global_index] = new_x
823+
max_h = Math.max(max_h, panel.get('height'));
824+
new_x = new_x + spacer + panel.get('width');
825+
last_panel_width = panel.get('width')
826+
global_index++
827+
}
828+
829+
// set the row position (i.e. y coordinate) of each row
830+
var ref_y_offset = max_h
831+
var rows_position = {}
832+
max_h = 0
833+
// for rows above the reference row
834+
for (var r = left_panel_row - 1; r >= 0; r--) {
835+
var row = grid[r];
836+
for (var c = 0; c < row.length; c++) {
837+
max_h = Math.max(max_h, row[c].get('height'));
838+
}
839+
new_y = new_y - spacer - max_h;
840+
rows_position[r] = new_y
841+
}
842+
max_h = ref_y_offset
843+
new_y = left.get('y')
844+
// for rows below the reference row
845+
for (var r = left_panel_row + 1; r < grid.length; r++) {
846+
var row = grid[r];
847+
new_y = new_y + spacer + max_h;
848+
rows_position[r] = new_y
849+
for (var c = 0; c < row.length; c++) {
850+
max_h = Math.max(max_h, row[c].get('height'));
851+
}
852+
}
853+
854+
// update position of panels
855+
for (var [r, y] of Object.entries(rows_position)){
856+
var row = grid[r];
857+
var last_column_id = -1
781858
for (var c=0; c<row.length; c++) {
782859
let panel = row[c];
783-
panel.save({'x':new_x, 'y':new_y});
784-
max_h = Math.max(max_h, panel.get('height'));
860+
var closest_column = this.get_closest_column(panel, reference_grid, last_panel_width)
861+
862+
if(closest_column >= 0){
863+
// update closest_column id to take into account spare panel positions
864+
if(last_column_id == closest_column){
865+
closest_column = last_column_id + 1
866+
if(closest_column == reference_grid.length){
867+
new_x = reference_grid[closest_column-1] + last_panel_width + spacer
868+
}else{
869+
new_x = reference_grid[closest_column]
870+
}
871+
}else{
872+
new_x = reference_grid[closest_column]
873+
}
874+
}else{
875+
// update closest_column id to take into account spare panel positions
876+
if(last_column_id == reference_grid.length - 1 - closest_column){
877+
closest_column--
878+
}
879+
var lastRefColumn = Object.keys(reference_grid).length - 1
880+
new_x = reference_grid[lastRefColumn] -closest_column*(last_panel_width + spacer)
881+
}
882+
last_column_id++
883+
panel.save({'x':new_x, 'y':y});
785884
new_x = new_x + spacer + panel.get('width');
786885
}
787-
new_y = new_y + spacer + max_h;
788-
new_x = top_x;
789886
}
790887
},
791888

889+
get_closest_column: function(panel, reference_row, last_ref_panel_width){
890+
// look at the reference row (i.e. the one with the most left panel)
891+
// and find the closest column to the current panel
892+
var closest_col = 0;
893+
var min_x_distance = Number.MAX_VALUE
894+
for (var [col_id, col_x] of Object.entries(reference_row)){
895+
var current_distance = Math.abs(col_x - panel.get('x'))
896+
if(current_distance < min_x_distance){
897+
closest_col = col_id
898+
min_x_distance = current_distance
899+
}
900+
}
901+
902+
// if the panel is located far away from the last reference column,
903+
// return the number of extra columns where to put the panel as a negative number
904+
if(closest_col == Object.keys(reference_row).length - 1 && min_x_distance > last_ref_panel_width){
905+
closest_col = - Math.floor(min_x_distance/last_ref_panel_width)
906+
}
907+
return closest_col
908+
},
909+
792910
get_panel_at: function(x, y, panels) {
793911
return panels.find(function(p) {
794912
return ((p.get('x') < x && (p.get('x')+p.get('width')) > x) &&
@@ -803,6 +921,50 @@
803921
return p;
804922
} else {
805923
return top_left;
924+
}
925+
});
926+
},
927+
928+
get_top_panel: function(panels) {
929+
// top panel is one where y is least
930+
return panels.reduce(function(top, p){
931+
if (p.get('y') < top.get('y')) {
932+
return p;
933+
} else {
934+
return top;
935+
}
936+
});
937+
},
938+
939+
get_bottom_panel: function(panels) {
940+
// bottom panel is one where y is greater
941+
return panels.reduce(function(bottom, p){
942+
if (p.get('y') > bottom.get('y')) {
943+
return p;
944+
} else {
945+
return bottom;
946+
}
947+
});
948+
},
949+
950+
get_left_panel: function(panels) {
951+
// left panel is one where x is least
952+
return panels.reduce(function(left, p){
953+
if (p.get('x') < left.get('x')) {
954+
return p;
955+
} else {
956+
return left;
957+
}
958+
});
959+
},
960+
961+
get_right_panel: function(panels) {
962+
// right panel is one where x is greater
963+
return panels.reduce(function(right, p){
964+
if (p.get('x') > right.get('x')) {
965+
return p;
966+
} else {
967+
return right;
806968
}
807969
});
808970
},

0 commit comments

Comments
 (0)