diff --git a/packages/examples/config/index.js b/packages/examples/config/index.js index 27d02ddc827..d9f3bf0f8e3 100644 --- a/packages/examples/config/index.js +++ b/packages/examples/config/index.js @@ -3,11 +3,13 @@ import { version } from "../package.json"; export default { name: "examples", version, - // This is not needed, but is here to sidestep an issue in freesewing - // that needs to be fixed but hasn't yet - dependencies: { - path_attr: "path_ops" + design: "Joost De Cock", + code: "Joost De Cock", + optionGroups: { + fit: ["fixme"] }, + measurements: [], + dependencies: {}, parts: [ "point_attr", "path__curve", @@ -70,6 +72,15 @@ export default { "utils_lineintersectscircle", "utils_curveintersectsy", "utils_curveintersectsx", - "utils_splitcurve" - ] + "utils_splitcurve", + "docs_overview" + ], + options: { + // Optiongroups are needed for now, because workbench + fixme: { + pct: 50, + min: 0, + max: 100 + } + } }; diff --git a/packages/examples/package.json b/packages/examples/package.json index c0039a1deaf..52f84d4f4fa 100644 --- a/packages/examples/package.json +++ b/packages/examples/package.json @@ -25,6 +25,7 @@ "test": "echo \"examples: No tests configured. Perhaps you'd like to do this?\" && exit 0", "pubtest": "npm publish --registry http://localhost:6662", "pubforce": "npm publish", + "start": "rollup -c -w", "symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -" }, "peerDependencies": { diff --git a/packages/examples/rollup.config.js b/packages/examples/rollup.config.js index dbee92ea2c2..ed2061ce7c7 100644 --- a/packages/examples/rollup.config.js +++ b/packages/examples/rollup.config.js @@ -8,18 +8,26 @@ import url from "rollup-plugin-url"; import postcss from "rollup-plugin-postcss"; import svgr from "@svgr/rollup"; import peerDepsExternal from "rollup-plugin-peer-deps-external"; -import { name, version, description, author, license } from "./package.json"; +import { + name, + version, + description, + author, + license, + main, + module +} from "./package.json"; export default { input: "src/index.js", output: [ { - file: "dist/index.js", + file: main, format: "cjs", sourcemap: true }, { - file: "dist/index.mjs", + file: module, format: "es", sourcemap: true } diff --git a/packages/examples/src/docs_overview.js b/packages/examples/src/docs_overview.js new file mode 100644 index 00000000000..589e38a9066 --- /dev/null +++ b/packages/examples/src/docs_overview.js @@ -0,0 +1,335 @@ +export default part => { + let { Point, points, Path, paths } = part.shorthand(); + + /** + * Returs the value passed to it randomized with a given tolerance + */ + const about = (value, tolerance = 5) => { + let randomized = (tolerance / 100) * Math.random() * value; + let fixed = (1 - tolerance / 100) * value; + + return fixed + randomized; + }; + + /** + * like about, but also randomly makes value negative + * This is for degrees + */ + const nabout = (value, tolerance = 5) => { + if (Math.random() > 0.5) return about(value, tolerance); + else return -1 * about(value, tolerance); + }; + + /** + * Draws a w*h box that's randomized by tolerance to give it + * that hand-drawn look. + * + * Returns a Path object + */ + const box = (name, origin, width, height, tolerance = 10) => { + let base = height; + if (width < height) base = width; + let t = base * (tolerance / 100); + points[name + "TopLeft"] = new Point( + about(origin.x, t), + about(origin.y, t) + ); + points[name + "BottomLeft"] = new Point( + about(origin.x, t), + about(origin.y + height, t) + ); + points[name + "BottomRight"] = new Point( + about(origin.x + width, t), + about(origin.y + height, t) + ); + points[name + "TopRight"] = new Point( + about(origin.x + width, t), + about(origin.y, t) + ); + points[name + "Mid"] = points[name + "TopLeft"].shiftFractionTowards( + points[name + "BottomRight"], + 0.5 + ); + points[name + "Mid"].y += 3; + + let f = 0.3; + let r = tolerance / 2; + points[name + "TopLeftCp1"] = points[name + "TopLeft"] + .shiftFractionTowards(points[name + "BottomLeft"], about(f)) + .rotate(nabout(r), points[name + "TopLeft"]); + points[name + "TopLeftCp2"] = points[name + "TopLeft"] + .shiftFractionTowards(points[name + "TopRight"], about(f)) + .rotate(nabout(r), points[name + "TopLeft"]); + points[name + "BottomLeftCp1"] = points[name + "BottomLeft"] + .shiftFractionTowards(points[name + "TopLeft"], about(f)) + .rotate(nabout(r), points[name + "BottomLeft"]); + points[name + "BottomLeftCp2"] = points[name + "BottomLeft"] + .shiftFractionTowards(points[name + "BottomRight"], about(f)) + .rotate(nabout(r), points[name + "BottomLeft"]); + points[name + "BottomRightCp1"] = points[name + "BottomRight"] + .shiftFractionTowards(points[name + "BottomLeft"], about(f)) + .rotate(nabout(r), points[name + "BottomRight"]); + points[name + "BottomRightCp2"] = points[name + "BottomRight"] + .shiftFractionTowards(points[name + "TopRight"], about(f)) + .rotate(nabout(r), points[name + "BottomRight"]); + points[name + "TopRightCp1"] = points[name + "TopRight"] + .shiftFractionTowards(points[name + "BottomRight"], about(f)) + .rotate(nabout(r), points[name + "TopRight"]); + points[name + "TopRightCp2"] = points[name + "TopRight"] + .shiftFractionTowards(points[name + "TopLeft"], about(f)) + .rotate(nabout(r), points[name + "TopRight"]); + + return new Path() + .move(points[name + "TopLeft"]) + .curve( + points[name + "TopLeftCp1"], + points[name + "BottomLeftCp1"], + points[name + "BottomLeft"] + ) + .curve( + points[name + "BottomLeftCp2"], + points[name + "BottomRightCp1"], + points[name + "BottomRight"] + ) + .curve( + points[name + "BottomRightCp2"], + points[name + "TopRightCp1"], + points[name + "TopRight"] + ) + .curve( + points[name + "TopRightCp2"], + points[name + "TopLeftCp2"], + points[name + "TopLeft"] + ) + .close() + .attr("class", "fabric"); + }; + + /** + * Draws an arrow from to + * Returns a Path object + */ + const arrow = (name, text = "", tolerance = 10) => { + let from = points[name + "From"]; + let to = points[name + "To"]; + from = from.shiftTowards(to, 3); + to = to.shiftTowards(from, 3); + let base = from.dist(to); + let t = base * (tolerance / 100); + from.x = about(from.x, t); + from.x = about(from.x, t); + to.x = about(to.x, t); + to.x = about(to.x, t); + let f = 0.3; + let r = tolerance / 2; + points[name + "FromCp"] = from + .shiftFractionTowards(to, about(f)) + .rotate(nabout(r), from); + points[name + "ToCp"] = to + .shiftFractionTowards(from, about(f)) + .rotate(nabout(r), to); + points[name + "Tip1"] = to + .shiftTowards(from, about(3.8)) + .rotate(about(15), to); + points[name + "Tip2"] = to + .shiftTowards(from, about(3.5)) + .rotate(about(-15), to); + let path = new Path() + .move(from) + .curve(points[name + "FromCp"], points[name + "ToCp"], to) + .move(points[name + "Tip1"]) + .line(to) + .line(points[name + "Tip2"]) + .attr("class", "fabric"); + if (text) + return path + .attr("data-text", " " + text) + .attr("data-text-class", "scribble"); + else return path; + }; + + const drawBox = (name, x, y, width, height, tolerance = 5, text = true) => { + points[name + "Origin"] = new Point(x, y); + paths[name] = box(name, points[name + "Origin"], width, height, tolerance); + if (text) { + points[name + "Mid"] + .attr("data-text", name) + .attr("data-text-class", "center scribble"); + } + }; + + const svgLogo = (anchor, size = 1) => { + points.svg15 = anchor + .shift(45, 4 * size) + .attr("data-circle", 1.2 * size) + .attr("data-circle-class", "fill-fabric"); + points.svg3 = anchor + .shift(0, 4 * size) + .attr("data-circle", 1.2 * size) + .attr("data-circle-class", "fill-fabric"); + points.svg45 = anchor + .shift(-45, 4 * size) + .attr("data-circle", 1.2 * size) + .attr("data-circle-class", "fill-fabric"); + points.svg6 = anchor + .shift(-90, 4 * size) + .attr("data-circle", 1.2 * size) + .attr("data-circle-class", "fill-fabric"); + points.svg75 = anchor + .shift(-135, 4 * size) + .attr("data-circle", 1.2 * size) + .attr("data-circle-class", "fill-fabric"); + points.svg9 = anchor + .shift(180, 4 * size) + .attr("data-circle", 1.2 * size) + .attr("data-circle-class", "fill-fabric"); + points.svg105 = anchor + .shift(135, 4 * size) + .attr("data-circle", 1.2 * size) + .attr("data-circle-class", "fill-fabric"); + points.svg12 = anchor + .shift(90, 4 * size) + .attr("data-circle", 1.2 * size) + .attr("data-circle-class", "fill-fabric"); + points.svgText = anchor + .clone() + .attr("data-text", "SVG") + .attr("data-text-class", "text-xl scribble"); + points.svgText.x += size * 7; + points.svgText.y += 6; + paths.svgLogo = new Path() + .move(points.svg15) + .line(points.svg75) + .move(points.svg3) + .line(points.svg9) + .move(points.svg45) + .line(points.svg105) + .move(points.svg6) + .line(points.svg12) + .attr("class", "stroke-l"); + }; + const reactLogo = (anchor, size = 1) => { + h = 3 * size; + w = 6 * size; + points.reactTop1 = anchor.shift(45, w); + points.reactBottom1 = anchor.shift(-135, w); + points.reactTop1Cp1 = points.reactTop1.shift(135, h); + points.reactTop1Cp2 = points.reactTop1.shift(-45, h); + points.reactBottom1Cp1 = points.reactBottom1.shift(135, h); + points.reactBottom1Cp2 = points.reactBottom1.shift(-45, h); + points.reactTop2 = points.reactTop1.rotate(60, anchor); + points.reactBottom2 = points.reactBottom1.rotate(60, anchor); + points.reactTop2Cp1 = points.reactTop1Cp1.rotate(60, anchor); + points.reactTop2Cp2 = points.reactTop1Cp2.rotate(60, anchor); + points.reactBottom2Cp1 = points.reactBottom1Cp1.rotate(60, anchor); + points.reactBottom2Cp2 = points.reactBottom1Cp2.rotate(60, anchor); + points.reactTop3 = points.reactTop1.rotate(-60, anchor); + points.reactBottom3 = points.reactBottom1.rotate(-60, anchor); + points.reactTop3Cp1 = points.reactTop1Cp1.rotate(-60, anchor); + points.reactTop3Cp2 = points.reactTop1Cp2.rotate(-60, anchor); + points.reactBottom3Cp1 = points.reactBottom1Cp1.rotate(-60, anchor); + points.reactBottom3Cp2 = points.reactBottom1Cp2.rotate(-60, anchor); + points.svgLogo = anchor + .clone() + .attr("data-circle", 1 * size) + .attr("data-circle-class", "fill-fabric"); + points.reactText = anchor + .clone() + .attr("data-text", "React") + .attr("data-text-class", "text-xl scribble"); + points.reactText.x += size * 7; + points.reactText.y += 6; + + paths.reactLogo = new Path() + .move(points.reactTop1) + .curve(points.reactTop1Cp1, points.reactBottom1Cp1, points.reactBottom1) + .curve(points.reactBottom1Cp2, points.reactTop1Cp2, points.reactTop1) + .close() + .move(points.reactTop2) + .curve(points.reactTop2Cp1, points.reactBottom2Cp1, points.reactBottom2) + .curve(points.reactBottom2Cp2, points.reactTop2Cp2, points.reactTop2) + .close() + .move(points.reactTop3) + .curve(points.reactTop3Cp1, points.reactBottom3Cp1, points.reactBottom3) + .curve(points.reactBottom3Cp2, points.reactTop3Cp2, points.reactTop3) + .close(); + }; + + // Other parts first so they're behind + drawBox("Part4", 4, -19, 40, 65, 5, false); + drawBox("Part3", 1, -16, 40, 65, 5, false); + drawBox("Part2", -2, -13, 40, 65, 5, false); + drawBox("Part", -5, -10, 40, 65, 5); + paths.Part4.attr("class", "fill-bg"); + paths.Part3.attr("class", "fill-bg"); + paths.Part2.attr("class", "fill-bg"); + paths.Part.attr("class", "fill-bg"); + points.PartMid.y = points.PartTopLeft.y + 9; + let x = 0; + let y = 0; + let w = 30; + let h = 15; + drawBox("Points", x, y, w, h); + y += 18; + drawBox("Paths", x, y, w, h); + y += 18; + drawBox("Snippets", x, y, w, h); + x = -35; + y = -15; + w = 25; + h = 20; + drawBox("config", x, y, w, h); + y += 23; + drawBox("utils", x, y, w, h); + y += 23; + drawBox("Store", x, y, w, h); + x = -40; + y = -30; + drawBox("Pattern", x, y, 90, 90); + points.PatternMid.y = points.PatternTopLeft.y + 9; + + drawBox("settings", -100, 6, 40, 20); + drawBox("draft", 80, 3, 20, 25); + + points.arrow1From = points.settingsTopRight.shiftFractionTowards( + points.settingsBottomRight, + 0.5 + ); + points.arrow1To = points.PatternTopLeft.shiftFractionTowards( + points.PatternBottomLeft, + 0.5 + ); + paths.arrow1 = arrow("arrow1"); + points.arrow2From = points.PatternTopRight.shiftFractionTowards( + points.PatternBottomRight, + 0.5 + ); + points.arrow2To = points.draftTopLeft.shiftFractionTowards( + points.draftBottomLeft, + 0.5 + ); + paths.arrow2 = arrow("arrow2", "draft()"); + + svgLogo(points.draftMid.shift(70, 50)); + reactLogo(points.draftMid.shift(-80, 36)); + + points.arrow3From = points.draftTopLeft.shiftFractionTowards( + points.draftTopRight, + 0.5 + ); + points.arrow3To = points.svgText.clone(); + paths.arrow3 = arrow("arrow3", "render()"); + points.arrow4From = points.draftBottomLeft.shiftFractionTowards( + points.draftBottomRight, + 0.5 + ); + points.arrow4To = points.reactText.clone().shift(40, 15); + paths.arrow4 = arrow("arrow4"); + + paths.extend = new Path() + .move(points.draftTopRight) + .line(points.draftTopRight.shift(0, 40)) + .attr("class", "hidden"); + + return part; +}; diff --git a/packages/examples/src/index.js b/packages/examples/src/index.js index 6a257b29c15..4839a57e367 100644 --- a/packages/examples/src/index.js +++ b/packages/examples/src/index.js @@ -65,6 +65,8 @@ import draftUtils_splitcurve from "./utils_splitcurve"; import draftSettings_sa from "./settings_sa"; import draftSnippet_attr from "./snippet_attr"; import draftSnippet_clone from "./snippet_clone"; +// Docs illustrations +import draftDocs_overview from "./docs_overview"; // Create design const Pattern = new freesewing.Design(config, plugins); @@ -135,7 +137,8 @@ let methods = { draftUtils_lineintersectscircle, draftUtils_curveintersectsx, draftUtils_curveintersectsy, - draftUtils_splitcurve + draftUtils_splitcurve, + draftDocs_overview }; for (let m of Object.keys(methods)) Pattern.prototype[m] = methods[m];