Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [next]

- chore(TS): this is harder [#9097](https://github.com/fabricjs/fabric.js/pull/9097)
- chore(TS) Add type-checking to files excluded with ts-nocheck ( Parser mostly ) [#9085](https://github.com/fabricjs/fabric.js/pull/9085)
- test(Text): Add some tests for text in Jest [#9083](https://github.com/fabricjs/fabric.js/pull/9083)
- ci(): Install system deps only when necessary [#9086](https://github.com/fabricjs/fabric.js/pull/9086)
Expand Down
7 changes: 3 additions & 4 deletions src/CommonMethods.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//@ts-nocheck
import { Observable } from './Observable';

export class CommonMethods<EventSpec> extends Observable<EventSpec> {
Expand Down Expand Up @@ -37,7 +36,7 @@ export class CommonMethods<EventSpec> extends Observable<EventSpec> {
}

_set(key: string, value: any) {
this[key] = value;
this[key as keyof this] = value;
}

/**
Expand All @@ -57,7 +56,7 @@ export class CommonMethods<EventSpec> extends Observable<EventSpec> {
* @param {String} property Property name
* @return {*} value of a property
*/
get(property: string) {
return this[property];
get(property: string): any {
return this[property as keyof this];
}
}
4 changes: 0 additions & 4 deletions src/parser/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,6 @@ export const svgValidTagNames = [
'vector-effect': 'strokeUniform',
'image-rendering': 'imageSmoothing',
},
colorAttributes = {
stroke: 'strokeOpacity',
fill: 'fillOpacity',
},
fSize = 'font-size',
cPath = 'clip-path';

Expand Down
15 changes: 7 additions & 8 deletions src/parser/parsePointsAttribute.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ts-nocheck
import type { XY } from '../Point';

/**
* Parses "points" attribute, returning an array of values
Expand All @@ -7,22 +7,21 @@
* @param {String} points points attribute string
* @return {Array} array of points
*/
export function parsePointsAttribute(points) {
export function parsePointsAttribute(points: string | null): XY[] {
// points attribute is required and must not be empty
if (!points) {
return null;
return [];
}

// replace commas with whitespace and remove bookending whitespace
points = points.replace(/,/g, ' ').trim();
const pointsSplit: string[] = points.replace(/,/g, ' ').trim().split(/\s+/);

points = points.split(/\s+/);
const parsedPoints = [];

for (let i = 0; i < points.length; i += 2) {
for (let i = 0; i < pointsSplit.length; i += 2) {
parsedPoints.push({
x: parseFloat(points[i]),
y: parseFloat(points[i + 1]),
x: parseFloat(pointsSplit[i]),
y: parseFloat(pointsSplit[i + 1]),
});
}

Expand Down
31 changes: 16 additions & 15 deletions src/parser/setStrokeFillOpacity.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
//@ts-nocheck
import { Color } from '../color/Color';
import { toFixed } from '../util/misc/toFixed';
import { colorAttributes } from './constants';
import { FabricObject } from '../shapes/Object/FabricObject';

const colorAttributesMap = {
stroke: 'strokeOpacity',
fill: 'fillOpacity',
};

/**
* @private
* @param {Object} attributes Array of attributes to parse
*/

export function setStrokeFillOpacity(attributes) {
for (const attr in colorAttributes) {
export function setStrokeFillOpacity(
attributes: Record<string, any>
): Record<string, any> {
const defaults = FabricObject.getDefaults();
Object.entries(colorAttributesMap).forEach(([attr, colorAttr]) => {
if (
typeof attributes[colorAttributes[attr]] === 'undefined' ||
typeof attributes[colorAttr] === 'undefined' ||
attributes[attr] === ''
) {
continue;
return;
}
const defaults = FabricObject.getDefaults();
if (typeof attributes[attr] === 'undefined') {
if (!defaults[attr]) {
continue;
return;
}
attributes[attr] = defaults[attr];
}

if (attributes[attr].indexOf('url(') === 0) {
continue;
return;
}

const color = new Color(attributes[attr]);
attributes[attr] = color
.setAlpha(
toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)
)
.setAlpha(toFixed(color.getAlpha() * attributes[colorAttr], 2))
.toRgba();
}
});
return attributes;
}
4 changes: 2 additions & 2 deletions src/shapes/Circle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export class Circle<
* @return {Array} an array of strings with the specific svg representation
* of the instance
*/
_toSVG(): (string | number)[] {
_toSVG(): string[] {
const angle = (this.endAngle - this.startAngle) % 360;

if (angle === 0) {
Expand All @@ -162,7 +162,7 @@ export class Circle<
'COMMON_PARTS',
'cx="0" cy="0" ',
'r="',
this.radius,
`${this.radius}`,
'" />\n',
];
} else {
Expand Down
9 changes: 2 additions & 7 deletions src/shapes/Ellipse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,11 @@ export class Ellipse<
* @return {Array} an array of strings with the specific svg representation
* of the instance
*/
_toSVG() {
_toSVG(): string[] {
return [
'<ellipse ',
'COMMON_PARTS',
'cx="0" cy="0" ',
'rx="',
this.rx,
'" ry="',
this.ry,
'" />\n',
`cx="0" cy="0" rx="${this.rx}" ry="${this.ry}" />\n`,
];
}

Expand Down
118 changes: 47 additions & 71 deletions src/shapes/Object/FabricObjectSVGExportMixin.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// @ts-nocheck
import type { TSVGReviver } from '../../typedefs';
import { uid } from '../../util/internals/uid';
import { colorPropToSVG, matrixToSVG } from '../../util/misc/svgParsing';
import { NONE } from '../../constants';
import type { FabricObject } from './FabricObject';
import { isFiller } from '../../util/typeAssertions';

export class FabricObjectSVGExportMixin {
/**
Expand All @@ -17,7 +18,10 @@ export class FabricObjectSVGExportMixin {
* @param {Boolean} skipShadow a boolean to skip shadow filter output
* @return {String}
*/
getSvgStyles(skipShadow?: boolean) {
getSvgStyles(
this: FabricObjectSVGExportMixin & FabricObject,
skipShadow?: boolean
) {
const fillRule = this.fillRule ? this.fillRule : 'nonzero',
strokeWidth = this.strokeWidth ? this.strokeWidth : '0',
strokeDashArray = this.strokeDashArray
Expand Down Expand Up @@ -65,80 +69,29 @@ export class FabricObjectSVGExportMixin {
].join('');
}

/**
* Returns styles-string for svg-export
* @param {Object} style the object from which to retrieve style properties
* @param {Boolean} useWhiteSpace a boolean to include an additional attribute in the style.
* @return {String}
*/
getSvgSpanStyles(style, useWhiteSpace?: boolean) {
const term = '; ',
fontFamily = style.fontFamily
? `font-family: ${
style.fontFamily.indexOf("'") === -1 &&
style.fontFamily.indexOf('"') === -1
? `'${style.fontFamily}'`
: style.fontFamily
}${term}`
: '',
strokeWidth = style.strokeWidth
? `stroke-width: ${style.strokeWidth}${term}`
: '',
fontSize = style.fontSize ? `font-size: ${style.fontSize}px${term}` : '',
fontStyle = style.fontStyle
? `font-style: ${style.fontStyle}${term}`
: '',
fontWeight = style.fontWeight
? `font-weight: ${style.fontWeight}${term}`
: '',
fill = style.fill ? colorPropToSVG('fill', style.fill) : '',
stroke = style.stroke ? colorPropToSVG('stroke', style.stroke) : '',
textDecoration = this.getSvgTextDecoration(style),
deltaY = style.deltaY ? `baseline-shift: ${-style.deltaY}; ` : '';

return [
stroke,
strokeWidth,
fontFamily,
fontSize,
fontStyle,
fontWeight,
textDecoration
? `text-decoration: ${textDecoration}${term}`
: textDecoration,
fill,
deltaY,
useWhiteSpace ? 'white-space: pre; ' : '',
].join('');
}

/**
* Returns text-decoration property for svg-export
* @param {Object} style the object from which to retrieve style properties
* @return {String}
*/
getSvgTextDecoration(style) {
return ['overline', 'underline', 'line-through']
.filter((decoration) => style[decoration.replace('-', '')])
.join(' ');
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to the text svg export


/**
* Returns filter for svg shadow
* @return {String}
*/
getSvgFilter() {
getSvgFilter(this: FabricObjectSVGExportMixin & FabricObject) {
return this.shadow ? `filter: url(#SVGID_${this.shadow.id});` : '';
}

/**
* Returns id attribute for svg output
* @return {String}
*/
getSvgCommons() {
getSvgCommons(
this: FabricObjectSVGExportMixin & FabricObject & { id?: string }
) {
return [
this.id ? `id="${this.id}" ` : '',
this.clipPath ? `clip-path="url(#${this.clipPath.clipPathId})" ` : '',
this.clipPath
? `clip-path="url(#${
(this.clipPath as FabricObjectSVGExportMixin & FabricObject)
.clipPathId
})" `
: '',
].join('');
}

Expand All @@ -147,18 +100,36 @@ export class FabricObjectSVGExportMixin {
* @param {Boolean} use the full transform or the single object one.
* @return {String}
*/
getSvgTransform(full?: boolean, additionalTransform = '') {
getSvgTransform(
this: FabricObjectSVGExportMixin & FabricObject,
full?: boolean,
additionalTransform = ''
) {
const transform = full ? this.calcTransformMatrix() : this.calcOwnMatrix(),
svgTransform = `transform="${matrixToSVG(transform)}`;
return `${svgTransform}${additionalTransform}" `;
}

/**
* Returns svg representation of an instance
* This function is implemented in each subclass
* This is just because typescript otherwise cryies all the time
* @return {Array} an array of strings with the specific svg representation
* of the instance
*/
_toSVG(reviver?: TSVGReviver): string[] {
return [''];
}

/**
* Returns svg representation of an instance
* @param {TSVGReviver} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
*/
toSVG(reviver?: TSVGReviver) {
toSVG(
this: FabricObjectSVGExportMixin & FabricObject,
reviver?: TSVGReviver
) {
return this._createBaseSVGMarkup(this._toSVG(reviver), {
reviver,
});
Expand All @@ -169,7 +140,10 @@ export class FabricObjectSVGExportMixin {
* @param {TSVGReviver} [reviver] Method for further parsing of svg representation.
* @return {String} svg representation of an instance
*/
toClipPathSVG(reviver?: TSVGReviver) {
toClipPathSVG(
this: FabricObjectSVGExportMixin & FabricObject,
reviver?: TSVGReviver
) {
return (
'\t' +
this._createBaseClipPathSVGMarkup(this._toSVG(reviver), {
Expand All @@ -182,6 +156,7 @@ export class FabricObjectSVGExportMixin {
* @private
*/
_createBaseClipPathSVGMarkup(
this: FabricObjectSVGExportMixin & FabricObject,
objectMarkup: string[],
{
reviver,
Expand All @@ -202,6 +177,7 @@ export class FabricObjectSVGExportMixin {
* @private
*/
_createBaseSVGMarkup(
this: FabricObjectSVGExportMixin & FabricObject,
objectMarkup: string[],
{
noStyle,
Expand All @@ -214,10 +190,10 @@ export class FabricObjectSVGExportMixin {
withShadow?: boolean;
additionalTransform?: string;
} = {}
) {
): string {
const styleInfo = noStyle ? '' : `style="${this.getSvgStyles()}" `,
shadowInfo = withShadow ? `style="${this.getSvgFilter()}" ` : '',
clipPath = this.clipPath,
clipPath = this.clipPath as FabricObjectSVGExportMixin & FabricObject,
vectorEffect = this.strokeUniform
? 'vector-effect="non-scaling-stroke" '
: '',
Expand Down Expand Up @@ -252,10 +228,10 @@ export class FabricObjectSVGExportMixin {
additionalTransform ? `transform="${additionalTransform}" ` : '',
].join('');
objectMarkup[index] = commonPieces;
if (fill && fill.toLive) {
if (isFiller(fill)) {
markup.push(fill.toSVG(this));
}
if (stroke && stroke.toLive) {
if (isFiller(stroke)) {
markup.push(stroke.toSVG(this));
}
if (shadow) {
Expand All @@ -270,7 +246,7 @@ export class FabricObjectSVGExportMixin {
return reviver ? reviver(markup.join('')) : markup.join('');
}

addPaintOrder() {
addPaintOrder(this: FabricObjectSVGExportMixin & FabricObject) {
return this.paintFirst !== 'fill'
? ` paint-order="${this.paintFirst}" `
: '';
Expand Down
Loading