diff --git a/index.ts b/index.ts
index 421de55c03a..be40e107ca5 100644
--- a/index.ts
+++ b/index.ts
@@ -1,6 +1,7 @@
import { Pattern } from './lib/pattern'
import { Point } from './lib/point'
import { Path } from './lib/path'
+import { Snippet } from './lib/snippet'
import themes from './lib/themes'
import * as utils from './lib/utils'
import bezier from 'bezier-js'
@@ -10,6 +11,7 @@ var Freesewing = {
pattern: Pattern,
point: Point,
path: Path,
+ snippet: Snippet,
utils,
bezier
}
diff --git a/lib/part.ts b/lib/part.ts
index 908b320fe97..e69a9c4b5af 100644
--- a/lib/part.ts
+++ b/lib/part.ts
@@ -1,5 +1,6 @@
import { Point } from './point'
import { Path } from './path'
+import { Snippet } from './snippet'
import { Attributes } from './attributes'
export class Part {
@@ -9,6 +10,7 @@ export class Part {
[index: string]: Point | boolean;
}
paths: { [index: string]: Path; } = {};
+ snippets: { [index: string]: Snippet; } = {};
attributes = new Attributes();
[propName: string]: any;
@@ -20,7 +22,6 @@ export class Part {
return this;
}
-
// purge = {
// points = function(prefix: string): void {}
// paths = function(prefix: string): void {}
diff --git a/lib/point.ts b/lib/point.ts
index 8d99fc4f9df..088e96112f9 100644
--- a/lib/point.ts
+++ b/lib/point.ts
@@ -1,9 +1,10 @@
import { round, rad2deg, deg2rad } from './utils';
-
+import { Attributes } from './attributes'
export class Point {
x: number;
y: number;
+ attributes: Attributes = new Attributes();
constructor(x: number, y: number) {
this.x = round(x);
diff --git a/lib/snippet.ts b/lib/snippet.ts
new file mode 100644
index 00000000000..081f42f1e22
--- /dev/null
+++ b/lib/snippet.ts
@@ -0,0 +1,17 @@
+import { Point } from './point'
+import { Attributes } from './attributes'
+
+export class Snippet {
+ anchor: Point;
+ def: string;
+ attributes: Attributes = new Attributes();
+ description: string | false;
+
+ constructor(anchor: Point, def: string, description: string | false = false) {
+ this.anchor = anchor;
+ this.def = def;
+ this.description = description;
+
+ return this;
+ }
+}
diff --git a/lib/svg.ts b/lib/svg.ts
index 3346ef73142..9595fb66c38 100644
--- a/lib/svg.ts
+++ b/lib/svg.ts
@@ -1,5 +1,6 @@
import { Part } from './part'
import { Path } from './path'
+import { Snippet } from './snippet'
import { Pattern } from './pattern'
import { Attributes } from './attributes'
@@ -7,6 +8,7 @@ export class Svg {
prefix: string;
body: string = '';
style: string = '';
+ script: string = '';
header: string = '';
footer: string = '';
defs: string = '';
@@ -33,6 +35,7 @@ export class Svg {
svg += this.renderComments(this.header);
svg += this.renderSvgTag(pattern);
svg += this.renderStyle();
+ svg += this.renderScript();
svg += this.renderDefs();
svg += this.openGroup('draftContainer');
for (let partId in pattern.parts) {
@@ -72,6 +75,17 @@ export class Svg {
return svg;
}
+ /** Returns SVG code for the script block */
+ renderScript() {
+ let svg = ''+this.nl();
+
+ return svg;
+ }
+
/** Returns SVG code for the defs block */
renderDefs() {
let svg = '';
@@ -91,16 +105,19 @@ export class Svg {
/** Returns SVG code for a Part object */
renderPart(part: Part): string {
let svg = '';
- for (let pathId in part.paths) {
- let path = part.paths[pathId];
+ for (let key in part.paths) {
+ let path = part.paths[key];
if(path.render) svg += this.renderPath(path);
}
+ for (let key in part.snippets) {
+ let snippet = part.snippets[key];
+ svg += this.renderSnippet(snippet);
+ }
// includes
// text on path
// notes
// dimensions
// texts
- // snippets
return svg;
}
@@ -111,6 +128,19 @@ export class Svg {
return `${this.nl()}`;
}
+ /** Returns SVG code for a snippet */
+ renderSnippet(snippet: Snippet): string {
+ let svg = this.nl();
+ svg += `';
+
+ return svg;
+ }
+
/** Returns SVG code to open a group */
openGroup(id: string, attributes?: Attributes): string {
diff --git a/lib/themes.ts b/lib/themes.ts
index 9812b98c960..3bb76f2cbc9 100644
--- a/lib/themes.ts
+++ b/lib/themes.ts
@@ -2,10 +2,11 @@ import { Draft } from './themes/draft'
import { Paperless } from './themes/paperless'
import { Sample } from './themes/sample'
import { Compare } from './themes/compare'
+import { Designer } from './themes/designer'
/** Standard themes that ship with freesewing */
var themes = {
- draft: new Draft(),
+ draft: new Designer(),
paperless: new Paperless(),
sample: new Sample(),
compare: new Compare()
diff --git a/lib/themes/designer.ts b/lib/themes/designer.ts
new file mode 100644
index 00000000000..642add790f0
--- /dev/null
+++ b/lib/themes/designer.ts
@@ -0,0 +1,149 @@
+import { Pattern } from '../pattern'
+import { Svg } from '../svg'
+import { Path } from '../path'
+import { Snippet } from '../snippet'
+import { Theme } from './theme';
+
+export class Designer extends Theme {
+ style: string = `
+ path.curve-control{stroke:#f0ad4e;stroke-width: 0.2;}
+ path.debug{stroke:#d9534f;stroke-opacity:0.4;stroke-width:2;}
+ .point{fill:none;stroke-width:0.6;stroke:#f0ad4e;}
+ text.tooltip{font-size:3px;}`;
+ defs: string = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ script:string = `
+ function pointHover(evt) {
+ var point = evt.target;
+ var id = point.id;
+ var cx = point.getAttribute('x');
+ var cy = point.getAttribute('y');
+ console.log('Point '+id+' ( '+cx+' , '+cy+' )');
+ var scale = 2;
+ cx = cx-scale*cx;
+ cy = cy-scale*cy;
+ point.setAttribute("transform", 'matrix('+scale+', 0, 0, '+scale+', '+cx+', '+cy+')');
+ setTimeout(function(){
+ var point = document.getElementById(evt.target.id);
+ point.removeAttribute("transform", '');
+ }, 1000);
+ }`;
+
+ /** Pre-render method is called just prior to rendering */
+ preRender(pattern: Pattern, svg: Svg): void {
+ super.preRender(pattern, svg);
+ svg.style += this.style;
+ svg.defs += this.defs;
+ svg.script += this.script;
+ svg.attributes.add('freesewing:theme', 'designer');
+ svg.attributes.add('viewBox', '-10 -10 300 500');
+ //this.decoratePoints(pattern, svg);
+ this.decoratePaths(pattern, svg);
+ }
+
+ /** Decorares points with extra info */
+ decoratePoints(pattern: Pattern, svg: Svg): void {
+ for (let partId in pattern.parts) {
+ let part = pattern.parts[partId];
+ if (part.render) {
+ for (let pointId in part.points) {
+ this.decoratePoint(pointId, part, svg);
+ }
+ }
+ }
+ }
+
+ /** Decorares a point with extra info */
+ decoratePoint(pointId: string, part: Part, svg: Svg): void {
+ let point = part.points[pointId];
+ point.attributes.add('id', svg.getUid());
+ point.attributes.add('data-point', id);
+ }
+
+ /** Decorares paths with extra info */
+ decoratePaths(pattern: Pattern, svg: Svg): void {
+ for (let partId in pattern.parts) {
+ let part = pattern.parts[partId];
+ if (part.render) {
+ for (let pathId in part.paths) {
+ this.decoratePath(pathId, part, svg);
+ }
+ }
+ }
+ }
+
+ /** Decorares a path with extra info */
+ decoratePath(pathId: string, part: Part, svg: Svg): void {
+ let path = part.paths[pathId];
+ if (!path.render) return false;
+ for (let op of path.ops) {
+ switch(op.type) {
+ case 'move':
+ let id = svg.getUid();
+ part.snippets[id] = new Snippet(op.to, 'path-start-point', `Startpoint of path ${pathId}`);
+ part.snippets[id].attributes.add('onmouseover', 'pointHover(evt)');
+ part.snippets[id].attributes.add('id', svg.getUid());
+ break;
+ case 'line':
+ let id = svg.getUid();
+ part.snippets[id] = new Snippet(op.to, 'path-point', `Line endpoint of path ${pathId}`);
+ part.snippets[id].attributes.add('onmouseover', 'pointHover(evt)');
+ part.snippets[id].attributes.add('id', svg.getUid());
+ break;
+ case 'curve':
+ let id = svg.getUid();
+ part.snippets[id] = new Snippet(op.to, 'path-point', `Curve endpoint of path ${pathId}`);
+ part.snippets[id].attributes.add('onmouseover', 'pointHover(evt)');
+ part.snippets[id].attributes.add('id', svg.getUid());
+ id = svg.getUid();
+ part.snippets[id] = new Snippet(op.cp1, 'path-curvecontrol', `Curve cp1 of path ${pathId}`);
+ part.snippets[id].attributes.add('onmouseover', 'pointHover(evt)');
+ part.snippets[id].attributes.add('id', svg.getUid());
+ id = svg.getUid();
+ part.snippets[id] = new Snippet(op.cp2, 'path-curvecontrol', `Curve cp2 of path ${pathId}`);
+ part.snippets[id].attributes.add('onmouseover', 'pointHover(evt)');
+ let cp1 = new Path().move(current).line(op.cp1);
+ let cp2 = new Path().move(op.to).line(op.cp2);
+ cp1.attributes.add('class', 'curve-control');
+ cp1.attributes.add('id', svg.getUid());
+ cp2.attributes.add('class', 'curve-control');
+ cp2.attributes.add('id', svg.getUid());
+ part.paths[svg.getUid()] = cp1;
+ part.paths[svg.getUid()] = cp2;
+ break;
+ }
+ let current = op.to;
+ }
+ }
+}
diff --git a/lib/themes/draft.ts b/lib/themes/draft.ts
index b88e72c9790..3d10768c605 100644
--- a/lib/themes/draft.ts
+++ b/lib/themes/draft.ts
@@ -1,3 +1,11 @@
+import { Pattern } from '../pattern'
+import { Svg } from '../svg'
import { Theme } from './theme';
-export class Draft extends Theme {}
+export class Draft extends Theme {
+ /** Pre-render method is called just prior to rendering */
+ preRender(pattern: Pattern, svg: Svg): void {
+ super.preRender(pattern, svg);
+ svg.attributes.add('freesewing:theme', 'draft');
+ }
+}
diff --git a/lib/themes/theme.ts b/lib/themes/theme.ts
index 1d81f9dc00a..24366c5064c 100644
--- a/lib/themes/theme.ts
+++ b/lib/themes/theme.ts
@@ -8,6 +8,7 @@ export abstract class Theme {
svg.header += this.loadHeader(pattern);
svg.footer += this.loadFooter(pattern);
svg.style += this.loadStyle(pattern);
+ svg.script += this.loadScript(pattern);
svg.defs += this.loadDefs(pattern);
}
@@ -116,6 +117,11 @@ export abstract class Theme {
.fill-gray{fill:#999}`;
}
+ /** Returns a string containing the SVG ECMA script */
+ loadScript(pattern: Pattern) {
+ return '';
+ }
+
/** Returns a string containing the SVG defs */
loadDefs(pattern: Pattern) {
return `