diff --git a/config/config.ts b/config/config.ts deleted file mode 100644 index ffc07605908..00000000000 --- a/config/config.ts +++ /dev/null @@ -1,3 +0,0 @@ -export var config = { - precision: 2 -} diff --git a/index.ts b/index.ts index 011eec6d081..421de55c03a 100644 --- a/index.ts +++ b/index.ts @@ -1,13 +1,12 @@ import { Pattern } from './lib/pattern' import { Point } from './lib/point' import { Path } from './lib/path' -import { config } from './config/config' +import themes from './lib/themes' import * as utils from './lib/utils' import bezier from 'bezier-js' var Freesewing = { version: '1.0.1', - config, pattern: Pattern, point: Point, path: Path, diff --git a/lib/path.ts b/lib/path.ts index cd01d67af24..bbe2bbabb65 100644 --- a/lib/path.ts +++ b/lib/path.ts @@ -3,10 +3,7 @@ import { Attributes } from './attributes' export class Path { - constructor() { - return this; - } - + render: boolean = true; ops: { type: "move" | "line" | "curve" | "close"; to?: Point; @@ -69,10 +66,4 @@ export class Path { return d; } - /** Returns SVG code for this path */ - render(): string { - this.attributes.add('d', this.asPathstring()); - return ``; - - } } diff --git a/lib/pattern.ts b/lib/pattern.ts index fdc29a05734..9e39bb5345e 100644 --- a/lib/pattern.ts +++ b/lib/pattern.ts @@ -1,14 +1,18 @@ import { PatternConfig, PatternOption } from './types' import { Part } from './part' -import { Renderer } from './renderer' +import { Svg } from './svg' import { Option } from './option' +import themes from './themes' +import { Theme } from './themes/theme' export class Pattern { config: PatternConfig; + svg: Svg = new Svg(); parts: { [index: string]: Part; } options: {[propName: string]: number}; + themes: {[index:string]: Theme} = themes; constructor(config: PatternConfig) { this.config = config; @@ -31,8 +35,8 @@ export class Pattern { throw Error('You have to implement the draft() method in your Pattern instance.'); } - render(pattern: Pattern): string { - let r = new Renderer(); - return r.render(pattern); + render(): string { + let svg = new Svg(); + return svg.render(this); } } diff --git a/lib/point.ts b/lib/point.ts index 008bbd6cb8e..1a70db9089e 100644 --- a/lib/point.ts +++ b/lib/point.ts @@ -1,11 +1,10 @@ import { round, rad2deg, deg2rad } from './utils'; -const PRECISION = 2; export class Point { x: number; y: number; - + readonly PRECISION = 2; constructor(x: number, y: number) { this.x = round(x); @@ -19,7 +18,7 @@ export class Point { let dx = this.x - that.x; let dy = this.y - that.y; - return round(Math.sqrt(Math.pow(dx, 2) + Math.pow(dy,2))); + return round(Math.sqrt(Math.pow(dx, this.PRECISION) + Math.pow(dy, this.PRECISION))); } /** Returns slope of a line made by this point and that point */ diff --git a/lib/renderer.ts b/lib/svg.ts similarity index 74% rename from lib/renderer.ts rename to lib/svg.ts index 26e1519e5ad..ea9762d45be 100644 --- a/lib/renderer.ts +++ b/lib/svg.ts @@ -3,14 +3,27 @@ import { Path } from './path' import { Pattern } from './pattern' import { Attributes } from './attributes' -export class Renderer { - svg = ''; +export class Svg { + prefix: string; + body: string = ''; + style: string = ''; + header: string = ''; + footer: string = ''; + defs: string = ''; + attributes: Attributes = new Attributes(); readonly TAB = ' '; tabs: number = 0; freeId: number = 1; openGroups: string[] = []; constructor() { + this.prefix = ''; + this.attributes.add + this.attributes.add("xmlns", "http://www.w3.org/2000/svg"); + this.attributes.add("xmlns:svg", "http://www.w3.org/2000/svg"); + this.attributes.add("xmlns:xlink", "http://www.w3.org/1999/xlink"); + this.attributes.add("xmlns:freesewing", "http://freesewing.org/namespaces/freesewing"); + return this; } @@ -49,7 +62,8 @@ export class Renderer { /** Returns SVG code for a Path object */ renderPath(path: Path): string { - return `${this.nl()}`; + path.attributes.add('d', path.asPathstring()); + return `${this.nl()}`; } diff --git a/lib/themes.ts b/lib/themes.ts new file mode 100644 index 00000000000..9812b98c960 --- /dev/null +++ b/lib/themes.ts @@ -0,0 +1,14 @@ +import { Draft } from './themes/draft' +import { Paperless } from './themes/paperless' +import { Sample } from './themes/sample' +import { Compare } from './themes/compare' + +/** Standard themes that ship with freesewing */ +var themes = { + draft: new Draft(), + paperless: new Paperless(), + sample: new Sample(), + compare: new Compare() +} + +export default themes; diff --git a/lib/themes/compare.ts b/lib/themes/compare.ts new file mode 100644 index 00000000000..d11ed206a75 --- /dev/null +++ b/lib/themes/compare.ts @@ -0,0 +1,10 @@ +import { Sample } from './sample'; + +export class Compare extends Sample { + constructor() { + super(); + this.style += ` + path.compare { fill: #000000; fill-opacity: 0.05; stroke: #000000; stroke-opacity:0.5; stroke-width: 1; stroke-linecap:round; stroke-linejoin:round; } + `; + } +} diff --git a/lib/themes/draft.ts b/lib/themes/draft.ts new file mode 100644 index 00000000000..b88e72c9790 --- /dev/null +++ b/lib/themes/draft.ts @@ -0,0 +1,3 @@ +import { Theme } from './theme'; + +export class Draft extends Theme {} diff --git a/lib/themes/paperless.ts b/lib/themes/paperless.ts new file mode 100644 index 00000000000..48c115b0177 --- /dev/null +++ b/lib/themes/paperless.ts @@ -0,0 +1,30 @@ +import { Sample } from './sample'; + +export class Paperless extends Sample { + constructor() { + super(); + this.style += ` + rect.grid{fill:none;stroke:#555;stroke-width:0.3;fill:url(#grid);} + path.gridline{stroke:#555;stroke-width:0.2;} + path.gridline-lg{stroke:#777;stroke-width:0.2;stroke-dasharray:1.5,1.5;} + path.gridline-sm{stroke:#999;stroke-width:0.1;} + path.gridline-xs{stroke:#999;stroke-width:0.1;stroke-dasharray:0.5,0.5;} + `; + this.defs += ` + + + + + + + + + + + + + + + `; + } +} diff --git a/lib/themes/sample.ts b/lib/themes/sample.ts new file mode 100644 index 00000000000..7fa3e29c4a2 --- /dev/null +++ b/lib/themes/sample.ts @@ -0,0 +1,11 @@ +import { Theme } from './theme'; + +export class Sample extends Theme { + constructor() { + super(); + this.style += ` + path { fill: none; stroke: #000000; stroke-opacity:1; stroke-width: 0.5; stroke-miterlimit:4; stroke-dashoffset:0; stroke-linecap:round; stroke-linejoin:round; } + path.hidden { fill: none; stroke: none; } + `; + } +} diff --git a/lib/themes/theme.ts b/lib/themes/theme.ts new file mode 100644 index 00000000000..5e8a63c4456 --- /dev/null +++ b/lib/themes/theme.ts @@ -0,0 +1,144 @@ +export abstract class Theme { + header: string = ''; + footer: string = ''; + defs: string = ''; + style: string = ''; + + constructor() { + this.header = this.loadHeader(); + this.footer = this.loadFooter(); + this.style = this.loadStyle(); + this.defs = this.loadDefs(); + } + + /** Returns a string containing the SVG header */ + loadHeader() { + + return ` + +`; + } + + /** Returns a string containing the SVG footer */ + loadFooter() { + return ''; + } + + /** Returns a string containing the SVG style/CSS */ + loadStyle() { + return ` + path,circle,rect{fill:none;stroke:none} + path{fill:none;stroke:#000;stroke-opacity:1;stroke-width:.3;stroke-linecap:round;stroke-linejoin:round} + path.fabric{stroke-width:.6;stroke:#653f95} + path.lining{stroke-width:.6;stroke:#0275d8} + path.interfacing{stroke-width:.6;stroke:#d9534f} + path.canvas{stroke-width:.6;stroke:#5cb85c} + path.various{stroke-width:.6;stroke:#5bc0de} + path.sa{stroke-dasharray:0.4,0.8} + path.help{stroke-width:.2;stroke-dasharray:15,1.5,1,1.5} + path.hint{stroke-width:.2;stroke-dasharray:0.4,0.8} + path.note{stroke:#0275d8;stroke-width:.6;marker-start:url(#noteArrow)} + text{font-size:5px;font-family:-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;fill:#000; + text-anchor:start;font-weight:200} + text.center{text-anchor:middle} + text.part-nr{font-size:28px;text-anchor:middle;fill:#000;font-weight:100} + text.part-nr.horizontal{text-anchor:start} + text.part-title{font-size:18px;text-anchor:middle;fill:#000} + text.part-title.horizontal{text-anchor:start} + text.pattern-title{font-size:8px;font-weight:bold;text-anchor:middle;fill:#000} + text.pattern-title.horizontal{text-anchor:start} + text.part-msg{font-size:10px;text-anchor:middle} + text.part-meta{font-size:7px;text-anchor:middle} + text.part-msg.horizontal,text.part-meta.horizontal,text.part-title.vertical,text.part-msg.vertical{text-anchor:start} + text.part-nr.small{font-size:14px} + text.part-title.small{font-size:9px} + text.pattern-title.small{font-size:4px} + text.part-msg.small{font-size:5px} + text.part-meta.small{font-size:5px} + text.part-nr.extrasmall{font-size:7px} + text.part-title.extrasmall{font-size:5px} + text.pattern-title.extrasmall{font-size:3px} + text.part-msg.extrasmall{font-size:4px} + text.part-meta.extrasmall{font-size:3px} + text.note,text.dimension-label{fill:#0275d8} + text.note tspan{alignment-baseline:middle} + text.note-5,text.note-6,text.note-7,text.note-11,text.note-12,text.note-0,text.note-1,text.dimension-label{text-anchor:middle} + text.note-8,text.note-9,text.note-10{text-anchor:end} + text.dimension-label{font-size:7px} + text.grainline{fill:#999} + path.arrow{stroke:#0275d8} + path.grainline{stroke:#999;stroke-width:.6;marker-start:url(#grainlineStart);marker-end:url(#grainlineEnd)} + path.dimension{stroke:#0275d8;stroke-width:.6;marker-start:url(#dimensionStart);marker-end:url(#dimensionEnd)} + path.dimension.dimension-sm{stroke-width:.3} + path.dimension-leader{stroke:#0275d8;stroke-width:.3} + path.single-arrow{marker-start:url(#dimensionStart)} + path.double-arrow{marker-start:url(#dimensionStart);marker-end:url(#dimensionEnd)} + .text-xs{font-size:3px} + .text-sm{font-size:4px} + .text-lg{font-size:7px} + .text-xl{font-size:9px} + .text-center{text-anchor:middle} + .stroke-xs{stroke-width:.1} + .stroke-sm{stroke-width:.2} + .stroke-lg{stroke-width:.6} + .stroke-xl{stroke-width:1} + .stroke-xxl{stroke-width:2} + .dashed{stroke-dasharray:1,1.5} + .lashed{stroke-dasharray:6,6} + .dotted{stroke-dasharray:0.4,0.8} + .hidden{stroke:none;file:none} + .stroke-fabric{stroke:#653f95} + .stroke-lining{stroke:#0275d8} + .stroke-interfacing{stroke:#d9534f} + .stroke-canvas{stroke:#5cb85c} + .stroke-note{stroke:#0275d8} + .stroke-mark{stroke:#f0ad4e} + .stroke-hint{stroke:#86739c} + .stroke-gray{stroke:#999} + .fill-fabric{fill:#653f95} + .fill-lining{fill:#0275d8} + .fill-interfacing{fill:#d9534f} + .fill-canvas{fill:#5cb85c} + .fill-note{fill:#0275d8} + .fill-mark{fill:#f0ad4e} + .fill-hint{fill:#86739c} + .fill-gray{fill:#999}`; + } + + /** Returns a string containing the SVG defs */ + loadDefs() { + return ` + + + + + + + + + + + freesewing core v__VERSION__ __TITLE__ freesewing.org/drafts/__DRAFTHANDLE__ __SCALEBOX_METRIC__ __SCALEBOX_IMPERIAL__ + + + + + + + +`; + } +}