Skip to content

Commit

Permalink
💥 Remove lineJoin from circle objects
Browse files Browse the repository at this point in the history
The `lineJoin` attribute does not make sense on a circle object.
This commit removes this attribute from graphics type `Circle`.

To reduce redundancy in `read-graphics`, line and fill attributes are
extracted.

Typing is improved on the `omit()` util function.
  • Loading branch information
ralfstx committed May 17, 2023
1 parent 901ae0f commit e60fe19
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 82 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
* Lines in a `TextBlock` will now break and continue on the next page
when they do not fit. To prevent this, set `breakInside` to `avoid`.

* The `lineJoin` attribute is no longer supported by the graphics type
`Circle`.

### Added

* Attribute `breakInside` to control page breaks inside a block on
Expand Down
2 changes: 1 addition & 1 deletion src/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ export type Circle = {
* The radius of the circle.
*/
r: number;
} & Omit<LineAttrs, 'lineCap'> &
} & Omit<LineAttrs, 'lineCap' | 'lineJoin'> &
FillAttrs;

/**
Expand Down
128 changes: 50 additions & 78 deletions src/read-graphics.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Color, parseColor } from './colors.js';
import { parseSvgPath, PathCommand } from './svg-paths.js';
import { Obj, optional, readFrom, readObject, required, types } from './types.js';
import { omit } from './utils.js';

export type GraphicsObject = {
type: 'graphics';
Expand All @@ -9,78 +10,60 @@ export type GraphicsObject = {

export type Shape = RectObject | CircleObject | LineObject | PolylineObject | PathObject;

export type RectObject = {
type: 'rect';
x: number;
y: number;
width: number;
height: number;
type LineCap = 'butt' | 'round' | 'square';
type LineJoin = 'miter' | 'round' | 'bevel';

type LineAttrs = {
lineWidth?: number;
lineColor?: Color;
lineOpacity?: number;
lineCap?: LineCap;
lineJoin?: LineJoin;
lineDash?: number[];
};

type FillAttrs = {
fillColor?: Color;
fillOpacity?: number;
};

export type RectObject = {
type: 'rect';
x: number;
y: number;
width: number;
height: number;
} & Omit<LineAttrs, 'lineCap'> &
FillAttrs;

export type CircleObject = {
type: 'circle';
cx: number;
cy: number;
r: number;
lineWidth?: number;
lineColor?: Color;
lineOpacity?: number;
lineCap?: LineCap;
lineJoin?: LineJoin;
lineDash?: number[];
fillColor?: Color;
fillOpacity?: number;
};
} & Omit<LineAttrs, 'lineCap' | 'lineJoin'> &
FillAttrs;

export type LineObject = {
type: 'line';
x1: number;
y1: number;
x2: number;
y2: number;
lineWidth?: number;
lineColor?: Color;
lineOpacity?: number;
lineCap?: LineCap;
lineDash?: number[];
};
} & Omit<LineAttrs, 'lineJoin'>;

export type PolylineObject = {
type: 'polyline';
points: { x: number; y: number }[];
closePath?: boolean;
lineWidth?: number;
lineColor?: Color;
lineOpacity?: number;
lineCap?: LineCap;
lineJoin?: LineJoin;
lineDash?: number[];
fillColor?: Color;
fillOpacity?: number;
};
} & LineAttrs &
FillAttrs;

export type PathObject = {
type: 'path';
commands: PathCommand[];
lineWidth?: number;
lineColor?: Color;
lineOpacity?: number;
lineCap?: LineCap;
lineJoin?: LineJoin;
lineDash?: number[];
fillColor?: Color;
fillOpacity?: number;
};

type LineCap = 'butt' | 'round' | 'square';
type LineJoin = 'miter' | 'round' | 'bevel';
} & LineAttrs &
FillAttrs;

const tLineCap = types.string({ enum: ['butt', 'round', 'square'] });
const tLineJoin = types.string({ enum: ['miter', 'round', 'bevel'] });
Expand Down Expand Up @@ -117,29 +100,20 @@ function readRect(input: Obj): RectObject {
y: required(types.number()),
width: required(types.number()),
height: required(types.number()),
lineWidth: optional(tLineWidth),
lineColor: optional(parseColor),
lineOpacity: optional(tOpacity),
lineJoin: optional(tLineJoin),
lineDash: optional(tLineDash),
fillColor: optional(parseColor),
fillOpacity: optional(tOpacity),
...omit(lineAttrs, 'lineCap'),
...fillAttrs,
}) as RectObject;
}

function readCircle(input: Obj): RectObject {
function readCircle(input: Obj): CircleObject {
return readObject(input, {
type: () => 'circle',
cx: required(types.number()),
cy: required(types.number()),
r: required(types.number({ minimum: 0 })),
lineWidth: optional(tLineWidth),
lineColor: optional(parseColor),
lineOpacity: optional(tOpacity),
lineDash: optional(tLineDash),
fillColor: optional(parseColor),
fillOpacity: optional(tOpacity),
}) as RectObject;
...omit(lineAttrs, 'lineCap', 'lineJoin'),
...fillAttrs,
}) as CircleObject;
}

function readLine(input: Obj): LineObject {
Expand All @@ -149,11 +123,7 @@ function readLine(input: Obj): LineObject {
x2: required(types.number()),
y1: required(types.number()),
y2: required(types.number()),
lineWidth: optional(tLineWidth),
lineColor: optional(parseColor),
lineOpacity: optional(tOpacity),
lineCap: optional(tLineCap),
lineDash: optional(tLineDash),
...omit(lineAttrs, 'lineJoin'),
}) as LineObject;
}

Expand All @@ -162,34 +132,36 @@ function readPolyline(input: Obj): PolylineObject {
type: () => 'polyline',
points: required(types.array(readPoint)),
closePath: optional(types.boolean()),
lineWidth: optional(tLineWidth),
lineColor: optional(parseColor),
lineOpacity: optional(tOpacity),
lineCap: optional(tLineCap),
lineJoin: optional(tLineJoin),
lineDash: optional(tLineDash),
fillColor: optional(parseColor),
fillOpacity: optional(tOpacity),
...lineAttrs,
...fillAttrs,
}) as PolylineObject;
}

function readPath(input: Obj): PathObject {
const obj = readObject(input, {
type: () => 'path',
d: required(types.string()),
lineWidth: optional(tLineWidth),
lineColor: optional(parseColor),
lineOpacity: optional(tOpacity),
lineCap: optional(tLineCap),
lineJoin: optional(tLineJoin),
lineDash: optional(tLineDash),
fillColor: optional(parseColor),
fillOpacity: optional(tOpacity),
...lineAttrs,
...fillAttrs,
});
const commands = parseSvgPath(obj.d as string);
return { ...obj, commands } as PathObject;
}

const lineAttrs = {
lineWidth: optional(tLineWidth),
lineColor: optional(parseColor),
lineOpacity: optional(tOpacity),
lineCap: optional(tLineCap),
lineJoin: optional(tLineJoin),
lineDash: optional(tLineDash),
};

const fillAttrs = {
fillColor: optional(parseColor),
fillOpacity: optional(tOpacity),
};

function readPoint(input: unknown): { x: number; y: number } {
return readObject(input, {
x: required(types.number()),
Expand Down
5 changes: 4 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ export function compact<T>(array: T[]) {
/**
* Returns a copy of the given object with the given keys removed.
*/
export function omit(obj: Record<string, unknown>, ...keys: string[]) {
export function omit<T extends Record<string, unknown>>(
obj: T,
...keys: string[]
): Omit<T, (typeof keys)[number]> {
const result = { ...obj };
for (const key of keys) {
delete result[key];
Expand Down
2 changes: 0 additions & 2 deletions test/render-graphics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ describe('render-graphics', () => {
fillColor: rgb(0, 0, 1),
lineColor: rgb(1, 0, 0),
lineWidth: 1,
lineJoin: 'round',
lineDash: [1, 2],
fillOpacity: 0.5,
lineOpacity: 0.5,
Expand All @@ -125,7 +124,6 @@ describe('render-graphics', () => {
'0 0 1 rg',
'1 0 0 RG',
'1 w',
'1 j',
'[1 2] 0 d',
'-2 2 m',
'-2 0.3431457505076194 -0.6568542494923806 -1 1 -1 c',
Expand Down

0 comments on commit e60fe19

Please sign in to comment.