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

refactor: use a new data sevice which provides only required render data #236

Merged
merged 1 commit into from
Dec 7, 2024
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
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"src/bindings/**/*",
"crates/wasms/**/*",
"packages/**/bindings/**/*",
"packages/**/dist/**/*",
"packages/**/wasm/**/*"
],
"rules": {
Expand Down
9 changes: 7 additions & 2 deletions crates/buildtools/src/generate.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
fn main() {
use gents::FileGroup;
use logisheets_controller::controller::display::CellPosition;
use logisheets_controller::controller::display::DisplayWindowWithStartPoint;
use logisheets_controller::controller::display::{DisplayRequest, DisplayResponse, SheetInfo};
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;

let path = "packages/web/src/bindings";
let mut file_group = FileGroup::new();
file_group.add::<DisplayRequest>();
file_group.add::<DisplaySheetRequest>();
file_group.add::<DisplayWindowRequest>();
file_group.add::<DisplayResponse>();
file_group.add::<CellPosition>();
file_group.add::<DisplayWindowWithStartPoint>();
file_group.add::<EditAction>();
file_group.add::<SheetInfo>();
Expand Down
186 changes: 186 additions & 0 deletions crates/controller/src/api/cell_positioner.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
use itertools::Itertools;

use super::worksheet::Worksheet;
use crate::errors::Result;

#[derive(Debug, Clone)]
pub struct CellPositioner<const INTERVAL: usize> {
cache_height: Vec<(usize, f64)>,
cache_width: Vec<(usize, f64)>,
}

impl<const INTERVAL: usize> CellPositioner<INTERVAL> {
pub fn new() -> Self {
CellPositioner {
cache_height: vec![],
cache_width: vec![],
}
}

pub fn clear(&mut self) {
self.cache_height = vec![];
self.cache_width = vec![];
}

pub fn get_row_start_y(&mut self, row: usize, ws: &Worksheet) -> Result<f64> {
let (mut curr, mut result) = self.find_closest_cache_height(row);
if curr == row {
return Ok(result);
}
let reverse = curr > row;

while curr != row {
if ws.is_row_hidden(row) {
curr = advance(reverse, curr);
continue;
}
let h = ws.get_row_height(curr)?;
result += h;
self.add_cache(true, curr, result);
}
Ok(result)
}

pub fn get_col_start_x(&mut self, col: usize, ws: &Worksheet) -> Result<f64> {
let (mut curr, mut result) = self.find_closest_cache_width(col);
if curr == col {
return Ok(result);
}
let reverse = curr > col;

while curr != col {
if ws.is_col_hidden(col) {
curr = advance(reverse, curr);
continue;
}
let h = ws.get_row_height(curr)?;
result += h;
self.add_cache(true, curr, result);
}
Ok(result)
}

pub fn get_nearest_row_before_given_y(
&mut self,
y: f64,
ws: &Worksheet,
) -> Result<(usize, f64)> {
let (mut curr_idx, mut curr_h) = self.find_closest_cache_before_y(y);
let mut h = 0.;
while curr_h < y {
if ws.is_row_hidden(curr_idx) {
curr_idx += 1;
continue;
}
h = ws.get_row_height(curr_idx)?;
curr_idx += 1;
curr_h += h;
self.add_cache(true, curr_idx, curr_h);
}

return Ok((curr_idx - 1, curr_h - h));
}

pub fn get_nearest_col_before_given_x(
&mut self,
x: f64,
ws: &Worksheet,
) -> Result<(usize, f64)> {
let (mut curr_idx, mut curr_w) = self.find_closest_cache_before_x(x);
let mut w = 0.;
while curr_w < x {
if ws.is_row_hidden(curr_idx) {
curr_idx += 1;
continue;
}
w = ws.get_row_height(curr_idx)?;
curr_idx += 1;
curr_w += w;
self.add_cache(false, curr_idx, curr_w);
}

return Ok((curr_idx - 1, curr_w - w));
}

fn find_closest_cache_before_x(&self, x: f64) -> (usize, f64) {
if self.cache_width.is_empty() {
return (0, 0.);
}

let r = self.cache_width.iter().find_position(|(_, v)| *v > x);
if let Some((idx, _)) = r {
self.cache_width.get(idx - 1).unwrap().clone()
} else {
self.cache_width.last().unwrap().clone()
}
}

fn find_closest_cache_before_y(&self, y: f64) -> (usize, f64) {
if self.cache_height.is_empty() {
return (0, 0.);
}

let r = self.cache_height.iter().find_position(|(_, v)| *v > y);
if let Some((idx, _)) = r {
self.cache_height.get(idx - 1).unwrap().clone()
} else {
self.cache_height.last().unwrap().clone()
}
}

fn find_closest_cache_width(&self, col: usize) -> (usize, f64) {
if self.cache_width.is_empty() {
return (0, 0.);
}

for (c, x) in self.cache_width.iter() {
if c.abs_diff(col) <= INTERVAL / 2 {
return (*c, *x);
}
}
let result = self.cache_width.last().unwrap();
*result
}

fn find_closest_cache_height(&self, row: usize) -> (usize, f64) {
if self.cache_height.is_empty() {
return (0, 0.);
}

for (r, y) in self.cache_height.iter() {
if r.abs_diff(row) <= usize::from(INTERVAL / 2) {
return (*r, *y);
}
}
let result = self.cache_height.last().unwrap();
*result
}

fn add_cache(&mut self, height: bool, k: usize, v: f64) -> bool {
let cache = if height {
&mut self.cache_height
} else {
&mut self.cache_width
};
if cache.is_empty() {
cache.push((k, v));
return true;
}

let last = cache.last().unwrap();
if k - last.0 >= INTERVAL {
cache.push((k, v));
return true;
}
return false;
}
}

#[inline]
fn advance(reverse: bool, curr: usize) -> usize {
if reverse {
curr - 1
} else {
curr + 1
}
}
1 change: 1 addition & 0 deletions crates/controller/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub use crate::{
errors::{Error, ErrorMessage, Result},
Comment, MergeCell, Style, Value,
};
mod cell_positioner;
mod types;
mod workbook;
mod worksheet;
Expand Down
50 changes: 39 additions & 11 deletions crates/controller/src/api/workbook.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use super::worksheet::Worksheet;
use std::collections::HashMap;

use super::{cell_positioner::CellPositioner, worksheet::Worksheet};
use crate::{
controller::display::{DisplayRequest, DisplayResponse, SheetInfo},
controller::display::{DisplayResponse, DisplaySheetRequest, SheetInfo},
edit_action::{ActionEffect, StatusCode},
lock::{locked_write, new_locked, Locked},
Controller,
};
use crate::{
Expand All @@ -11,16 +14,21 @@ use crate::{
use logisheets_base::{
async_func::{AsyncCalcResult, Task},
errors::BasicError,
SheetId,
};

pub(crate) type CellPositionerDefault = CellPositioner<1000>;

pub struct Workbook {
controller: Controller,
cell_positioners: Locked<HashMap<SheetId, Locked<CellPositionerDefault>>>,
}

impl Default for Workbook {
fn default() -> Self {
Self {
controller: Default::default(),
cell_positioners: new_locked(HashMap::new()),
}
}
}
Expand All @@ -30,6 +38,7 @@ impl Workbook {
pub fn new() -> Self {
Workbook {
controller: Default::default(),
cell_positioners: new_locked(HashMap::new()),
}
}

Expand All @@ -41,7 +50,10 @@ impl Workbook {
/// Create a workbook from a .xlsx file.
pub fn from_file(buf: &[u8], book_name: String) -> Result<Self> {
let controller = Controller::from_file(book_name, buf)?;
Ok(Workbook { controller })
Ok(Workbook {
controller,
cell_positioners: new_locked(HashMap::new()),
})
}

#[inline]
Expand All @@ -60,8 +72,8 @@ impl Workbook {
}

#[inline]
pub fn get_display_response(&self, req: DisplayRequest) -> DisplayResponse {
self.controller.get_display_response(req)
pub fn get_display_sheet_response(&self, req: DisplaySheetRequest) -> Result<DisplayResponse> {
self.controller.get_display_sheet_response(req)
}

#[inline]
Expand All @@ -85,14 +97,29 @@ impl Workbook {
self.controller.get_all_sheet_info()
}

#[inline]
pub fn get_cell_positioner(&self, sheet: SheetId) -> Locked<CellPositionerDefault> {
let mut cell_positioners = locked_write(&self.cell_positioners);
let entry = cell_positioners
.entry(sheet)
.or_insert_with(|| new_locked(CellPositionerDefault::new()));

entry.clone()
}

pub fn get_sheet_by_name(&self, name: &str) -> Result<Worksheet> {
match self.controller.get_sheet_id_by_name(name) {
Some(sheet_id) => Ok(Worksheet {
sheet_id,
controller: &self.controller,
}),
None => Err(BasicError::SheetNameNotFound(name.to_string()).into()),
let id = self.controller.get_sheet_id_by_name(name);
if id.is_none() {
return Err(BasicError::SheetNameNotFound(name.to_string()).into());
}
let sheet_id = id.unwrap();
let positioner = self.get_cell_positioner(sheet_id);
let c = &self.controller;
Ok(Worksheet {
sheet_id,
controller: c,
positioner,
})
}

pub fn get_sheet_idx_by_name(&self, name: &str) -> Result<usize> {
Expand All @@ -113,6 +140,7 @@ impl Workbook {
Some(sheet_id) => Ok(Worksheet {
sheet_id,
controller: &self.controller,
positioner: self.get_cell_positioner(sheet_id),
}),
None => Err(Error::UnavailableSheetIdx(idx)),
}
Expand Down
Loading
Loading