UPDATE: Double click resizes columns/rows automatically
This commit is contained in:
committed by
Nicolás Hatcher Andrés
parent
4095b7db6e
commit
fc7335707a
@@ -307,7 +307,13 @@ impl Model {
|
|||||||
// This two are only used when we want to compute the automatic width of a column or height of a row
|
// This two are only used when we want to compute the automatic width of a column or height of a row
|
||||||
#[wasm_bindgen(js_name = "getRowsWithData")]
|
#[wasm_bindgen(js_name = "getRowsWithData")]
|
||||||
pub fn get_rows_with_data(&self, sheet: u32, column: i32) -> Result<Vec<i32>, JsError> {
|
pub fn get_rows_with_data(&self, sheet: u32, column: i32) -> Result<Vec<i32>, JsError> {
|
||||||
let sheet_data = &self.model.get_model().workbook.worksheet(sheet).map_err(to_js_error)?.sheet_data;
|
let sheet_data = &self
|
||||||
|
.model
|
||||||
|
.get_model()
|
||||||
|
.workbook
|
||||||
|
.worksheet(sheet)
|
||||||
|
.map_err(to_js_error)?
|
||||||
|
.sheet_data;
|
||||||
Ok(sheet_data
|
Ok(sheet_data
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, data)| data.contains_key(&column))
|
.filter(|(_, data)| data.contains_key(&column))
|
||||||
@@ -317,9 +323,12 @@ impl Model {
|
|||||||
|
|
||||||
#[wasm_bindgen(js_name = "getColumnsWithData")]
|
#[wasm_bindgen(js_name = "getColumnsWithData")]
|
||||||
pub fn get_columns_with_data(&self, sheet: u32, row: i32) -> Result<Vec<i32>, JsError> {
|
pub fn get_columns_with_data(&self, sheet: u32, row: i32) -> Result<Vec<i32>, JsError> {
|
||||||
Ok(self.model.get_model()
|
Ok(self
|
||||||
|
.model
|
||||||
|
.get_model()
|
||||||
.workbook
|
.workbook
|
||||||
.worksheet(sheet).map_err(to_js_error)?
|
.worksheet(sheet)
|
||||||
|
.map_err(to_js_error)?
|
||||||
.sheet_data
|
.sheet_data
|
||||||
.get(&row)
|
.get(&row)
|
||||||
.map(|row_data| row_data.keys().copied().collect())
|
.map(|row_data| row_data.keys().copied().collect())
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export interface CanvasSettings {
|
|||||||
};
|
};
|
||||||
onColumnWidthChanges: (sheet: number, column: number, width: number) => void;
|
onColumnWidthChanges: (sheet: number, column: number, width: number) => void;
|
||||||
onRowHeightChanges: (sheet: number, row: number, height: number) => void;
|
onRowHeightChanges: (sheet: number, row: number, height: number) => void;
|
||||||
|
refresh: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fonts = {
|
export const fonts = {
|
||||||
@@ -106,6 +107,8 @@ export default class WorksheetCanvas {
|
|||||||
|
|
||||||
onRowHeightChanges: (sheet: number, row: number, height: number) => void;
|
onRowHeightChanges: (sheet: number, row: number, height: number) => void;
|
||||||
|
|
||||||
|
refresh: () => void;
|
||||||
|
|
||||||
constructor(options: CanvasSettings) {
|
constructor(options: CanvasSettings) {
|
||||||
this.model = options.model;
|
this.model = options.model;
|
||||||
this.sheetWidth = 0;
|
this.sheetWidth = 0;
|
||||||
@@ -116,6 +119,7 @@ export default class WorksheetCanvas {
|
|||||||
this.ctx = this.setContext();
|
this.ctx = this.setContext();
|
||||||
this.workbookState = options.workbookState;
|
this.workbookState = options.workbookState;
|
||||||
this.editor = options.elements.editor;
|
this.editor = options.elements.editor;
|
||||||
|
this.refresh = options.refresh;
|
||||||
|
|
||||||
this.cellOutline = options.elements.cellOutline;
|
this.cellOutline = options.elements.cellOutline;
|
||||||
this.cellOutlineHandle = options.elements.cellOutlineHandle;
|
this.cellOutlineHandle = options.elements.cellOutlineHandle;
|
||||||
@@ -580,15 +584,16 @@ export default class WorksheetCanvas {
|
|||||||
document.removeEventListener("pointermove", resizeHandleMove);
|
document.removeEventListener("pointermove", resizeHandleMove);
|
||||||
document.removeEventListener("pointerup", resizeHandleUp);
|
document.removeEventListener("pointerup", resizeHandleUp);
|
||||||
const newColumnWidth = columnWidth + event.pageX - initPageX;
|
const newColumnWidth = columnWidth + event.pageX - initPageX;
|
||||||
this.onColumnWidthChanges(
|
if (newColumnWidth !== columnWidth) {
|
||||||
this.model.getSelectedSheet(),
|
this.onColumnWidthChanges(
|
||||||
column,
|
this.model.getSelectedSheet(),
|
||||||
newColumnWidth,
|
column,
|
||||||
);
|
newColumnWidth,
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
resizeHandleUp = resizeHandleUp.bind(this);
|
resizeHandleUp = resizeHandleUp.bind(this);
|
||||||
div.addEventListener("pointerdown", (event) => {
|
div.addEventListener("pointerdown", (event) => {
|
||||||
event.stopPropagation();
|
|
||||||
div.style.opacity = "1";
|
div.style.opacity = "1";
|
||||||
this.columnGuide.style.display = "block";
|
this.columnGuide.style.display = "block";
|
||||||
this.columnGuide.style.left = `${headerColumnWidth + x}px`;
|
this.columnGuide.style.left = `${headerColumnWidth + x}px`;
|
||||||
@@ -596,6 +601,35 @@ export default class WorksheetCanvas {
|
|||||||
document.addEventListener("pointermove", resizeHandleMove);
|
document.addEventListener("pointermove", resizeHandleMove);
|
||||||
document.addEventListener("pointerup", resizeHandleUp);
|
document.addEventListener("pointerup", resizeHandleUp);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
div.addEventListener("dblclick", (event) => {
|
||||||
|
// This is tough. We should have a call like this.model.setAutofitColumn(sheet, column)
|
||||||
|
// but we can't do that because the back end knows nothing about the rendering engine.
|
||||||
|
const sheet = this.model.getSelectedSheet();
|
||||||
|
const rows = this.model.getRowsWithData(sheet, column);
|
||||||
|
let width = 0;
|
||||||
|
// This is a bit of a HACK. We should use the actual font size and weather is bold or not
|
||||||
|
const fontSize = 13;
|
||||||
|
this.ctx.font = `${fontSize}px ${defaultCellFontFamily}`;
|
||||||
|
for (const row of rows) {
|
||||||
|
const fullText = this.model.getFormattedCellValue(sheet, row, column);
|
||||||
|
if (fullText === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const lines = fullText.split("\n");
|
||||||
|
for (const line of lines) {
|
||||||
|
const textWidth = this.ctx.measureText(line).width;
|
||||||
|
width = Math.max(width, textWidth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the width is 0, we do nothing
|
||||||
|
if (width !== 0) {
|
||||||
|
// The +8 is so that the text is in the same position regardless of the horizontal alignment
|
||||||
|
this.model.setColumnsWidth(sheet, column, column, width + 8);
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private addRowResizeHandle(y: number, row: number, rowHeight: number): void {
|
private addRowResizeHandle(y: number, row: number, rowHeight: number): void {
|
||||||
@@ -618,8 +652,10 @@ export default class WorksheetCanvas {
|
|||||||
this.rowGuide.style.display = "none";
|
this.rowGuide.style.display = "none";
|
||||||
document.removeEventListener("pointermove", resizeHandleMove);
|
document.removeEventListener("pointermove", resizeHandleMove);
|
||||||
document.removeEventListener("pointerup", resizeHandleUp);
|
document.removeEventListener("pointerup", resizeHandleUp);
|
||||||
const newRowHeight = rowHeight + event.pageY - initPageY - 1;
|
const newRowHeight = rowHeight + event.pageY - initPageY;
|
||||||
this.onRowHeightChanges(sheet, row, newRowHeight);
|
if (newRowHeight !== rowHeight) {
|
||||||
|
this.onRowHeightChanges(sheet, row, newRowHeight);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
resizeHandleUp = resizeHandleUp.bind(this);
|
resizeHandleUp = resizeHandleUp.bind(this);
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
@@ -632,6 +668,35 @@ export default class WorksheetCanvas {
|
|||||||
document.addEventListener("pointermove", resizeHandleMove);
|
document.addEventListener("pointermove", resizeHandleMove);
|
||||||
document.addEventListener("pointerup", resizeHandleUp);
|
document.addEventListener("pointerup", resizeHandleUp);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
div.addEventListener("dblclick", (event) => {
|
||||||
|
// This is tough. We should have a call like this.model.setAutofitRow(sheet, row)
|
||||||
|
// but we can't do that because the back end knows nothing about the rendering engine.
|
||||||
|
const sheet = this.model.getSelectedSheet();
|
||||||
|
const columns = this.model.getColumnsWithData(sheet, row);
|
||||||
|
let height = 0;
|
||||||
|
const lineHeight = 22;
|
||||||
|
// This is a bit of a HACK. We should use the actual font size and weather is bold or not
|
||||||
|
const fontSize = 13;
|
||||||
|
this.ctx.font = `${fontSize}px ${defaultCellFontFamily}`;
|
||||||
|
for (const column of columns) {
|
||||||
|
const fullText = this.model.getFormattedCellValue(sheet, row, column);
|
||||||
|
if (fullText === "") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const lines = fullText.split("\n");
|
||||||
|
const lineCount = lines.length;
|
||||||
|
// This si computed so that the y position of the text is independent of the vertical alignment
|
||||||
|
const textHeight = (lineCount - 1) * lineHeight + 8 + fontSize;
|
||||||
|
height = Math.max(height, textHeight);
|
||||||
|
}
|
||||||
|
// If the height is 0, we do nothing
|
||||||
|
if (height !== 0) {
|
||||||
|
this.model.setRowsHeight(sheet, row, row, height);
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
event.stopPropagation();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private styleColumnHeader(
|
private styleColumnHeader(
|
||||||
|
|||||||
@@ -119,6 +119,11 @@ const usePointer = (options: PointerSettings): PointerEvents => {
|
|||||||
|
|
||||||
const onPointerDown = useCallback(
|
const onPointerDown = useCallback(
|
||||||
(event: PointerEvent) => {
|
(event: PointerEvent) => {
|
||||||
|
const target = event.target as HTMLElement;
|
||||||
|
if (target !== null && target.className === "column-resize-handle") {
|
||||||
|
// we are resizing a column
|
||||||
|
return;
|
||||||
|
}
|
||||||
let x = event.clientX;
|
let x = event.clientX;
|
||||||
let y = event.clientY;
|
let y = event.clientY;
|
||||||
const {
|
const {
|
||||||
|
|||||||
@@ -115,7 +115,14 @@ function Worksheet(props: {
|
|||||||
const { range } = model.getSelectedView();
|
const { range } = model.getSelectedView();
|
||||||
let columnStart = column;
|
let columnStart = column;
|
||||||
let columnEnd = column;
|
let columnEnd = column;
|
||||||
if (column >= range[1] && column <= range[3]) {
|
const fullColumn = range[0] === 1 && range[2] === LAST_ROW;
|
||||||
|
const fullRow = range[1] === 1 && range[3] === LAST_COLUMN;
|
||||||
|
if (
|
||||||
|
fullColumn &&
|
||||||
|
column >= range[1] &&
|
||||||
|
column <= range[3] &&
|
||||||
|
!fullRow
|
||||||
|
) {
|
||||||
columnStart = Math.min(range[1], column, range[3]);
|
columnStart = Math.min(range[1], column, range[3]);
|
||||||
columnEnd = Math.max(range[1], column, range[3]);
|
columnEnd = Math.max(range[1], column, range[3]);
|
||||||
}
|
}
|
||||||
@@ -129,13 +136,16 @@ function Worksheet(props: {
|
|||||||
const { range } = model.getSelectedView();
|
const { range } = model.getSelectedView();
|
||||||
let rowStart = row;
|
let rowStart = row;
|
||||||
let rowEnd = row;
|
let rowEnd = row;
|
||||||
if (row >= range[0] && row <= range[2]) {
|
const fullColumn = range[0] === 1 && range[2] === LAST_ROW;
|
||||||
|
const fullRow = range[1] === 1 && range[3] === LAST_COLUMN;
|
||||||
|
if (fullRow && row >= range[0] && row <= range[2] && !fullColumn) {
|
||||||
rowStart = Math.min(range[0], row, range[2]);
|
rowStart = Math.min(range[0], row, range[2]);
|
||||||
rowEnd = Math.max(range[0], row, range[2]);
|
rowEnd = Math.max(range[0], row, range[2]);
|
||||||
}
|
}
|
||||||
model.setRowsHeight(sheet, rowStart, rowEnd, height);
|
model.setRowsHeight(sheet, rowStart, rowEnd, height);
|
||||||
worksheetCanvas.current?.renderSheet();
|
worksheetCanvas.current?.renderSheet();
|
||||||
},
|
},
|
||||||
|
refresh,
|
||||||
});
|
});
|
||||||
const scrollX = model.getScrollX();
|
const scrollX = model.getScrollX();
|
||||||
const scrollY = model.getScrollY();
|
const scrollY = model.getScrollY();
|
||||||
|
|||||||
Reference in New Issue
Block a user