Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c13f241c6 | ||
|
|
26b20eea43 | ||
|
|
b62256963a | ||
|
|
4f627b4363 |
8
.github/workflows/pypi.yml
vendored
8
.github/workflows/pypi.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
|||||||
manylinux: auto
|
manylinux: auto
|
||||||
working-directory: bindings/python
|
working-directory: bindings/python
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels
|
||||||
path: bindings/python/dist
|
path: bindings/python/dist
|
||||||
@@ -56,7 +56,7 @@ jobs:
|
|||||||
sccache: 'true'
|
sccache: 'true'
|
||||||
working-directory: bindings/python
|
working-directory: bindings/python
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels
|
||||||
path: bindings/python/dist
|
path: bindings/python/dist
|
||||||
@@ -79,7 +79,7 @@ jobs:
|
|||||||
sccache: 'true'
|
sccache: 'true'
|
||||||
working-directory: bindings/python
|
working-directory: bindings/python
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels
|
||||||
path: bindings/python/dist
|
path: bindings/python/dist
|
||||||
@@ -95,7 +95,7 @@ jobs:
|
|||||||
args: --out dist
|
args: --out dist
|
||||||
working-directory: bindings/python
|
working-directory: bindings/python
|
||||||
- name: Upload sdist
|
- name: Upload sdist
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels
|
||||||
path: bindings/python/dist
|
path: bindings/python/dist
|
||||||
|
|||||||
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -414,7 +414,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ironcalc"
|
name = "ironcalc"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcode",
|
"bitcode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -430,7 +430,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ironcalc_base"
|
name = "ironcalc_base"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitcode",
|
"bitcode",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -448,7 +448,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ironcalc_nodejs"
|
name = "ironcalc_nodejs"
|
||||||
version = "0.3.1"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ironcalc",
|
"ironcalc",
|
||||||
"napi",
|
"napi",
|
||||||
@@ -784,7 +784,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyroncalc"
|
name = "pyroncalc"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ironcalc",
|
"ironcalc",
|
||||||
"pyo3",
|
"pyo3",
|
||||||
@@ -1070,7 +1070,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm"
|
name = "wasm"
|
||||||
version = "0.3.2"
|
version = "0.5.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ironcalc_base",
|
"ironcalc_base",
|
||||||
"serde",
|
"serde",
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ And visit <http://0.0.0.0:8000/ironcalc/>
|
|||||||
Add the dependency to `Cargo.toml`:
|
Add the dependency to `Cargo.toml`:
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ironcalc = { git = "https://github.com/ironcalc/IronCalc", version = "0.1"}
|
ironcalc = { git = "https://github.com/ironcalc/IronCalc", version = "0.5"}
|
||||||
```
|
```
|
||||||
|
|
||||||
And then use this code in `main.rs`:
|
And then use this code in `main.rs`:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ironcalc_base"
|
name = "ironcalc_base"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
authors = ["Nicolás Hatcher <nicolas@theuniverse.today>"]
|
authors = ["Nicolás Hatcher <nicolas@theuniverse.today>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
homepage = "https://www.ironcalc.com"
|
homepage = "https://www.ironcalc.com"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
name = "ironcalc_nodejs"
|
name = "ironcalc_nodejs"
|
||||||
version = "0.3.1"
|
version = "0.5.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
@@ -10,7 +10,7 @@ crate-type = ["cdylib"]
|
|||||||
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
|
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
|
||||||
napi = { version = "2.12.2", default-features = false, features = ["napi4", "serde-json"] }
|
napi = { version = "2.12.2", default-features = false, features = ["napi4", "serde-json"] }
|
||||||
napi-derive = "2.12.2"
|
napi-derive = "2.12.2"
|
||||||
ironcalc = { path = "../../xlsx", version = "0.3.0" }
|
ironcalc = { path = "../../xlsx", version = "0.5.0" }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ironcalc/nodejs",
|
"name": "@ironcalc/nodejs",
|
||||||
"version": "0.3.1",
|
"version": "0.5.1",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"types": "index.d.ts",
|
"types": "index.d.ts",
|
||||||
"napi": {
|
"napi": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "pyroncalc"
|
name = "pyroncalc"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ crate-type = ["cdylib"]
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
xlsx = { package= "ironcalc", path = "../../xlsx", version = "0.3.0" }
|
xlsx = { package= "ironcalc", path = "../../xlsx", version = "0.5.0" }
|
||||||
pyo3 = { version = "0.23", features = ["extension-module"] }
|
pyo3 = { version = "0.23", features = ["extension-module"] }
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ironcalc"
|
name = "ironcalc"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
description = "Create, edit and evaluate Excel spreadsheets"
|
description = "Create, edit and evaluate Excel spreadsheets"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
keywords = [
|
keywords = [
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "wasm"
|
name = "wasm"
|
||||||
version = "0.3.2"
|
version = "0.5.0"
|
||||||
authors = ["Nicolas Hatcher <nicolas@theuniverse.today>"]
|
authors = ["Nicolas Hatcher <nicolas@theuniverse.today>"]
|
||||||
description = "IronCalc Web bindings"
|
description = "IronCalc Web bindings"
|
||||||
license = "MIT/Apache-2.0"
|
license = "MIT/Apache-2.0"
|
||||||
@@ -14,7 +14,7 @@ crate-type = ["cdylib"]
|
|||||||
# Uses `../ironcalc/base` when used locally, and uses
|
# Uses `../ironcalc/base` when used locally, and uses
|
||||||
# the inicated version from crates.io when published.
|
# the inicated version from crates.io when published.
|
||||||
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations
|
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations
|
||||||
ironcalc_base = { path = "../../base", version = "0.3", features = ["use_regex_lite"] }
|
ironcalc_base = { path = "../../base", version = "0.5", features = ["use_regex_lite"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
wasm-bindgen = "0.2.92"
|
wasm-bindgen = "0.2.92"
|
||||||
serde-wasm-bindgen = "0.4"
|
serde-wasm-bindgen = "0.4"
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import type {
|
|||||||
import { styled } from "@mui/material/styles";
|
import { styled } from "@mui/material/styles";
|
||||||
import type {} from "@mui/system";
|
import type {} from "@mui/system";
|
||||||
import {
|
import {
|
||||||
AArrowDown,
|
|
||||||
AArrowUp,
|
|
||||||
AlignCenter,
|
AlignCenter,
|
||||||
AlignLeft,
|
AlignLeft,
|
||||||
AlignRight,
|
AlignRight,
|
||||||
@@ -22,9 +20,11 @@ import {
|
|||||||
Grid2x2X,
|
Grid2x2X,
|
||||||
ImageDown,
|
ImageDown,
|
||||||
Italic,
|
Italic,
|
||||||
|
Minus,
|
||||||
PaintBucket,
|
PaintBucket,
|
||||||
PaintRoller,
|
PaintRoller,
|
||||||
Percent,
|
Percent,
|
||||||
|
Plus,
|
||||||
Redo2,
|
Redo2,
|
||||||
RemoveFormatting,
|
RemoveFormatting,
|
||||||
Strikethrough,
|
Strikethrough,
|
||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
Type,
|
Type,
|
||||||
Underline,
|
Underline,
|
||||||
Undo2,
|
Undo2,
|
||||||
|
WrapText,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -64,6 +65,7 @@ type ToolbarProperties = {
|
|||||||
onToggleStrike: (v: boolean) => void;
|
onToggleStrike: (v: boolean) => void;
|
||||||
onToggleHorizontalAlign: (v: string) => void;
|
onToggleHorizontalAlign: (v: string) => void;
|
||||||
onToggleVerticalAlign: (v: string) => void;
|
onToggleVerticalAlign: (v: string) => void;
|
||||||
|
onToggleWrapText: (v: boolean) => void;
|
||||||
onCopyStyles: () => void;
|
onCopyStyles: () => void;
|
||||||
onTextColorPicked: (hex: string) => void;
|
onTextColorPicked: (hex: string) => void;
|
||||||
onFillColorPicked: (hex: string) => void;
|
onFillColorPicked: (hex: string) => void;
|
||||||
@@ -74,12 +76,14 @@ type ToolbarProperties = {
|
|||||||
onDownloadPNG: () => void;
|
onDownloadPNG: () => void;
|
||||||
fillColor: string;
|
fillColor: string;
|
||||||
fontColor: string;
|
fontColor: string;
|
||||||
|
fontSize: number;
|
||||||
bold: boolean;
|
bold: boolean;
|
||||||
underline: boolean;
|
underline: boolean;
|
||||||
italic: boolean;
|
italic: boolean;
|
||||||
strike: boolean;
|
strike: boolean;
|
||||||
horizontalAlign: HorizontalAlignment;
|
horizontalAlign: HorizontalAlignment;
|
||||||
verticalAlign: VerticalAlignment;
|
verticalAlign: VerticalAlignment;
|
||||||
|
wrapText: boolean;
|
||||||
canEdit: boolean;
|
canEdit: boolean;
|
||||||
numFmt: string;
|
numFmt: string;
|
||||||
showGridLines: boolean;
|
showGridLines: boolean;
|
||||||
@@ -205,6 +209,30 @@ function Toolbar(properties: ToolbarProperties) {
|
|||||||
</StyledButton>
|
</StyledButton>
|
||||||
</FormatMenu>
|
</FormatMenu>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
<StyledButton
|
||||||
|
type="button"
|
||||||
|
$pressed={false}
|
||||||
|
disabled={!canEdit}
|
||||||
|
onClick={() => {
|
||||||
|
properties.onIncreaseFontSize(-1);
|
||||||
|
}}
|
||||||
|
title={t("toolbar.decrease_font_size")}
|
||||||
|
>
|
||||||
|
<Minus />
|
||||||
|
</StyledButton>
|
||||||
|
<FontSizeBox>{properties.fontSize}</FontSizeBox>
|
||||||
|
<StyledButton
|
||||||
|
type="button"
|
||||||
|
$pressed={false}
|
||||||
|
disabled={!canEdit}
|
||||||
|
onClick={() => {
|
||||||
|
properties.onIncreaseFontSize(1);
|
||||||
|
}}
|
||||||
|
title={t("toolbar.increase_font_size")}
|
||||||
|
>
|
||||||
|
<Plus />
|
||||||
|
</StyledButton>
|
||||||
|
<Divider />
|
||||||
<StyledButton
|
<StyledButton
|
||||||
type="button"
|
type="button"
|
||||||
$pressed={properties.bold}
|
$pressed={properties.bold}
|
||||||
@@ -253,28 +281,6 @@ function Toolbar(properties: ToolbarProperties) {
|
|||||||
>
|
>
|
||||||
<Type />
|
<Type />
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
<StyledButton
|
|
||||||
type="button"
|
|
||||||
$pressed={false}
|
|
||||||
disabled={!canEdit}
|
|
||||||
onClick={() => {
|
|
||||||
properties.onIncreaseFontSize(1);
|
|
||||||
}}
|
|
||||||
title={t("toolbar.increase_font_size")}
|
|
||||||
>
|
|
||||||
<AArrowUp />
|
|
||||||
</StyledButton>
|
|
||||||
<StyledButton
|
|
||||||
type="button"
|
|
||||||
$pressed={false}
|
|
||||||
disabled={!canEdit}
|
|
||||||
onClick={() => {
|
|
||||||
properties.onIncreaseFontSize(-1);
|
|
||||||
}}
|
|
||||||
title={t("toolbar.decrease_font_size")}
|
|
||||||
>
|
|
||||||
<AArrowDown />
|
|
||||||
</StyledButton>
|
|
||||||
<StyledButton
|
<StyledButton
|
||||||
type="button"
|
type="button"
|
||||||
$pressed={false}
|
$pressed={false}
|
||||||
@@ -363,6 +369,17 @@ function Toolbar(properties: ToolbarProperties) {
|
|||||||
>
|
>
|
||||||
<ArrowDownToLine />
|
<ArrowDownToLine />
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
<StyledButton
|
||||||
|
type="button"
|
||||||
|
$pressed={properties.wrapText === true}
|
||||||
|
onClick={() => {
|
||||||
|
properties.onToggleWrapText(!properties.wrapText);
|
||||||
|
}}
|
||||||
|
disabled={!canEdit}
|
||||||
|
title={t("toolbar.wrap_text")}
|
||||||
|
>
|
||||||
|
<WrapText />
|
||||||
|
</StyledButton>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<StyledButton
|
<StyledButton
|
||||||
@@ -534,4 +551,16 @@ const Divider = styled("div")({
|
|||||||
margin: "0px 12px",
|
margin: "0px 12px",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const FontSizeBox = styled("div")({
|
||||||
|
width: "24px",
|
||||||
|
height: "24px",
|
||||||
|
lineHeight: "24px",
|
||||||
|
textAlign: "center",
|
||||||
|
fontFamily: "Inter",
|
||||||
|
fontSize: "11px",
|
||||||
|
border: `1px solid ${theme.palette.grey["300"]}`,
|
||||||
|
borderRadius: "4px",
|
||||||
|
minWidth: "24px",
|
||||||
|
});
|
||||||
|
|
||||||
export default Toolbar;
|
export default Toolbar;
|
||||||
|
|||||||
@@ -112,6 +112,10 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
updateRangeStyle("alignment.vertical", value);
|
updateRangeStyle("alignment.vertical", value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onToggleWrapText = (value: boolean) => {
|
||||||
|
updateRangeStyle("alignment.wrap_text", `${value}`);
|
||||||
|
};
|
||||||
|
|
||||||
const onTextColorPicked = (hex: string) => {
|
const onTextColorPicked = (hex: string) => {
|
||||||
updateRangeStyle("font.color", hex);
|
updateRangeStyle("font.color", hex);
|
||||||
};
|
};
|
||||||
@@ -532,6 +536,7 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
onToggleStrike={onToggleStrike}
|
onToggleStrike={onToggleStrike}
|
||||||
onToggleHorizontalAlign={onToggleHorizontalAlign}
|
onToggleHorizontalAlign={onToggleHorizontalAlign}
|
||||||
onToggleVerticalAlign={onToggleVerticalAlign}
|
onToggleVerticalAlign={onToggleVerticalAlign}
|
||||||
|
onToggleWrapText={onToggleWrapText}
|
||||||
onCopyStyles={onCopyStyles}
|
onCopyStyles={onCopyStyles}
|
||||||
onTextColorPicked={onTextColorPicked}
|
onTextColorPicked={onTextColorPicked}
|
||||||
onFillColorPicked={onFillColorPicked}
|
onFillColorPicked={onFillColorPicked}
|
||||||
@@ -628,6 +633,7 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
}}
|
}}
|
||||||
fillColor={style.fill.fg_color || "#FFFFFF"}
|
fillColor={style.fill.fg_color || "#FFFFFF"}
|
||||||
fontColor={style.font.color}
|
fontColor={style.font.color}
|
||||||
|
fontSize={style.font.sz}
|
||||||
bold={style.font.b}
|
bold={style.font.b}
|
||||||
underline={style.font.u}
|
underline={style.font.u}
|
||||||
italic={style.font.i}
|
italic={style.font.i}
|
||||||
@@ -638,6 +644,7 @@ const Workbook = (props: { model: Model; workbookState: WorkbookState }) => {
|
|||||||
verticalAlign={
|
verticalAlign={
|
||||||
style.alignment?.vertical ? style.alignment.vertical : "bottom"
|
style.alignment?.vertical ? style.alignment.vertical : "bottom"
|
||||||
}
|
}
|
||||||
|
wrapText={style.alignment?.wrap_text || false}
|
||||||
canEdit={true}
|
canEdit={true}
|
||||||
numFmt={style.num_fmt}
|
numFmt={style.num_fmt}
|
||||||
showGridLines={model.getShowGridLines(model.getSelectedSheet())}
|
showGridLines={model.getShowGridLines(model.getSelectedSheet())}
|
||||||
|
|||||||
@@ -70,6 +70,52 @@ function hexToRGBA10Percent(colorHex: string): string {
|
|||||||
return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
|
return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits the given text into multiple lines. If `wrapText` is true, it applies word-wrapping
|
||||||
|
* based on the specified canvas context, maximum width, and horizontal padding.
|
||||||
|
*
|
||||||
|
* - First, the text is split by newline characters so that explicit newlines are respected.
|
||||||
|
* - If wrapping is enabled, each line is further split into words and measured against the
|
||||||
|
* available width. Whenever adding an extra word would exceed
|
||||||
|
* this limit, a new line is started.
|
||||||
|
*
|
||||||
|
* @param text The text to split into lines.
|
||||||
|
* @param wrapText Whether to apply word-wrapping or just return text split by newlines.
|
||||||
|
* @param context The `CanvasRenderingContext2D` used for measuring text width.
|
||||||
|
* @param width The maximum width for each line.
|
||||||
|
* @returns An array of lines (strings), each fitting within the specified width if wrapping is enabled.
|
||||||
|
*/
|
||||||
|
function computeWrappedLines(
|
||||||
|
text: string,
|
||||||
|
wrapText: boolean,
|
||||||
|
context: CanvasRenderingContext2D,
|
||||||
|
width: number,
|
||||||
|
): string[] {
|
||||||
|
// Split the text into lines
|
||||||
|
const rawLines = text.split("\n");
|
||||||
|
if (!wrapText) {
|
||||||
|
// If there is no wrapping, return the raw lines
|
||||||
|
return rawLines;
|
||||||
|
}
|
||||||
|
const wrappedLines = [];
|
||||||
|
for (const line of rawLines) {
|
||||||
|
const words = line.split(" ");
|
||||||
|
let currentLine = words[0];
|
||||||
|
for (const word of words) {
|
||||||
|
const testLine = `${currentLine} ${word}`;
|
||||||
|
const textWidth = context.measureText(testLine).width;
|
||||||
|
if (textWidth < width) {
|
||||||
|
currentLine = testLine;
|
||||||
|
} else {
|
||||||
|
wrappedLines.push(currentLine);
|
||||||
|
currentLine = word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wrappedLines.push(currentLine);
|
||||||
|
}
|
||||||
|
return wrappedLines;
|
||||||
|
}
|
||||||
|
|
||||||
export default class WorksheetCanvas {
|
export default class WorksheetCanvas {
|
||||||
sheetWidth: number;
|
sheetWidth: number;
|
||||||
|
|
||||||
@@ -371,6 +417,7 @@ export default class WorksheetCanvas {
|
|||||||
if (style.alignment?.vertical) {
|
if (style.alignment?.vertical) {
|
||||||
verticalAlign = style.alignment.vertical;
|
verticalAlign = style.alignment.vertical;
|
||||||
}
|
}
|
||||||
|
const wrapText = style.alignment?.wrap_text || false;
|
||||||
|
|
||||||
const context = this.ctx;
|
const context = this.ctx;
|
||||||
context.font = font;
|
context.font = font;
|
||||||
@@ -496,9 +543,14 @@ export default class WorksheetCanvas {
|
|||||||
context.rect(x, y, width, height);
|
context.rect(x, y, width, height);
|
||||||
context.clip();
|
context.clip();
|
||||||
|
|
||||||
// Is there any better parameter?
|
// Is there any better to determine the line height?
|
||||||
const lineHeight = fontSize * 1.5;
|
const lineHeight = fontSize * 1.5;
|
||||||
const lines = fullText.split("\n");
|
const lines = computeWrappedLines(
|
||||||
|
fullText,
|
||||||
|
wrapText,
|
||||||
|
context,
|
||||||
|
width - padding,
|
||||||
|
);
|
||||||
const lineCount = lines.length;
|
const lineCount = lines.length;
|
||||||
|
|
||||||
lines.forEach((text, line) => {
|
lines.forEach((text, line) => {
|
||||||
@@ -682,13 +734,19 @@ export default class WorksheetCanvas {
|
|||||||
if (fullText === "") {
|
if (fullText === "") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const width = this.getColumnWidth(sheet, column);
|
||||||
const style = this.model.getCellStyle(sheet, row, column);
|
const style = this.model.getCellStyle(sheet, row, column);
|
||||||
const fontSize = style.font.sz;
|
const fontSize = style.font.sz;
|
||||||
const lineHeight = fontSize * 1.5;
|
const lineHeight = fontSize * 1.5;
|
||||||
let font = `${fontSize}px ${defaultCellFontFamily}`;
|
let font = `${fontSize}px ${defaultCellFontFamily}`;
|
||||||
font = style.font.b ? `bold ${font}` : `400 ${font}`;
|
font = style.font.b ? `bold ${font}` : `400 ${font}`;
|
||||||
this.ctx.font = font;
|
this.ctx.font = font;
|
||||||
const lines = fullText.split("\n");
|
const lines = computeWrappedLines(
|
||||||
|
fullText,
|
||||||
|
style.alignment?.wrap_text || false,
|
||||||
|
this.ctx,
|
||||||
|
width,
|
||||||
|
);
|
||||||
const lineCount = lines.length;
|
const lineCount = lines.length;
|
||||||
// This is computed so that the y position of the text is independent of the vertical alignment
|
// This is computed so that the y position of the text is independent of the vertical alignment
|
||||||
const textHeight = (lineCount - 1) * lineHeight + 8 + fontSize;
|
const textHeight = (lineCount - 1) * lineHeight + 8 + fontSize;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
"vertical_align_middle": " Align middle",
|
"vertical_align_middle": " Align middle",
|
||||||
"vertical_align_top": "Align top",
|
"vertical_align_top": "Align top",
|
||||||
"selected_png": "Export Selected area as PNG",
|
"selected_png": "Export Selected area as PNG",
|
||||||
|
"wrap_text": "Wrap text",
|
||||||
"format_menu": {
|
"format_menu": {
|
||||||
"auto": "Auto",
|
"auto": "Auto",
|
||||||
"number": "Number",
|
"number": "Number",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ironcalc_server"
|
name = "ironcalc_server"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ironcalc"
|
name = "ironcalc"
|
||||||
version = "0.3.0"
|
version = "0.5.0"
|
||||||
authors = ["Nicolás Hatcher <nicolas@theuniverse.today>"]
|
authors = ["Nicolás Hatcher <nicolas@theuniverse.today>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
homepage = "https://www.ironcalc.com"
|
homepage = "https://www.ironcalc.com"
|
||||||
@@ -20,7 +20,7 @@ thiserror = "1.0"
|
|||||||
# Uses `../base` when used locally, and uses
|
# Uses `../base` when used locally, and uses
|
||||||
# the inicated version from crates.io when published.
|
# the inicated version from crates.io when published.
|
||||||
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations
|
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations
|
||||||
ironcalc_base = { path = "../base", version = "0.3" }
|
ironcalc_base = { path = "../base", version = "0.5" }
|
||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
bitcode = "0.6.0"
|
bitcode = "0.6.0"
|
||||||
|
|||||||
@@ -9,11 +9,9 @@
|
|||||||
//!
|
//!
|
||||||
//! ```toml
|
//! ```toml
|
||||||
//! [dependencies]
|
//! [dependencies]
|
||||||
//! ironcalc = { git = "https://github.com/ironcalc/IronCalc" }
|
//! ironcalc = { git = "https://github.com/ironcalc/IronCalc", tag = "v0.5.0" }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! <small> until version 0.5.0 you should use the git dependencies as stated </small>
|
|
||||||
//!
|
|
||||||
//! A simple example with some numbers, a new sheet and a formula:
|
//! A simple example with some numbers, a new sheet and a formula:
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
|
|||||||
Reference in New Issue
Block a user