Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: scrollbar #254

Merged
merged 1 commit into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions crates/buildtools/src/generate.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
fn main() {
use gents::FileGroup;
use logisheets_controller::controller::display::CellPosition;
use logisheets_controller::controller::display::DisplayWindowWithStartPoint;
use logisheets_controller::controller::display::{
DisplayResponse, DisplaySheetRequest, DisplayWindowRequest, SheetInfo,
};
use logisheets_controller::edit_action::AsyncFuncResult;
use logisheets_controller::edit_action::{ActionEffect, EditAction};
use logisheets_controller::CellInfo;
use logisheets_controller::ErrorMessage;
use gents::FileGroup;
use logisheets_controller::controller::display::{
CellPosition, DisplayResponse, DisplaySheetRequest, DisplayWindowRequest,
DisplayWindowWithStartPoint, SheetInfo,
};
use logisheets_controller::edit_action::{ActionEffect, AsyncFuncResult, EditAction};
use logisheets_controller::{CellInfo, ErrorMessage, SheetDimension};

fn main() {
let path = "packages/web/src/bindings";
let mut file_group = FileGroup::new();
file_group.add::<DisplaySheetRequest>();
Expand All @@ -21,6 +18,7 @@ fn main() {
file_group.add::<SheetInfo>();
file_group.add::<ActionEffect>();
file_group.add::<AsyncFuncResult>();
file_group.add::<SheetDimension>();

file_group.add::<CellInfo>();
file_group.add::<ErrorMessage>();
Expand Down
12 changes: 12 additions & 0 deletions crates/controller/src/api/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,15 @@ pub struct CellInfo {
pub style: Style,
pub block_id: Option<BlockId>,
}

#[cfg_attr(
feature = "gents",
gents_derives::gents_header(file_name = "sheet_dimension.ts")
)]
#[derive(Debug, Clone)]
pub struct SheetDimension {
pub max_row: usize,
pub max_col: usize,
pub height: f64,
pub width: f64,
}
57 changes: 37 additions & 20 deletions crates/controller/src/api/worksheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use logisheets_base::{BlockId, CellId, ColId, RowId, SheetId};
use logisheets_parser::unparse;

use super::workbook::CellPositionerDefault;
use super::SheetDimension;

// Use a cache to record the coordinate
pub struct Worksheet<'a> {
Expand Down Expand Up @@ -473,35 +474,51 @@ impl<'a> Worksheet<'a> {
}

/// Get the dimension of the sheet.
pub fn get_sheet_dimension(&self) -> (usize, usize) {
pub fn get_sheet_dimension(&self) -> Result<SheetDimension> {
let sheet_container = self
.controller
.status
.container
.get_sheet_container(self.sheet_id);
if sheet_container.is_none() {
return (0, 0);
return Ok(SheetDimension {
max_row: 0,
max_col: 0,
height: 0.,
width: 0.,
});
}
let sheet_container = sheet_container.unwrap();
sheet_container
.cells
.clone()
.iter()
.fold((0, 0), |(r, c), (id, _)| {
let cell_idx = self
.controller
.status
.navigator
.fetch_cell_idx(&self.sheet_id, id);
match cell_idx {
Ok((row, col)) => {
let r = if r > row { r } else { row };
let c = if c > col { c } else { col };
(r, c)
let (max_row, max_col) =
sheet_container
.cells
.clone()
.iter()
.fold((0, 0), |(r, c), (id, _)| {
let cell_idx = self
.controller
.status
.navigator
.fetch_cell_idx(&self.sheet_id, id);
match cell_idx {
Ok((row, col)) => {
let r = if r > row { r } else { row };
let c = if c > col { c } else { col };
(r, c)
}
Err(_) => (r, c),
}
Err(_) => (r, c),
}
})
});
let CellPosition {
y: start_row,
x: start_col,
} = self.get_cell_position(max_row, max_col)?;
Ok(SheetDimension {
max_row,
max_col,
height: start_row,
width: start_col,
})
}

pub fn get_row_info(&self, row: usize) -> Option<RowInfo> {
Expand Down
14 changes: 14 additions & 0 deletions crates/wasms/server/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,20 @@ pub fn get_cell_position(id: usize, sheet_idx: usize, row: usize, col: usize) ->
serde_wasm_bindgen::to_value(&result).unwrap()
}

#[wasm_bindgen]
pub fn get_sheet_dimension(id: usize, sheet_idx: usize) -> JsValue {
init();
let manager = MANAGER.get();
let result = manager
.get_workbook(&id)
.unwrap()
.get_sheet_by_idx(sheet_idx)
.unwrap()
.get_sheet_dimension();
handle_result!(result);
serde_wasm_bindgen::to_value(&result).unwrap()
}

#[wasm_bindgen]
/// logisheets_controller::DisplayResponse
pub fn get_patches(id: usize, sheet_idx: u32, version: u32) -> JsValue {
Expand Down
8 changes: 7 additions & 1 deletion packages/web/src/api/worksheet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
get_display_window_within_cell,
get_cell_position,
get_all_fully_covered_blocks,
get_sheet_dimension,
} from '../../wasm'
import {
BlockInfo,
Expand All @@ -22,8 +23,9 @@ import {
RowInfo,
Style,
Value,
CellInfo,
SheetDimension,
} from '../bindings'
import {CellInfo} from '../bindings/cell_info'
import {Cell} from './cell'
import {isErrorMessage, Result} from './utils'

Expand All @@ -33,6 +35,10 @@ export class Worksheet {
this._sheetIdx = idx
}

public getSheetDimension(): Result<SheetDimension> {
return get_sheet_dimension(this._id, this._sheetIdx)
}

public getDisplayWindow(
startRow: number,
endRow: number,
Expand Down
1 change: 1 addition & 0 deletions packages/web/src/bindings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export * from './set_visible'
export * from './sheet_blocks'
export * from './sheet_col_info'
export * from './sheet_comments'
export * from './sheet_dimension'
export * from './sheet_info'
export * from './sheet_merge_cells'
export * from './sheet_names'
Expand Down
8 changes: 8 additions & 0 deletions packages/web/src/bindings/sheet_dimension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// DO NOT EDIT. CODE GENERATED BY gents.

export interface SheetDimension {
maxRow: number
maxCol: number
height: number
width: number
}
1 change: 1 addition & 0 deletions packages/web/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type {
SheetBlocks,
SheetColInfo,
SheetComments,
SheetDimension,
SheetInfo,
SheetMergeCells,
SheetNames,
Expand Down
1 change: 1 addition & 0 deletions src/components/canvas/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const Internal: FC<CanvasProps> = observer((props: CanvasProps) => {
lastScrollTime = now
store.setAnchor(store.anchorX, store.anchorY + e.deltaY)
store.render.render()
store.scrollbar.update('y')
store.scroll()
}

Expand Down
2 changes: 2 additions & 0 deletions src/components/canvas/store/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ export class Render {
)
this.render()
this._jumpToCellInCurrentView(row, col)
this.store.scrollbar.update('x')
this.store.scrollbar.update('y')
})
}

Expand Down
67 changes: 56 additions & 11 deletions src/components/canvas/store/scrollbar.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {action, makeObservable, observable} from 'mobx'
import {CanvasStore} from './store'
import {ScrollbarAttr, ScrollbarType} from '@/components/scrollbar'
import type {ScrollbarAttr, ScrollbarType} from '@/components/scrollbar'
import {CANVAS_OFFSET} from '@/core/data2'
import {isErrorMessage} from 'logisheets-web'
import {ptToPx, widthToPx} from '@/core'

export class ScrollBar {
constructor(public readonly store: CanvasStore) {
Expand All @@ -16,25 +18,65 @@ export class ScrollBar {

@action
init() {
this.store.dataSvc
.getSheetDimension(this.store.currSheetIdx)
.then((v) => {
if (isErrorMessage(v)) {
throw Error(
`failed to get sheet dimension: ${this.store.currSheetIdx}`
)
}

this._init(ptToPx(v.height), widthToPx(v.width))
})
}

@action
_init(dimensionHeight: number, dimensionWidth: number) {
const {offsetHeight: height, offsetWidth: width} =
this.store.render.canvas
const h = Math.max(dimensionHeight, height + CANVAS_OFFSET)
const w = Math.max(dimensionWidth, width + CANVAS_OFFSET)
this.xScrollbar.scrollTop = this.store.anchorX
this.xScrollbar.scrollHeight = w
this.xScrollbar.offsetHeight = width
this.xScrollbar.scrollHeight = width + CANVAS_OFFSET
this.yScrollbar.scrollTop = this.store.anchorY
this.yScrollbar.scrollHeight = h
this.yScrollbar.offsetHeight = height
this.yScrollbar.scrollHeight = height + CANVAS_OFFSET

this._appropriateHeight = h
this._appropriateWidth = w
}

@action
onResize() {
const {offsetHeight: canvasHeight, offsetWidth: canvasWidth} =
this.store.render.canvas
const scrollWidth = canvasWidth + CANVAS_OFFSET
const scrollHeight = +canvasHeight + CANVAS_OFFSET
this.init()
}

this.xScrollbar.offsetHeight = canvasWidth
this.xScrollbar.scrollHeight = scrollWidth
this.yScrollbar.offsetHeight = canvasHeight
this.yScrollbar.scrollHeight = scrollHeight
/**
* Make sure this happens after the anchor X or Y is updated.
*/
@action
update(type: ScrollbarType) {
const {offsetHeight: height, offsetWidth: width} =
this.store.render.canvas
if (type === 'x') {
this.xScrollbar.scrollTop = this.store.anchorX
const viewLength = this.store.anchorX + width
if (this.store.anchorX + width > this.xScrollbar.scrollHeight) {
this.xScrollbar.scrollHeight = this.store.anchorX + width
} else if (viewLength < this._appropriateWidth) {
this.xScrollbar.scrollHeight = this._appropriateWidth
}
} else {
this.yScrollbar.scrollTop = this.store.anchorY
const viewLength = this.store.anchorY + height
if (viewLength > this.yScrollbar.scrollHeight) {
this.yScrollbar.scrollHeight = viewLength + CANVAS_OFFSET
} else if (viewLength < this._appropriateHeight) {
this.yScrollbar.scrollHeight = this._appropriateHeight
}
}
}

@action
Expand All @@ -46,4 +88,7 @@ export class ScrollBar {
}
this.store.render.render()
}

private _appropriateHeight: number = 0
private _appropriateWidth: number = 0
}
14 changes: 7 additions & 7 deletions src/components/scrollbar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export * from './scroll_event'
export type ScrollbarType = 'x' | 'y'
export interface ScrollbarAttr {
offsetHeight?: number
scrollHeight?: number
scrollHeight: number
scrollTop?: number
minThumbLength?: number
direction: ScrollbarType
Expand Down Expand Up @@ -48,29 +48,29 @@ export const ScrollbarComponent: FC<ScrollbarProps> = ({
* The difference between clientHeight, offsetHeight, scrollHeight, offsetTop, and scrollTop
* https://www.programmersought.com/article/76801676023/
*/
const scrollRadio =
const scrollRatio =
scrollHeight === 0 ? 0 : scrollTop / scrollHeight
const thumbRadio =
const thumbRatio =
scrollHeight === 0 ? 0 : offsetHeight / scrollHeight
const containerStyle = getComputedStyle(thumbContainer)
const newThumbStyle: CSSProperties = {}
if (xScrollbar()) {
const containerLength = parseFloat(containerStyle.width)
const thumbWidth = containerLength * thumbRadio
const thumbWidth = containerLength * thumbRatio
const thumbLength = Math.max(thumbWidth, minThumbLength)
newThumbStyle.width =
thumbLength === containerLength ? 0 : toPx(thumbLength)
const left = scrollRadio * containerLength
const left = scrollRatio * containerLength
if (left + thumbLength > containerLength) {
newThumbStyle.right = 0
} else newThumbStyle.left = toPx(left)
} else {
const containerLength = parseFloat(containerStyle.height)
const thumbHeight = thumbContainer.offsetHeight * thumbRadio
const thumbHeight = thumbContainer.offsetHeight * thumbRatio
const thumbLength = Math.max(thumbHeight, minThumbLength)
newThumbStyle.height =
thumbLength === containerLength ? 0 : toPx(thumbLength)
const top = scrollRadio * containerLength
const top = scrollRatio * containerLength
if (top + thumbLength > containerLength) {
newThumbStyle.bottom = 0
} else newThumbStyle.top = toPx(top)
Expand Down
1 change: 0 additions & 1 deletion src/components/sheets-tab/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export const SheetsTabComponent: FC<SheetTabProps> = ({
const onTabChange = (key: string) => {
const i = sheets.findIndex((s) => s === key)
activeSheet$(i)
DATA_SERVICE.setCurrentSheetIdx(i)
}

const add = () => {
Expand Down
Loading
Loading