Skip to content

Commit

Permalink
Merge pull request #35 from zurmokeeper/feature/add_shape_text_func
Browse files Browse the repository at this point in the history
add shape and text
  • Loading branch information
zurmokeeper authored Jan 17, 2025
2 parents a18b3ed + 638b069 commit 779752b
Show file tree
Hide file tree
Showing 44 changed files with 1,947 additions and 67 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ To be clear, all contributions added to this library will be included in the lib
<li><a href="#conditional-formatting">Conditional Formatting</a></li>
<li><a href="#outline-levels">Outline Levels</a></li>
<li><a href="#images">Images</a></li>
<li><a href="#shape">Shape</a></li>
<li><a href="#sheet-protection">Sheet Protection</a></li>
<li><a href="#file-io">File I/O</a>
<ul>
Expand Down Expand Up @@ -2236,6 +2237,31 @@ worksheet.addImage(imageId2, {
});
```

## Shape

### Add shape to worksheet[](#contents)

```javascript
worksheet.addShape({
type: 'roundRect',
rotation: 0,
fill: { type: 'solid', color: { rgb: '4499FF' } },
outline: { weight: 2, color: { rgb: '446699' }, dash: 'sysDash' },
textBody: {
vertAlign: 'ctr',
paragraphs: [
{ alignment: 'l', runs: ["Lorem ipsum dolor sit amet, consectetur adipiscing elit."] },
{ alignment: 'r', runs: [
{ text: "Nulla eget odio sed libero ultrices vehicula.", font: { bold: true, color: { rgb: 'FF0000' } } },
] },
],
},
}, 'B2:H8', {
hyperlink: 'https://www.example.com',
tooltip: 'Example Link',
});
```

## Sheet Protection[](#contents)<!-- Link generated with jump2header -->

Worksheets can be protected from modification by adding a password.
Expand Down
26 changes: 26 additions & 0 deletions README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ ws1.getCell('A1').value = { text: 'Sheet2', hyperlink: '#A1:B1' };
<li><a href="#条件格式化">条件格式化</a></li>
<li><a href="#大纲级别">大纲级别</a></li>
<li><a href="#图片">图片</a></li>
<li><a href="#形状">形状Shape</a></li>
<li><a href="#工作表保护">工作表保护</a></li>
<li><a href="#文件-io">文件 I/O</a>
<ul>
Expand Down Expand Up @@ -2134,6 +2135,31 @@ worksheet.addImage(imageId2, {
});
```

## 形状(Shape)

### 新增形状(Shape)到工作表[](#contents)

```javascript
worksheet.addShape({
type: 'roundRect',
rotation: 0,
fill: { type: 'solid', color: { rgb: '4499FF' } },
outline: { weight: 2, color: { rgb: '446699' }, dash: 'sysDash' },
textBody: {
vertAlign: 'ctr',
paragraphs: [
{ alignment: 'l', runs: ["Lorem ipsum dolor sit amet, consectetur adipiscing elit."] },
{ alignment: 'r', runs: [
{ text: "Nulla eget odio sed libero ultrices vehicula.", font: { bold: true, color: { rgb: 'FF0000' } } },
] },
],
},
}, 'B2:H8', {
hyperlink: 'https://www.example.com',
tooltip: 'Example Link',
});
```

## 工作表保护[](#目录)<!-- Link generated with jump2header -->

可以通过添加密码来保护工作表免受修改。
Expand Down
77 changes: 71 additions & 6 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1004,21 +1004,79 @@ export class Anchor implements IAnchor {

constructor(model?: IAnchor | object);
}
export interface ImageRange {
export interface DrawingRange {
tl: Anchor;
br: Anchor;
}

export interface ImagePosition {
export interface DrawingPosition {
tl: { col: number; row: number };
ext: { width: number; height: number };
}

export interface ImageHyperlinkValue {
export interface DrawingHyperlinkValue {
hyperlink: string;
tooltip?: string;
}

export interface ShapeProps {
/**
* Defined as DocumentFormat.OpenXml.Drawing.ShapeTypeValues in Open API Spec.
* See https://learn.microsoft.com/ja-jp/dotnet/api/documentformat.openxml.drawing.shapetypevalues
*/
type: string;
rotation?: number;
horizontalFlip?: boolean;
verticalFlip?: boolean;
fill?: ShapeFill;
outline?: ShapeOutline;
textBody?: ShapeTextBody;
}

export type ShapeFill = {
type: 'solid',
color: { theme?: string, rgb?: string }
}

export interface ShapeArrowEnd {
type?: 'triangle' | 'arrow' | 'stealth' | 'diamond' | 'oval';
length?: 'lg' | 'med' | 'sm';
width?: 'lg' | 'med' | 'sm';
}

export type ShapeOutline = {
weight?: number,
color?: { theme?: string, rgb?: string },
dash?: 'solid' | 'sysDot' | 'sysDash' | 'dash' | 'dashDot' | 'lgDash' | 'lgDashDot' | 'lgDashDotDot',
arrow?: {
head?: ShapeArrowEnd,
tail?: ShapeArrowEnd
}
}

export type ShapeTextBody = {
paragraphs: ShapeParagraph[],
vertAlign?: 't' | 'ctr' | 'b',
}

export type ShapeParagraph = {
runs: ShapeRun[],
alignment?: 'l' | 'ctr' | 'r',
}

export type ShapeRun = {
text: string,
font?: Partial<ShapeRunFont>,
}

export type ShapeRunFont = {
size: number,
color: { theme?: string, rgb?: string },
bold: boolean,
italic: boolean,
underline: 'sng' | 'dbl' | 'none',
}

export interface Range extends Location {
sheetName: string;

Expand Down Expand Up @@ -1466,14 +1524,21 @@ export interface Worksheet {
* Using the image id from `Workbook.addImage`,
* embed an image within the worksheet to cover a range
*/
addImage(imageId: number, range: string | { editAs?: string; } & ImageRange & { hyperlinks?: ImageHyperlinkValue } | { editAs?: string; } & ImagePosition & { hyperlinks?: ImageHyperlinkValue }): void;
addImage(imageId: number, range: string | { editAs?: string; } & DrawingRange & { hyperlinks?: DrawingHyperlinkValue } | { editAs?: string; } & DrawingPosition & { hyperlinks?: DrawingHyperlinkValue }): void;

getImages(): Array<{
type: 'image',
imageId: string;
range: ImageRange;
imageId: string,
range: DrawingRange,
}>;

addShape(props: ShapeProps, range: string | { editAs?: string; } & DrawingRange | { editAs?: string; } & DrawingPosition, hyperlinks?: DrawingHyperlinkValue ): void;

getShapes(): Array<{
props: ShapeProps,
range: DrawingRange,
}>

commit(): void;

model: WorksheetModel;
Expand Down
22 changes: 22 additions & 0 deletions lib/doc/drawing-range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const colCache = require('../utils/col-cache');
const Anchor = require('./anchor');

module.exports = {
parseRange: (range, hyperlinks, worksheet) => {
if (typeof range === 'string') {
const decoded = colCache.decode(range);
return {
tl: new Anchor(worksheet, {col: decoded.left, row: decoded.top}, -1),
br: new Anchor(worksheet, {col: decoded.right, row: decoded.bottom}, 0),
editAs: 'oneCell',
};
}
return {
tl: new Anchor(worksheet, range.tl, 0),
br: range.br && new Anchor(worksheet, range.br, 0),
ext: range.ext,
editAs: range.editAs,
hyperlinks: hyperlinks || range.hyperlinks,
};
},
};
22 changes: 3 additions & 19 deletions lib/doc/image.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const colCache = require('../utils/col-cache');
const Anchor = require('./anchor');
const {parseRange} = require('./drawing-range');

class Image {
constructor(worksheet, model) {
Expand Down Expand Up @@ -36,24 +35,9 @@ class Image {
this.imageId = imageId;

if (type === 'image') {
if (typeof range === 'string') {
const decoded = colCache.decode(range);
this.range = {
tl: new Anchor(this.worksheet, {col: decoded.left, row: decoded.top}, -1),
br: new Anchor(this.worksheet, {col: decoded.right, row: decoded.bottom}, 0),
editAs: 'oneCell',
};
} else {
this.range = {
tl: new Anchor(this.worksheet, range.tl, 0),
br: range.br && new Anchor(this.worksheet, range.br, 0),
ext: range.ext,
editAs: range.editAs,
hyperlinks: hyperlinks || range.hyperlinks,
};
}
this.range = parseRange(range, hyperlinks, this.worksheet);
}
}
}

module.exports = Image;
module.exports = Image;
110 changes: 110 additions & 0 deletions lib/doc/shape.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
const {parseRange} = require('./drawing-range');

class Shape {
constructor(worksheet, model) {
this.worksheet = worksheet;
this.model = model;
}

get model() {
return {
props: {
type: this.props.type,
rotation: this.props.rotation,
horizontalFlip: this.props.horizontalFlip,
verticalFlip: this.props.verticalFlip,
fill: this.props.fill,
outline: this.props.outline,
textBody: this.props.textBody,
},
range: {
tl: this.range.tl.model,
br: this.range.br && this.range.br.model,
ext: this.range.ext,
editAs: this.range.editAs,
},
hyperlinks: this.hyperlinks,
};
}

set model({props, range, hyperlinks}) {
this.props = {type: props.type};
if (props.rotation) {
this.props.rotation = props.rotation;
}
if (props.horizontalFlip) {
this.props.horizontalFlip = props.horizontalFlip;
}
if (props.verticalFlip) {
this.props.verticalFlip = props.verticalFlip;
}
if (props.fill) {
this.props.fill = props.fill;
}
if (props.outline) {
this.props.outline = props.outline;
}
if (props.textBody) {
this.props.textBody = parseAsTextBody(props.textBody);
}
this.range = parseRange(range, undefined, this.worksheet);
this.hyperlinks = hyperlinks;
}
}

function parseAsTextBody(input) {
if (typeof input === 'string') {
return {
paragraphs: [parseAsParagraph(input)],
};
}
if (Array.isArray(input)) {
return {
paragraphs: input.map(parseAsParagraph),
};
}
const model = {
paragraphs: input.paragraphs.map(parseAsParagraph),
};
if (input.vertAlign) {
model.vertAlign = input.vertAlign;
}
return model;
}

function parseAsParagraph(input) {
if (typeof input === 'string') {
return {
runs: [parseAsRun(input)],
};
}
if (Array.isArray(input)) {
return {
runs: input.map(parseAsRun),
};
}
const model = {
runs: input.runs.map(parseAsRun),
};
if (input.alignment) {
model.alignment = input.alignment;
}
return model;
}

function parseAsRun(input) {
if (typeof input === 'string') {
return {
text: input,
};
}
const model = {
text: input.text,
};
if (input.font) {
model.font = input.font;
}
return model;
}

module.exports = Shape;
Loading

0 comments on commit 779752b

Please sign in to comment.