1
0
Fork 0

🚧 Progress on workbench

This commit is contained in:
Joost De Cock 2019-05-06 17:01:44 +02:00
parent 158c19ae1d
commit a888922968
31 changed files with 716 additions and 153 deletions

View file

@ -1,17 +1,14 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
const Circle = props => {
return null;
let foo = (
<circle
cx={props.point.x}
cy={props.point.y}
r={props.point.attributes.get("data-circle")}
{...props.point.attributes.asPropsIfPrefixIs("data-circle-")}
/>
);
};
const Circle = props => (
<circle
cx={props.point.x}
cy={props.point.y}
r={props.point.attributes.get("data-circle")}
{...props.point.attributes.asPropsIfPrefixIs("data-circle-")}
/>
);
Circle.propTypes = {
point: PropTypes.object.isRequired

View file

@ -0,0 +1,84 @@
import React from "react";
const Grid = props => {
let style = {
style: {
fill: "none",
stroke: "currentColor"
}
};
if (props.units === "imperial")
return (
<pattern
id="grid"
height="25.4"
width="25.4"
patternUnits="userSpaceOnUse"
key="grid"
>
<path
className="gridline lg imperial"
d="M 0 0 L 0 25.4 L 25.4 25.4"
{...style}
/>
<path
className="gridline lg imperial"
d="M 12.7 0 L 12.7 25.4 M 0 12.7 L 25.4 12.7"
{...style}
/>
<path
className="gridline sm imperial"
d="M 3.175 0 L 3.175 25.4 M 6.32 0 L 6.35 25.4 M 9.525 0 L 9.525 25.4 M 15.875 0 L 15.875 25.4 M 19.05 0 L 19.05 25.4 M 22.225 0 L 22.225 25.4"
{...style}
/>
<path
className="gridline sm imperial"
d="M 0 3.175 L 25.4 3.175 M 0 6.32 L 25.4 6.35 M 0 9.525 L 25.4 9.525 M 0 15.875 L 25.4 15.875 M 0 19.05 L 25.4 19.05 M 0 22.225 L 25.4 22.225"
{...style}
/>
</pattern>
);
else
return (
<pattern
id="grid"
height="100"
width="100"
patternUnits="userSpaceOnUse"
key="grid"
>
<path
className="gridline lg metric"
d="M 0 0 L 0 100 L 100 100"
{...style}
/>
<path
className="gridline metric"
d="M 50 0 L 50 100 M 0 50 L 100 50"
{...style}
/>
<path
className="gridline sm metric"
d="M 10 0 L 10 100 M 20 0 L 20 100 M 30 0 L 30 100 M 40 0 L 40 100 M 60 0 L 60 100 M 70 0 L 70 100 M 80 0 L 80 100 M 90 0 L 90 100"
{...style}
/>
<path
className="gridline sm metric"
d="M 0 10 L 100 10 M 0 20 L 100 20 M 0 30 L 100 30 M 0 40 L 100 40 M 0 60 L 100 60 M 0 70 L 100 70 M 0 80 L 100 80 M 0 90 L 100 90"
{...style}
/>
<path
className="gridline xs metric"
d="M 5 0 L 5 100 M 15 0 L 15 100 M 25 0 L 25 100 M 35 0 L 35 100 M 45 0 L 45 100 M 55 0 L 55 100 M 65 0 L 65 100 M 75 0 L 75 100 M 85 0 L 85 100 M 95 0 L 95 100"
{...style}
/>
<path
className="gridline xs metric"
d="M 0 5 L 100 5 M 0 15 L 100 15 M 0 25 L 100 25 M 0 35 L 100 35 M 0 45 L 100 45 M 0 55 L 100 55 M 0 65 L 100 65 M 0 75 L 100 75 M 0 85 L 100 85 M 0 95 L 100 95"
{...style}
/>
</pattern>
);
};
export default Grid;

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,34 @@
import React from "react";
const Markers = props => {
const markerProps = {
orient: "auto",
refX: "0.0",
refY: "0.0",
style: { overflow: "visible" }
};
const from = { d: "M 0,0 L 12,-4 C 10,-2 10,2 12, 4 z" };
const to = { d: "M 0,0 L -12,-4 C -10,-2 -10,2 -12, 4 z" };
const types = {
grainline: "note",
cutonfold: "note",
dimension: "mark"
};
let output = [];
for (let type in types) {
output.push(
<marker id={type + "From"} key={type + "-from"} {...markerProps}>
<path className={types[type] + " fill-" + types[type]} {...from} />
</marker>
);
output.push(
<marker id={type + "To"} key={type + "-to"} {...markerProps}>
<path className={types[type] + " fill-" + types[type]} {...to} />
</marker>
);
}
return output;
};
export default Markers;

View file

@ -0,0 +1,41 @@
import React from "react";
import logoPathString from "./logo-path";
const Snippets = props => {
const fill = { fill: "currentColor", stroke: "none" };
const stroke = { fill: "none", stroke: "currentColor" };
return [
<g id="notch" className="snippet notch" key="notch">
<circle cy="0" cx="0" r="1.4" {...fill} />
<circle cy="0" cx="0" r="2.8" {...stroke} />
</g>,
<g id="bnotch" className="snippet bnotch" key="bnotch">
<path d="M -1.1 -1.1 L 1.1 1.1 M 1.1 -1.1 L -1.1 1.1" {...stroke} />
<circle cy="0" cx="0" r="2.8" {...stroke} />
</g>,
<g id="button" className="snippet button" key="button">
<circle cx="0" cy="0" r="3.4" {...stroke} /> />
<circle cx="-1" cy="-1" r="0.5" {...fill} />
<circle cx="1" cy="-1" r="0.5" {...fill} />
<circle cx="1" cy="1" r="0.5" {...fill} />
<circle cx="-1" cy="1" r="0.5" {...fill} />
</g>,
<g id="buttonhole" className="snippet buttonhole" key="buttonhole">
<path d="M -1,-5 L 1,-5 L 1,5 L -1,5 z" {...stroke} />
<path
d="M -1,-5 L 1,-5 L 1,-4 L -1,-4 z M -1,5 L 1,5 L 1,4 L -1,4 z"
{...fill}
/>
</g>,
<g
id="logo"
className="snippet logo"
transform="translate(-23 -36)"
key="logo"
>
<path d={logoPathString} {...fill} />
</g>
];
};
export default Snippets;

File diff suppressed because one or more lines are too long

View file

@ -1,9 +1,37 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import React from "react";
import Markers from "./Markers";
import Snippets from "./Snippets";
import Grid from "./Grid";
const Defs = props => <defs>{props.defs}</defs>;
Defs.propTypes = { defs: PropTypes.string };
Defs.defaultProps = { defs: "" };
const Defs = props => {
let paperlessGrids = null;
if (props.paperless) {
paperlessGrids = [];
for (let p in props.parts) {
let anchor = { x: 0, y: 0 };
if (typeof props.parts[p].points.gridAnchor !== "undefined")
anchor = props.parts[p].points.gridAnchor;
else if (typeof props.parts[p].points.anchor !== "undefined")
anchor = props.parts[p].points.anchor;
paperlessGrids.push(
<pattern
id={"grid-" + p}
key={"grid-" + p}
xlinkHref="#grid"
x={anchor.x}
y={anchor.y}
/>
);
}
}
return (
<defs>
<Markers />
<Snippets />
<Grid units={props.units} />
{paperlessGrids}
</defs>
);
};
export default Defs;

View file

@ -2,21 +2,45 @@ import React, { useState } from "react";
import PropTypes from "prop-types";
import Path from "../Path";
import Point from "../Point";
import Snippet from "../Snippet";
import { getProps } from "../utils";
const Part = props => {
console.log(props.part);
let grid = props.paperless ? (
<rect
x={props.part.topLeft.x}
y={props.part.topLeft.y}
width={props.part.width}
height={props.part.height}
className="grid"
fill={"url(#grid-" + props.name + ")"}
/>
) : null;
return (
<g {...getProps(props.part)}>
{grid}
{Object.keys(props.part.points).map(name => (
<Point
key={name}
name={name}
part={props.name}
language={props.language}
point={props.part.points[name]}
/>
))}
{Object.keys(props.part.paths).map(name => (
<Path key={name} name={name} path={props.part.paths[name]} />
<Path
key={name}
name={name}
part={props.name}
language={props.language}
path={props.part.paths[name]}
/>
))}
{Object.keys(props.part.snippets).map(name => (
<Snippet key={name} name={name} snippet={props.part.snippets[name]} />
))}
</g>
);
@ -25,7 +49,9 @@ const Part = props => {
Part.propTypes = {
part: PropTypes.object.isRequired,
name: PropTypes.string.isRequired,
language: PropTypes.string.isRequired
language: PropTypes.string.isRequired,
paperless: PropTypes.bool.isRequired,
units: PropTypes.oneOf(["metric", "imperial"]).isRequired
};
export default Part;

View file

@ -1,14 +1,36 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import TextOnPath from "../TextOnPath";
import { getProps } from "../utils";
const Path = props => {
if (!props.path.render) return null;
return <path d={props.path.asPathstring()} {...getProps(props.path)} />;
const output = [];
const pathId = "path-" + props.part + "-" + props.name;
output.push(
<path
id={pathId}
key={"path-" + props.name}
d={props.path.asPathstring()}
{...getProps(props.path)}
/>
);
if (props.path.attributes.get("data-text"))
output.push(
<TextOnPath
key={"text-on-path-" + props.name}
pathId={pathId}
{...props}
/>
);
return output;
};
Path.propTypes = {
path: PropTypes.object.isRequired
path: PropTypes.object.isRequired,
name: PropTypes.string.isRequired,
language: PropTypes.string.isRequired
};
export default Path;

View file

@ -0,0 +1,39 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import Text from "../Text";
import Circle from "../Circle";
const Snippet = props => {
const snippetProps = {
xlinkHref: "#" + props.snippet.def,
x: props.snippet.anchor.x,
y: props.snippet.anchor.y
};
let scale = props.snippet.attributes.get("data-scale");
let rotate = props.snippet.attributes.get("data-rotate");
if (scale || rotate) {
snippetProps.transform = "";
if (scale) {
snippetProps.transform += `translate(${snippetProps.x}, ${
snippetProps.y
}) `;
snippetProps.transform += `scale(${scale}) `;
snippetProps.transform += `translate(${snippetProps.x *
-1}, ${snippetProps.y * -1}) `;
}
if (rotate) {
snippetProps.transform += `rotate(${rotate}, ${snippetProps.x}, ${
snippetProps.y
}) `;
}
}
return <use {...snippetProps} />;
};
Snippet.propTypes = {
snippet: PropTypes.object.isRequired,
name: PropTypes.string.isRequired
};
export default Snippet;

View file

@ -30,7 +30,6 @@ const Text = props => {
);
}
} else text.push(<tspan key="tspan-1">{translated}</tspan>);
return null;
return (
<text
x={props.point.x}
@ -43,7 +42,8 @@ const Text = props => {
};
Text.propTypes = {
point: PropTypes.object.isRequired
point: PropTypes.object.isRequired,
language: PropTypes.string.isRequired
};
export default Text;

View file

@ -0,0 +1,40 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import { strings } from "@freesewing/i18n";
const TextOnPath = props => {
let text = [];
// Handle translation
let translated = "";
for (let string of props.path.attributes.getAsArray("data-text")) {
if (strings[props.language]["plugin." + string])
translated += strings[props.language]["plugin." + string];
else translated += string;
translated += " ";
}
let textPathProps = {
xlinkHref: "#" + props.pathId,
startOffset: "0%"
};
let align = props.path.attributes.get("data-text-class");
if (align && align.indexOf("center") > -1) textPathProps.startOffset = "50%";
else if (align && align.indexOf("right") > -1)
textPathProps.startOffset = "100%";
return (
<text>
<textPath {...textPathProps}>
<tspan {...props.path.attributes.asPropsIfPrefixIs("data-text-")}>
{translated}
</tspan>
</textPath>
</text>
);
};
TextOnPath.propTypes = {
path: PropTypes.object.isRequired,
language: PropTypes.string.isRequired
};
export default TextOnPath;

View file

@ -1,93 +0,0 @@
svg.freesewing {
/* Reset */
path,circle,rect{fill:none;stroke:none}
/* Defaults */
path,circle{
stroke:#000;
stroke-opacity:1;
stroke-width:.3;
stroke-linecap:round;
stroke-linejoin:round;
}
/* Stroke classes */
.fabric{
stroke-width:.6;
stroke:#212121
}
.lining{
stroke-width:.6;
stroke:#ff5b77;
}
.interfacing{
stroke-width:.6;
stroke:#64b5f6;
}
.canvas{
stroke-width:.6;
stroke:#ff9000;
}
.various{
stroke-width:.6;
stroke:#4caf50;
}
.note{
stroke-width:.4;
stroke:#dd60dd;
}
.mark{
stroke-width:.4;
stroke:blue;
}
.contrast{
stroke-width:.8;
stroke:red;
}
.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; }
.sa { stroke-dasharray:0.4,0.8; }
.help {
stroke-width:.2;
stroke-dasharray:15,1.5,1,1.5;
}
.dotted { stroke-dasharray:0.4,0.8; }
.dashed { stroke-dasharray:1,1.5; }
.lashed { stroke-dasharray:6,6; }
.hidden {
stroke:none;
fill:none;
}
/* Fill classes */
.fill-fabric{ fill:#212121; }
.fill-lining{ fill:#ff5b77; }
.fill-interfacing{ fill:#64b5f6; }
.fill-canvas{ fill:#ff9000; }
.fill-various{ fill:#4caf50; }
.fill-note{ fill:#dd69dd; }
.fill-mark{ fill:blue; }
.fill-contrast{ fill:red; }
/* Text */
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;
dominant-baseline:ideographic;
}
.text-xs { font-size:3px; }
.text-sm { font-size:4px; }
.text-lg { font-size:7px; }
.text-xl { font-size:9px; }
.text-xxl{ font-size:12px; }
.center{ text-anchor:middle; }
.right{ text-anchor:end; }
}

View file

@ -1,8 +1,7 @@
import React, { useState } from "react";
import PropTypes from "prop-types";
import Svg from "./Svg";
//import Style from "./Style";
//import Defs from "./Defs";
import Defs from "./Defs";
import Part from "./Part";
const Draft = props => {
@ -14,11 +13,18 @@ const Draft = props => {
language={props.settings.locale}
id={props.settings.idPrefix + "svg"}
>
<Defs
units={props.settings.units}
parts={props.parts}
paperless={props.settings.paperless}
/>
<g>
{Object.keys(props.parts).map(name => (
<Part
part={props.parts[name]}
language={props.settings.locale}
paperless={props.settings.paperless}
units={props.settings.units}
key={name}
name={name}
/>

View file

@ -51,7 +51,7 @@ const OptionGroup = props => {
return <Count {...option} {...extraProps} />;
break;
default:
throw new Error("Unsupport option type: " + type);
throw new Error("Unsupported option type: " + type);
}
};

View file

@ -64,7 +64,7 @@ const Footer = props => {
);
}
return (
<div>
<div key={l}>
<h4>
<FormattedMessage id={"app." + l} />
</h4>

View file

@ -58,6 +58,7 @@ const Workbench = props => {
};
const measurementsMissing = () => {
let required = props.config.measurements;
if (required.length < 1) return false;
if (measurements === null) return true;
for (let m of required) {
if (typeof measurements[m] === "undefined") return true;