diff --git a/CHANGELOG.md b/CHANGELOG.md index d8ce771d605..105bacdba2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -685,6 +685,12 @@ ### yuri +#### Changed + + - Migrated from Rollup to Esbuild for all builds + +### examples + #### Changed - Migrated from Rollup to Esbuild for all builds @@ -1272,6 +1278,16 @@ ### yuri +#### Changed + + - Switched to default import for version from package.json + +### examples + +#### Added + + - Added plugin_gore example + #### Changed - Switched to default import for version from package.json @@ -2527,6 +2543,13 @@ - Added the (disabled) waistbandHeight option from Titan - Changed to Titan's waistbandWidth option +### examples + +#### Added + + - Added examples for bartack plugin + - Added examples for new buttonhole-start/end snippets + ### plugin-buttons #### Added @@ -4012,6 +4035,12 @@ ### wahid +#### Added + + - Initial release + +### examples + #### Added - Initial release diff --git a/config/dependencies.yaml b/config/dependencies.yaml index 20b7dd25f44..452e4aa2cc6 100644 --- a/config/dependencies.yaml +++ b/config/dependencies.yaml @@ -65,6 +65,10 @@ diana: peer: '@freesewing/brian': *freesewing '@freesewing/plugin-bust': *freesewing +examples: + peer: + '@freesewing/plugin-mirror': *freesewing + '@freesewing/plugin-gore': *freesewing holmes: _: '@freesewing/plugin-gore': *freesewing diff --git a/config/keywords.yaml b/config/keywords.yaml index 7b04674c8cf..f6b93f28536 100644 --- a/config/keywords.yaml +++ b/config/keywords.yaml @@ -24,6 +24,10 @@ design: - pattern - sewing - sewing pattern +examples: + - documentation + - example + - parametric design i18n: - i18n - internationalisation diff --git a/config/software/designs.json b/config/software/designs.json index d235ed76bb6..03ad76be50b 100644 --- a/config/software/designs.json +++ b/config/software/designs.json @@ -328,6 +328,10 @@ } }, "utilities": { + "examples": { + "description": "A FreeSewing pattern holding examples for our documentation", + "code": "Joost De Cock" + }, "legend": { "description": "A FreeSewing pattern to document pattern notation", "code": "Joost De Cock" diff --git a/designs/examples/.eslintrc.yml b/designs/examples/.eslintrc.yml new file mode 100644 index 00000000000..b39fd0463e8 --- /dev/null +++ b/designs/examples/.eslintrc.yml @@ -0,0 +1,18 @@ +env: + browser: true + es2021: true +extends: eslint:recommended +overrides: + - files: ["*.yaml", "*.yml"] + plugins: ["yaml"] + extends: ["plugin:yaml/recommended"] +parserOptions: + ecmaVersion: latest + sourceType: module +rules: {} +globals: + it: readonly + describe: readonly + process: readonly + __dirname: readonly + diff --git a/designs/examples/CHANGELOG.md b/designs/examples/CHANGELOG.md new file mode 100644 index 00000000000..0173d7207ac --- /dev/null +++ b/designs/examples/CHANGELOG.md @@ -0,0 +1,38 @@ +# Change log for: @freesewing/examples + + +## 2.21.0 (2022-06-27) + +### Changed + + - Migrated from Rollup to Esbuild for all builds + +## 2.20.0 (2022-01-24) + +### Added + + - Added plugin_gore example + +### Changed + + - Switched to default import for version from package.json + +## 2.15.0 (2021-04-15) + +### Added + + - Added examples for bartack plugin + - Added examples for new buttonhole-start/end snippets + +## 2.0.0 (2019-08-25) + +### Added + + - Initial release + + +This is the **initial release**, and the start of this change log. + +> Prior to version 2, FreeSewing was not a JavaScript project. +> As such, that history is out of scope for this change log. + diff --git a/designs/examples/README.md b/designs/examples/README.md new file mode 100644 index 00000000000..31fba58bc1f --- /dev/null +++ b/designs/examples/README.md @@ -0,0 +1,290 @@ +![FreeSewing](https://static.freesewing.org/banner.png) +

@freesewing/examples on NPM + License: MIT + Code quality on DeepScan + Open issues tagged pkg:examples + All Contributors +

Follow @freesewing_org on Twitter + Chat with us on Discord + Become a FreeSewing Patron + Follow @freesewing_org on Twitter +

+ +# @freesewing/examples + +A FreeSewing pattern holding examples for our documentation + + + + +> #### Note: Version 3 is a work in progress +> +> We are working on a new major version (v3) but it is not ready for prime-time. +> For production use, please refer to our v2 packages (the `latest` on NPM) +> or [the `v2` branch in our monorepo](https://github.com/freesewing/freesewing/tree/v2). + +## What am I looking at? πŸ€” + +This repository is our *monorepo* holding all our NPM designs, plugins, other NPM packages, and (web)sites. + +This folder holds: @freesewing/examples + +If you're not entirely sure what to do or how to start, type this command: + +``` +npm run tips +``` + +> If you don't want to set up a dev environment, you can run it in your browser: +> +> [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/freesewing/freesewing) +> +> We recommend that you fork our repository and then +> put `gitpod.io/# to start up a browser-based dev environment of your own. + +## About FreeSewing πŸ’€ + +Where the world of makers and developers collide, that's where you'll find FreeSewing. + +If you're a maker, checkout [freesewing.org](https://freesewing.org/) where you can generate +our sewing patterns adapted to your measurements. + +If you're a developer, our documentation is on [freesewing.dev](https://freesewing.dev/). +Our [core library](https://freesewing.dev/reference/api/) is a *batteries-included* toolbox +for parametric design of sewing patterns. But we also provide a range +of [plugins](https://freesewing.dev/reference/plugins/) that further extend the +functionality of the platform. + +If you have NodeJS installed, you can try it right now by running: + +```bash +npx create-freesewing-pattern +``` + +Or, consult our getting started guides +for [Linux](https://freesewing.dev/tutorials/getting-started-linux/), +[MacOS](https://freesewing.dev/tutorials/getting-started-mac/), +or [Windows](https://freesewing.dev/tutorials/getting-started-windows/). + +We also have a [pattern design tutorial](https://freesewing.dev/tutorials/pattern-design/) that +walks you through your first parametric design, +and [a friendly community](https://freesewing.org/community/where/) with +people who can help you when you get stuck. + +## Support FreeSewing: Become a patron πŸ₯° + +FreeSewing is an open source project run by a community, +and financially supported by our patrons. + +If you feel what we do is worthwhile, and you can spend a few coind without +hardship, then you should [join us and become a patron](https://freesewing.org/community/join). + +## Links πŸ‘©β€πŸ’» + + - πŸ’» Makers website: [freesewing.org](https://freesewing.org) + - πŸ’» Developers website: [freesewing.dev](https://freesewing.dev) + - πŸ’¬ Chat: On Discord via [discord.freesewing.org](https://discord.freesewing.org/) + - βœ… Todo list/Kanban board: On Github via [todo.freesewing.org](https://todo.freesewing.org/) + - 🐦 Twitter: [@freesewing_org](https://twitter.com/freesewing_org) + - πŸ“· Instagram: [@freesewing_org](https://instagram.com/freesewing_org) + +## License: MIT πŸ€“ + +Β© [Joost De Cock](https://github.com/joostdecock). +See [the license file](https://github.com/freesewing/freesewing/blob/develop/LICENSE) for details. + +## Where to get help 🀯 + +Our [chatrooms on Discord](https://chat.freesewing.org/) are the best place to ask questions, +share your feedback, or just hang out. + +If you want to report a problem, please [create an issue](https://github.com/freesewing/freesewing/issues/new). + + + +## Contributors ✨ + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Adam Tomkins

πŸ“–

Alexandre Ignjatovic

πŸ’»

AlfaLyr

πŸ’» πŸ”Œ 🎨

Andrew James

πŸ“–

Anneke

πŸ“– 🌍

Annie Kao

πŸ“–

Anternative

πŸ“–

Anthony

πŸ’¬

Ari Grayzel-student

πŸ’»

Bart

πŸ“–

BenJamesBen

πŸ’» πŸ“–

Cameron Dubas

πŸ“–

Carsten Biebricher

πŸ“–

Cathy Zoller

πŸ“–

Chantal Lapointe

🌍

Damien PIQUET

πŸ’»

Darigov Research

πŸ“– πŸ€”

Elena FdR

πŸ“– πŸ“

Emmanuel Nyachoke

πŸ’» πŸ“–

Enoch Riese

πŸ’»

EvEkSwed

🌍

Fantastik-Maman

🌍

Forrest O.

πŸ“–

FrΓ©dΓ©ric

🌍

Glenn Matthews

πŸ“–

Greg Sadetsky

πŸ“–

Igor Couto

πŸ›

Ikko Ashimine

πŸ“–

Irapeke

🌍

Jacek Sawoszczuk

πŸ“–

Jason Williams

πŸ“–

Jeremy Jackson

πŸ’»

Jeroen Hoek

πŸ“–

Joe Schofield

πŸ“–

Joebidido

🌍

Joost De Cock

🚧

Josh Essman

πŸ“–

Kake

πŸ“–

Kapunahele Wong

πŸ“–

Karen

πŸ“– πŸ“‹

Katie McGinley

πŸ“–

Kieran Klaassen

πŸ’»

Kittycatou

🌍

Kris

πŸ“–

Kristin Ruben

πŸ’»

Loudepeuter

🌍

Lucian

πŸ“‹

Marcus

🌍

Martin Tribo

πŸ“–

Nadege Michel

⚠️ πŸ“–

Natalia

πŸ’» 🎨 πŸ“

Nathan Yergler

πŸ“–

Nick Dower

πŸ“– πŸ’» πŸ›

Nikhil Chelliah

πŸ“–

OysteinHoiby

πŸ’»

Patrick Forringer

πŸ”Œ

Paul

πŸ“– πŸ“ 🌍

Phillip Thelen

πŸ’»

Pixieish

πŸ“–

Prof. dr. Sorcha NΓ­ Dhubhghaill

πŸ“–

Quentin FELIX

πŸ’» 🎨

Rik Hekker

πŸ›

Sam Livingston-Gray

πŸ“–

Sanne

πŸ’» πŸ“–

Sara Latorre

🌍

SeaZeeZee

πŸ“– πŸ’»

SimonbJohnson

πŸ›

Slylele

πŸ“– 🌍

Soazillon

🌍

SoneaTheBest

🌍

Stefan Sydow

🌍 πŸ“– πŸ’»

TrΓ­ona

πŸ“–

Unmutual

πŸ“–

Wouter van Wageningen

πŸ’» 🎨 πŸ”§

amysews

πŸ“–

anna-puk

πŸ’»

beautifulsummermoon

🌍

berce

πŸ“–

biou

πŸ’»

bobgeorgethe3rd

πŸ’» πŸ“– 🎨

brmlyklr

πŸ“–

chri5b

πŸ’» ⚠️

dingcycle

🌍

drowned-in-books

πŸ’¬

econo202

πŸ“–

ericamattos

🌍

fightingrabbit

πŸ’»

gaylyndie

πŸ“–

grimlokason

πŸ’»

hellgy

🎨

jackseye

πŸ“–

marckiesel

🌍

mesil

πŸ›

starfetch

πŸ’» πŸ“– 🌍 🎨

ttimearl

πŸ–‹

tuesgloomsday

πŸ“–

valadaptive

πŸ’»

viocky

🌍

woolishboy

πŸ’»

yc

🌍
+ + + + + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! + diff --git a/designs/examples/build.mjs b/designs/examples/build.mjs new file mode 100644 index 00000000000..aa4dfabb290 --- /dev/null +++ b/designs/examples/build.mjs @@ -0,0 +1,36 @@ +/* This script will build the package with esbuild */ +import esbuild from 'esbuild' +import pkg from './package.json' assert { type: 'json' } + +// Create banner based on package info +const banner = `/** + * ${pkg.name} | v${pkg.version} + * ${pkg.description} + * (c) ${new Date().getFullYear()} ${pkg.author} + * @license ${pkg.license} + */` + +// Shared esbuild options +const options = { + banner: { js: banner }, + bundle: true, + entryPoints: ['src/index.mjs'], + format: 'esm', + outfile: 'dist/index.mjs', + external: ["@freesewing"], + metafile: process.env.VERBOSE ? true : false, + minify: process.env.NO_MINIFY ? false : true, + sourcemap: true, +} + +// Let esbuild generate the build +let result +(async () => { + result = await esbuild.build(options).catch(() => process.exit(1)) + + if (process.env.VERBOSE) { + const info = await esbuild.analyzeMetafile(result.metafile) + console.log(info) + } + +})() diff --git a/designs/examples/config/index.js b/designs/examples/config/index.js new file mode 100644 index 00000000000..c7219e59e22 --- /dev/null +++ b/designs/examples/config/index.js @@ -0,0 +1,122 @@ +import pkg from '../package.json' assert { type: 'json' } + +const { version } = pkg + +export default { + version, + name: 'examples', + design: 'Joost De Cock', + code: 'Joost De Cock', + department: 'womenswear', + type: 'pattern', + difficulty: 1, + tags: ['example'], + optionGroups: { + fit: ['fixme'], + }, + measurements: [], + dependencies: { + //point_attr: 'path_attr' + }, + parts: [ + 'point_attr', + 'path_move', + 'path_line', + 'path_curve', + 'path__curve', + 'path_curve_', + 'path_close', + 'path_ops', + 'path_attr', + 'path_clone', + 'path_divide', + 'path_edge', + 'path_end', + 'path_intersects', + 'path_intersectsx', + 'path_intersectsy', + 'path_join', + 'path_length', + 'path_noop', + 'path_offset', + 'path_reverse', + 'path_shiftalong', + 'path_shiftfractionalong', + 'path_split', + 'path_start', + 'path_translate', + 'path_trim', + 'plugin_banner', + 'plugin_bartack', + 'plugin_bartackalong', + 'plugin_bartackfractionalong', + 'plugin_buttons', + 'plugin_cutonfold', + 'plugin_dimension', + 'plugin_gore', + 'plugin_grainline', + 'plugin_logo', + 'plugin_mirror', + 'plugin_notches', + 'plugin_round', + 'plugin_scalebox', + 'plugin_sprinkle', + 'plugin_title', + 'point_angle', + 'point_attr', + 'point_clone', + 'point_copy', + 'point_dist', + 'point_dx', + 'point_dy', + 'point_flipx', + 'point_flipy', + 'point_shift', + 'point_shiftfractiontowards', + 'point_shifttowards', + 'point_shiftoutwards', + 'point_sitson', + 'point_sitsroughlyon', + 'point_rotate', + 'point_translate', + 'settings_sa', + 'snippet', + 'snippet_attr', + 'snippet_clone', + 'snippets_bnotch', + 'snippets_notch', + 'snippets_button', + 'snippets_buttonhole', + 'snippets_buttonhole_start', + 'snippets_buttonhole_end', + 'snippets_snapsocket', + 'snippets_snapstud', + 'snippets_logo', + 'utils_linesintersect', + 'utils_beamsintersect', + 'utils_beamintersectsx', + 'utils_beamintersectsy', + 'utils_lineintersectscurve', + 'utils_curvesintersect', + 'utils_pointonbeam', + 'utils_pointonline', + 'utils_pointoncurve', + 'utils_circlesintersect', + 'utils_beamintersectscircle', + 'utils_lineintersectscircle', + 'utils_curveintersectsy', + 'utils_curveintersectsx', + 'utils_splitcurve', + 'docs_overview', + 'docs_coords', + ], + options: { + focus: '', + // Optiongroups are needed for now, because workbench + fixme: { + pct: 50, + min: 0, + max: 100, + }, + }, +} diff --git a/designs/examples/data.mjs b/designs/examples/data.mjs new file mode 100644 index 00000000000..0617f3ee8e5 --- /dev/null +++ b/designs/examples/data.mjs @@ -0,0 +1,4 @@ +// This file is auto-generated | All changes you make will be overwritten. +export const name = "@freesewing/examples" +export const version = "3.0.0-alpha.0" +export const data = { name, version } diff --git a/designs/examples/package.json b/designs/examples/package.json new file mode 100644 index 00000000000..63b468a69e4 --- /dev/null +++ b/designs/examples/package.json @@ -0,0 +1,65 @@ +{ + "name": "@freesewing/examples", + "version": "3.0.0-alpha.0", + "description": "A FreeSewing pattern holding examples for our documentation", + "author": "Joost De Cock (https://github.com/joostdecock)", + "homepage": "https://freesewing.org/", + "repository": "github:freesewing/freesewing", + "license": "MIT", + "bugs": { + "url": "https://github.com/freesewing/freesewing/issues" + }, + "funding": { + "type": "individual", + "url": "https://freesewing.org/patrons/join" + }, + "keywords": [ + "freesewing", + "documentation", + "example", + "parametric design" + ], + "type": "module", + "module": "dist/index.mjs", + "exports": { + ".": "./dist/index.mjs" + }, + "scripts": { + "build": "node build.mjs", + "clean": "rimraf dist", + "mbuild": "NO_MINIFY=1 node build.mjs", + "symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -", + "test": "npx mocha tests/*.test.mjs", + "vbuild": "VERBOSE=1 node build.mjs", + "lab": "cd ../../sites/lab && yarn start", + "tips": "node ../../scripts/help.mjs", + "lint": "npx eslint 'src/**' 'tests/*.mjs'", + "prettier": "npx prettier --write 'src/*.mjs' 'tests/*.mjs'", + "testci": "npx mocha tests/*.test.mjs --reporter ../../tests/reporters/terse.js", + "cibuild_step5": "node build.mjs" + }, + "peerDependencies": { + "@freesewing/core": "^3.0.0-alpha.0", + "@freesewing/plugin-bundle": "^3.0.0-alpha.0", + "@freesewing/config-helpers": "^3.0.0-alpha.0", + "@freesewing/plugin-mirror": "^3.0.0-alpha.0", + "@freesewing/plugin-gore": "^3.0.0-alpha.0" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "^10.0.0", + "chai": "^4.2.0" + }, + "files": [ + "dist/*", + "README.md" + ], + "publishConfig": { + "access": "public", + "tag": "next" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8" + } +} diff --git a/designs/examples/src/docs.mjs b/designs/examples/src/docs.mjs new file mode 100644 index 00000000000..e00000a3d42 --- /dev/null +++ b/designs/examples/src/docs.mjs @@ -0,0 +1,321 @@ +import { box } from './shared.mjs' + +export const docs_coords = { + name: 'examples.box_coords', + draft: ({ Point, points, paths, Path, part }) => { + points.origin = new Point(10, 10) + points.x = new Point(100, 10) + points.y = new Point(10, 50) + points.textX = points.x.shift(135, 2).attr('data-text', 'X') + points.textY = points.y.shift(180, 5).attr('data-text', 'Y') + paths.coords = new Path() + .move(points.y) + .line(points.origin) + .line(points.x) + .attr('class', 'mark') + .attr('marker-start', 'url(#dimensionFrom)') + .attr('marker-end', 'url(#dimensionTo)') + + return box(part, 100, 50) + }, +} + +export const docs_overview = { + name: 'examples.docs_overview', + draft: ({ Point, points, Path, paths, options, part }) => { + /** + * 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', options.focus === name ? 'note' : '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 (options.focus === name) path = path.attr('class', 'note') + if (text) + return path + .attr('data-text', ' ' + text) + .attr('data-text-class', 'scribble') + .attr('data-text-class', options.focus === name ? 'fill-note' : '') + 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') + if (options.focus === name) points[name + 'Mid'].attr('data-text-class', 'fill-note') + } + } + + 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 = -3 + w = 25 + h = 20 + drawBox('config', 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/designs/examples/src/index.mjs b/designs/examples/src/index.mjs new file mode 100644 index 00000000000..73e2d676f09 --- /dev/null +++ b/designs/examples/src/index.mjs @@ -0,0 +1,387 @@ +import { Design } from '@freesewing/core' +import { pluginBundle } from '@freesewing/plugin-bundle' +import { gorePlugin } from '@freesewing/plugin-gore' +import { data } from '../data.mjs' + +// Path API +import { + path__curve, + path_addclass, + path_addtext, + path_attr, + path_move, + path_line, + path_curve, + path_curve_, + path_close, + path_ops, + path_clone, + path_divide, + path_edge, + path_end, + path_intersects, + path_intersectsx, + path_intersectsy, + path_join, + path_length, + path_noop, + path_offset, + path_reverse, + path_shiftalong, + path_shiftfractionalong, + path_smurve, + path_smurve_, + path_split, + path_start, + path_translate, + path_trim, +} from './path.mjs' + +// Point API +import { + point_addcircle, + point_addtext, + point_angle, + point_attr, + point_clone, + point_copy, + point_dist, + point_dx, + point_dy, + point_flipx, + point_flipy, + point_setcircle, + point_settext, + point_shift, + point_shiftfractiontowards, + point_shifttowards, + point_shiftoutwards, + point_sitson, + point_sitsroughlyon, + point_rotate, + point_translate, +} from './point.mjs' + +// Snippet API +import { snippet, snippet_attr, snippet_clone } from './snippet.mjs' + +// Utils API +import { + utils_linesintersect, + utils_beamsintersect, + utils_beamintersectsx, + utils_beamintersectsy, + utils_lineintersectscurve, + utils_curvesintersect, + utils_pointonbeam, + utils_pointonline, + utils_pointoncurve, + utils_circlesintersect, + utils_beamintersectscircle, + utils_lineintersectscircle, + utils_curveintersectsx, + utils_curveintersectsy, + utils_splitcurve, +} from './utils.mjs' + +// Plugins +import { + plugin_banner, + plugin_bartack, + plugin_bartackalong, + plugin_bartackfractionalong, + plugin_buttons, + plugin_cutonfold, + plugin_dimension, + plugin_gore, + plugin_grainline, + plugin_logo, + plugin_mirror, + plugin_notches, + plugin_round, + plugin_sprinkle, + plugin_scalebox, + plugin_title, +} from './plugins.mjs' + +// Snippets +import { + snippet_bnotch, + snippet_notch, + snippet_button, + snippet_buttonhole, + snippet_buttonholestart, + snippet_buttonholeend, + snippet_snapsocket, + snippet_snapstud, + snippet_logo, +} from './snippets.mjs' + +// Stacks +import { + stacks_top, + stacks_left, + stacks_right, + stacks_bottom, + stacks_leftEye, + stacks_rightEye, + stacks_mouth, +} from './stacks.mjs' + +// Settings +import { settings_sa } from './settings.mjs' + +// Docs illustrations +import { docs_coords, docs_overview } from './docs.mjs' + +// Setup our new design +const Examples = new Design({ + data, + parts: [ + // Path API + path__curve, + path_addclass, + path_addtext, + path_attr, + path_move, + path_line, + path_curve, + path_curve_, + path_close, + path_ops, + path_clone, + path_divide, + path_edge, + path_end, + path_intersects, + path_intersectsx, + path_intersectsy, + path_join, + path_length, + path_noop, + path_offset, + path_reverse, + path_shiftalong, + path_shiftfractionalong, + path_smurve, + path_smurve_, + path_split, + path_start, + path_translate, + path_trim, + + // Point API + point_addcircle, + point_addtext, + point_angle, + point_attr, + point_clone, + point_copy, + point_dist, + point_dx, + point_dy, + point_flipx, + point_flipy, + point_setcircle, + point_settext, + point_shift, + point_shiftfractiontowards, + point_shifttowards, + point_shiftoutwards, + point_sitson, + point_sitsroughlyon, + point_rotate, + point_translate, + + // Snippet API + snippet, + snippet_attr, + snippet_clone, + + // Utils API + utils_linesintersect, + utils_beamsintersect, + utils_beamintersectsx, + utils_beamintersectsy, + utils_lineintersectscurve, + utils_curvesintersect, + utils_pointonbeam, + utils_pointonline, + utils_pointoncurve, + utils_circlesintersect, + utils_beamintersectscircle, + utils_lineintersectscircle, + utils_curveintersectsx, + utils_curveintersectsy, + utils_splitcurve, + + // Plugins + plugin_banner, + plugin_bartack, + plugin_bartackalong, + plugin_bartackfractionalong, + plugin_buttons, + plugin_cutonfold, + plugin_dimension, + plugin_gore, + plugin_grainline, + plugin_logo, + plugin_mirror, + plugin_notches, + plugin_round, + plugin_sprinkle, + plugin_scalebox, + plugin_title, + + // Snippets + snippet_bnotch, + snippet_notch, + snippet_button, + snippet_buttonhole, + snippet_buttonholestart, + snippet_buttonholeend, + snippet_snapsocket, + snippet_snapstud, + snippet_logo, + + // Stacks + stacks_top, + stacks_left, + stacks_right, + stacks_bottom, + stacks_leftEye, + stacks_rightEye, + stacks_mouth, + + // Settings + settings_sa, + + // Docs + docs_coords, + docs_overview, + ], + plugins: [pluginBundle, gorePlugin], +}) + +// Named exports +export { + // Path API + path__curve, + path_addclass, + path_addtext, + path_attr, + path_move, + path_line, + path_curve, + path_curve_, + path_close, + path_ops, + path_clone, + path_divide, + path_edge, + path_end, + path_intersects, + path_intersectsx, + path_intersectsy, + path_join, + path_length, + path_noop, + path_offset, + path_reverse, + path_shiftalong, + path_shiftfractionalong, + path_smurve, + path_smurve_, + path_split, + path_start, + path_translate, + path_trim, + + // Point API + point_addcircle, + point_addtext, + point_angle, + point_attr, + point_clone, + point_copy, + point_dist, + point_dx, + point_dy, + point_flipx, + point_flipy, + point_setcircle, + point_settext, + point_shift, + point_shiftfractiontowards, + point_shifttowards, + point_shiftoutwards, + point_sitson, + point_sitsroughlyon, + point_rotate, + point_translate, + + // Snippet API + snippet, + snippet_attr, + snippet_clone, + + // Utils API + utils_linesintersect, + utils_beamsintersect, + utils_beamintersectsx, + utils_beamintersectsy, + utils_lineintersectscurve, + utils_curvesintersect, + utils_pointonbeam, + utils_pointonline, + utils_pointoncurve, + utils_circlesintersect, + utils_beamintersectscircle, + utils_lineintersectscircle, + utils_curveintersectsx, + utils_curveintersectsy, + utils_splitcurve, + + // Plugins + plugin_banner, + plugin_bartack, + plugin_bartackalong, + plugin_bartackfractionalong, + plugin_buttons, + plugin_cutonfold, + plugin_dimension, + plugin_gore, + plugin_grainline, + plugin_logo, + plugin_mirror, + plugin_notches, + plugin_round, + plugin_sprinkle, + plugin_scalebox, + plugin_title, + + // Snippets + snippet_bnotch, + snippet_notch, + snippet_button, + snippet_buttonhole, + snippet_buttonholestart, + snippet_buttonholeend, + snippet_snapsocket, + snippet_snapstud, + snippet_logo, + + // Stacks + stacks_top, + stacks_left, + stacks_right, + stacks_bottom, + stacks_leftEye, + stacks_rightEye, + stacks_mouth, + + // Docs + docs_coords, + docs_overview, + Examples, +} diff --git a/designs/examples/src/path.mjs b/designs/examples/src/path.mjs new file mode 100644 index 00000000000..d3ce4366009 --- /dev/null +++ b/designs/examples/src/path.mjs @@ -0,0 +1,752 @@ +import { box } from './shared.mjs' + +export const path__curve = { + name: 'examples.path__curve', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(5, 20) + points.cp2 = new Point(60, 30) + points.to = new Point(90, 20) + + paths.line = new Path() + .move(points.from) + ._curve(points.cp2, points.to) + .attr('data-text', 'Path._curve()') + .attr('data-text-class', 'text-sm center fill-note') + + return box(part, 100, 25) + }, +} + +export const path_addclass = { + name: 'examples.path_addclass', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(5, 10) + points.to = new Point(95, 10) + + paths.line = new Path().move(points.from).line(points.to).addClass('note dashed') + + return box(part, 100, 20) + }, +} + +export const path_addtext = { + name: 'examples.path_addtext', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(5, 10) + points.to = new Point(95, 10) + + paths.line = new Path().move(points.from).line(points.to).addText('FreeSewing rocks') + + return box(part, 100, 20) + }, +} + +export const path_attr = { + name: 'examples.path_attr', + draft: ({ Point, points, Path, paths, part }) => { + points.B = new Point(10, 50) + points.BCp2 = new Point(40, 10) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, 90) + + paths.example = new Path() + .move(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .attr('class', 'canvas') + .attr('data-text', 'supportFreesewingBecomeAPatron') + .attr('data-text-class', 'text-xs center') + + return part + }, +} + +export const path_clone = { + name: 'examples.path_clone', + draft: ({ Point, points, Path, paths, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.example = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + + paths.clone = paths.example + .clone() + .setClass('note lashed stroke-xl') + .attr('style', 'stroke-opacity: 0.5') + + return part + }, +} + +export const path_close = { + name: 'examples.path_close', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 20) + points.cp2 = new Point(60, 30) + points.to = new Point(90, 20) + + paths.line = new Path() + .move(points.from) + ._curve(points.cp2, points.to) + .close() + .reverse() // To keep text from being upside-down + .setText('Path._close()', 'text-sm right fill-note') + + return box(part, 100, 25) + }, +} + +export const path_curve = { + name: 'examples.path_curve', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 20) + points.cp1 = new Point(40, 0) + points.cp2 = new Point(60, 30) + points.to = new Point(90, 20) + + paths.line = new Path() + .move(points.from) + .curve(points.cp1, points.cp2, points.to) + .setText('Path.curve()', 'text-sm center fill-note') + + return box(part, 100, 25) + }, +} + +export const path_curve_ = { + name: 'examples.path_curve_', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 20) + points.cp1 = new Point(40, 0) + points.to = new Point(90, 20) + + paths.line = new Path() + .move(points.from) + .curve_(points.cp1, points.to) + .attr('data-text', 'Path.curve_()') + .attr('data-text-class', 'text-sm center fill-note') + + return box(part, 100, 25) + }, +} + +export const path_divide = { + name: 'examples.path_divide', + draft: ({ Point, points, Path, paths, part }) => { + points.A = new Point(55, 40) + points.B = new Point(10, 70) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 60) + points.CCp1 = new Point(50, -30) + points.D = new Point(50, 80) + points.DCp1 = new Point(140, 50) + + paths.example = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .curve(points.DCp1, points.DCp1, points.D) + .close() + + let style = 'stroke-width: 4; stroke-opacity: 0.5;' + let i = 0 + for (let p of paths.example.divide()) { + i++ + paths[i] = p.attr('style', style).attr('style', `stroke: hsl(${i * 70}, 100%, 50%)`) + } + + return part + }, +} + +export const path_edge = { + name: 'examples.path_edge', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + points.D = new Point(-60, 90) + points.E = new Point(90, 190) + + paths.demo = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .curve(points.E, points.D, points.A) + .close() + + for (let i of [ + 'topLeft', + 'topRight', + 'bottomLeft', + 'bottomRight', + 'top', + 'left', + 'bottom', + 'right', + ]) + snippets[i] = new Snippet('notch', paths.demo.edge(i)) + + return part + }, +} + +export const path_end = { + name: 'examples.path_end', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.demo = new Path().move(points.A).line(points.B).curve(points.BCp2, points.CCp1, points.C) + + snippets.end = new Snippet('notch', paths.demo.end()) + + return part + }, +} + +export const path_intersects = { + name: 'examples.path_intersects', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + points.D = new Point(50, 130) + points.DCp1 = new Point(150, 30) + + points._A = new Point(55, 40) + points._B = new Point(0, 55) + points._BCp2 = new Point(40, -20) + points._C = new Point(90, 40) + points._CCp1 = new Point(50, -30) + points._D = new Point(40, 120) + points._DCp1 = new Point(180, 40) + + paths.demo1 = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .curve(points.DCp1, points.DCp1, points.D) + paths.demo2 = new Path() + .move(points._A) + .line(points._B) + .curve(points._BCp2, points._CCp1, points._C) + .curve(points._DCp1, points._DCp1, points._D) + + for (let p of paths.demo1.intersects(paths.demo2)) { + snippets[part.getId()] = new Snippet('notch', p) + } + + return part + }, +} + +export const path_intersectsx = { + name: 'examples.path_intersectsx', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(95, 50) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + points.D = new Point(50, 130) + points.DCp1 = new Point(150, 30) + + points.top = new Point(60, -10) + points.bot = new Point(60, 140) + + paths.line = new Path().move(points.top).line(points.bot).attr('class', 'lining dashed') + + paths.demo = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .curve(points.DCp1, points.DCp1, points.D) + + for (let p of paths.demo.intersectsX(60)) { + snippets[part.getId()] = new Snippet('notch', p) + } + + return part + }, +} + +export const path_intersectsy = { + name: 'examples.path_intersectsy', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(55, 40) + points.B = new Point(10, 70) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 60) + points.CCp1 = new Point(50, -30) + points.D = new Point(50, 80) + points.DCp1 = new Point(140, 50) + + points.top = new Point(10, 58) + points.bot = new Point(130, 58) + + paths.line = new Path().move(points.top).line(points.bot).attr('class', 'lining dashed') + + paths.demo = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .curve(points.DCp1, points.DCp1, points.D) + for (let p of paths.demo.intersectsY(58)) { + snippets[part.getId()] = new Snippet('notch', p) + } + + return part + }, +} + +export const path_join = { + name: 'examples.path_join', + draft: ({ Point, points, Path, paths, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.path1 = new Path().move(points.A).line(points.B).attr('class', 'various') + + paths.path2 = new Path() + .move(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .attr('class', 'canvas') + + paths.joint = paths.path1 + .join(paths.path2) + .attr('class', 'note lashed stroke-l') + .attr('style', 'stroke-opacity: 0.5') + + return part + }, +} + +export const path_length = { + name: 'examples.path_length', + draft: ({ Point, points, Path, paths, macro, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.example = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + + macro('pd', { + path: paths.example, + d: -20, + }) + + macro('pd', { + path: new Path().move(points.B).line(points.A), + d: 10, + }) + + macro('pd', { + path: new Path().move(points.B).curve(points.BCp2, points.CCp1, points.C), + d: -10, + }) + + return part + }, +} + +export const path_line = { + name: 'examples.path_line', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 10) + points.to = new Point(90, 10) + + paths.line = new Path() + .move(points.from) + .line(points.to) + .attr('data-text', 'Path.line()') + .attr('data-text-class', 'text-sm center fill-note') + + return box(part, 100, 15) + }, +} + +export const path_move = { + name: 'examples.path_move', + draft: ({ Point, points, Path, paths, part }) => { + points.to = new Point(50, 10) + .attr('data-text', 'Path.move()') + .attr('data-text-class', 'fill-note center') + + paths.noline = new Path().move(points.to) + + return box(part, 100, 15) + }, +} + +export const path_noop = { + name: 'examples.path_noop', + draft: ({ Point, points, Path, paths, part }) => { + points.left = new Point(10, 10) + points.dartLeft = new Point(40, 10) + points.dartTip = new Point(50, 50) + points.dartRight = new Point(60, 10) + points.right = new Point(90, 10) + + paths.without = new Path() + .move(points.left) + .line(points.dartLeft) + .noop('dart') + .line(points.right) + + paths.withDart = paths.without + .insop('dart', new Path().line(points.dartTip).line(points.dartRight)) + .attr('style', 'stroke-width: 2px; stroke-opacity: 0.5; stroke: orange;') + + return part + }, +} + +export const path_offset = { + name: 'examples.path_offset', + draft: ({ Point, points, Path, paths, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.example = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .line(points.A) + .close() + + paths.offset = paths.example.offset(-10).attr('class', 'interfacing') + + paths.lineOffset = new Path().move(points.A).line(points.B).offset(-5).attr('class', 'various') + + paths.curveOffset = new Path() + .move(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .offset(-5) + .attr('class', 'canvas') + + return part + }, +} + +export const path_ops = { + name: 'examples.path_ops', + draft: ({ Point, points, Path, paths, options, part }) => { + const textClasses = (label) => + options.focus === label ? 'center text-xs fill-note' : 'center text-xs' + + points.A = new Point(10, 10) + .attr('data-text', 'Path.move()') + .attr('data-text-class', textClasses('move')) + points.B = new Point(70, 30) + points.BCp2 = new Point(40, 10) + points.C = new Point(90, -50) + points.CCp1 = new Point(125, -30) + points.D = new Point(20, -50) + points.DCp = new Point(40, 0) + points.E = new Point(-20, -20) + points.ECp = new Point(-20, -50) + + paths.line = new Path() + .move(points.A) + .line(points.B) + .attr('data-text', 'Path.line()') + .attr('data-text-class', textClasses('line')) + + paths.curve = new Path() + .move(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .attr('data-text', 'Path.curve()') + .attr('data-text-class', textClasses('curve')) + + paths._curve = new Path() + .move(points.C) + ._curve(points.DCp, points.D) + .attr('data-text', 'Path._curve()') + .attr('data-text-class', textClasses('_curve')) + + paths.curve_ = new Path() + .move(points.D) + .curve_(points.ECp, points.E) + .attr('data-text', 'Path.curve_()') + .attr('data-text-class', textClasses('curve_')) + + paths.close = new Path() + .move(points.E) + .line(points.A) + .attr('data-text', 'Path.close()') + .attr('data-text-class', textClasses('close')) + + paths.example = paths.line.join(paths.curve).join(paths._curve).join(paths.curve_).close() + + return part + }, +} + +export const path_reverse = { + name: 'examples.path_reverse', + draft: ({ Point, points, Path, paths, part }) => { + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.example = new Path() + .move(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .attr('data-text', 'freesewingIsMadeByJoostDeCockAndContributors') + .attr('data-text-class', 'text-xs fill-note') + + paths.reverse = paths.example + .reverse() + .attr('data-text', 'freesewingIsMadeByJoostDeCockAndContributors') + .attr('data-text-class', 'text-xs fill-lining') + + return part + }, +} + +export const path_shiftalong = { + name: 'examples.path_shiftalong', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.example = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + + points.x1 = paths.example + .shiftAlong(20) + .attr('data-text', '2cm') + .attr('data-text-class', 'center fill-note') + .attr('data-text-lineheight', 6) + points.x2 = paths.example + .shiftAlong(90) + .attr('data-text', '9cm') + .attr('data-text-class', 'center fill-note') + .attr('data-text-lineheight', 6) + + snippets.x1 = new Snippet('notch', points.x1) + snippets.x2 = new Snippet('notch', points.x2) + + return part + }, +} + +export const path_shiftfractionalong = { + name: 'examples.path_shiftfractionalong', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.example = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + + points.x1 = paths.example + .shiftFractionAlong(0.2) + .attr('data-text', '20%') + .attr('data-text-class', 'center fill-note') + .attr('data-text-lineheight', 6) + points.x2 = paths.example + .shiftFractionAlong(0.9) + .attr('data-text', '90%') + .attr('data-text-class', 'center fill-note') + .attr('data-text-lineheight', 6) + + snippets.xl = new Snippet('notch', points.x1) + snippets.x2 = new Snippet('notch', points.x2) + + return part + }, +} + +export const path_smurve = { + name: 'examples.path_smurve', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 20) + points.cp1 = new Point(40, 10) + points.cp2 = new Point(60, 30) + points.to = new Point(90, 20) + points.scp2 = new Point(140, 30) + points.sto = new Point(170, 20) + + paths.line = new Path() + .move(points.from) + .curve(points.cp1, points.cp2, points.to) + .smurve(points.scp2, points.sto) + .attr('data-text', 'Path.smurve()') + .attr('data-text-class', 'text-sm center fill-note') + + return box(part, 180, 40) + }, +} + +export const path_smurve_ = { + name: 'examples.path_smurve_', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 20) + points.cp1 = new Point(40, 10) + points.cp2 = new Point(60, 30) + points.to = new Point(90, 20) + points.sto = new Point(170, 20) + + paths.line = new Path() + .move(points.from) + .curve(points.cp1, points.cp2, points.to) + .smurve_(points.sto) + .attr('data-text', 'Path.smurve_()') + .attr('data-text-class', 'text-sm center fill-note') + + return box(part, 180, 40) + }, +} + +export const path_split = { + name: 'examples.path_split', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + points.D = new Point(50, 130) + points.DCp1 = new Point(150, 30) + + paths.demo = new Path() + .move(points.D) + .curve(points.DCp1, points.DCp1, points.C) + .curve(points.CCp1, points.BCp2, points.B) + .line(points.A) + + points.split = paths.demo.shiftFractionAlong(0.75) + snippets.x = new Snippet('x', points.split) + + let style = 'stroke-width: 3; stroke-opacity: 0.5;' + let halves = paths.demo.split(points.split) + for (let i in halves) { + paths[i] = halves[i].attr('style', style).attr('style', `stroke: hsl(${i * 70}, 100%, 50%)`) + } + + return part + }, +} + +export const path_start = { + name: 'examples.path_start', + draft: ({ Point, points, Path, paths, Snippet, snippets, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.example = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + + snippets.start = new Snippet('notch', paths.example.start()) + return part + }, +} + +export const path_translate = { + name: 'examples.path_translate', + draft: ({ Point, points, Path, paths, macro, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.A = new Path().move(points.A).line(points.B).curve(points.BCp2, points.CCp1, points.C) + + paths.B = paths.A.translate(60, 30) + + points.step1 = points.B.shift(0, 60) + points.step2 = points.step1.shift(-90, 30) + macro('ld', { + from: points.B, + to: points.step1, + noStartMarker: true, + }) + macro('ld', { + from: points.step1, + to: points.step2, + noStartMarker: true, + }) + + return part + }, +} + +export const path_trim = { + name: 'examples.path_trim', + draft: ({ Point, points, Path, paths, part }) => { + points.center = new Point(0, 0) + points.base = new Point(0, 10) + points.tip = new Point(0, 50) + points.tipCpRight = new Point(30, 50) + points.tipCpLeft = new Point(-30, 50) + paths.example = new Path().move(points.base) + for (let i = 0; i < 4; i++) { + points['base' + i] = points.base.rotate(60 * i, points.center) + points['tip' + i] = points.tip.rotate(60 * i, points.center) + points['tipCpRight' + i] = points.tipCpRight.rotate(60 * i, points.center) + points['tipCpLeft' + i] = points.tipCpLeft.rotate(60 * i, points.center) + if (i < 2) { + paths.example + .line(points['base' + i]) + .curve(points['base' + i], points['tipCpLeft' + i], points['tip' + i]) + .curve(points['tipCpRight' + i], points['base' + i], points['base' + i]) + } else { + paths.example + .line(points['base' + i]) + .line(points['tip' + i]) + .line(points['tipCpRight' + i]) + .line(points['base' + i]) + } + } + + paths.offset = paths.example.offset(10).attr('class', 'lining dotted stroke-sm') + + paths.trimmed = paths.offset + .trim() + .attr('class', 'various stroke-xl') + .attr('style', 'stroke-opacity: 0.5;') + return part + }, +} diff --git a/designs/examples/src/plugins.mjs b/designs/examples/src/plugins.mjs new file mode 100644 index 00000000000..e8f436e8f94 --- /dev/null +++ b/designs/examples/src/plugins.mjs @@ -0,0 +1,342 @@ +import { box } from './shared.mjs' + +export const plugin_banner = { + name: 'examples.plugin_banner', + draft: ({ points, Point, paths, Path, macro, part }) => { + points.from = new Point(0, 0) + points.to = new Point(320, 0) + + paths.banner = new Path().move(points.from).line(points.to) + + macro('banner', { + path: paths.banner, + text: 'banner plugin', + }) + + // Prevent clipping of text + paths.box = new Path().move(new Point(0, -20)).line(new Point(0, 20)).attr('class', 'hidden') + + return part + }, +} + +export const plugin_bartack = { + name: 'examples.plugin_bartack', + draft: ({ Point, points, macro, part }) => { + points.a = new Point(15, 15) + + macro('bartack', { + anchor: points.a, + angle: 30, + length: 15, + }) + + return box(part, 60, 30) + }, +} + +export const plugin_bartackalong = { + name: 'examples.plugin_bartackalong', + draft: ({ Point, Path, points, paths, macro, part }) => { + points.a = new Point(15, 15) + points.b = new Point(20, 20) + points.c = new Point(30, 20) + points.d = new Point(35, 15) + points.e = new Point(20, 10) + points.f = new Point(30, 10) + + paths.a = new Path().move(points.a).curve(points.b, points.c, points.d).hide() + + macro('bartackAlong', { + path: paths.a, + }) + + macro('sprinkle', { + snippet: 'notch', + on: ['e', 'f'], + }) + + return box(part, 60, 30) + }, +} + +export const plugin_bartackfractionalong = { + name: 'examples.plugin_bartackfractionalong', + draft: ({ Point, Path, points, paths, macro, part }) => { + points.a = new Point(15, 15) + points.b = new Point(20, 20) + points.c = new Point(30, 20) + points.d = new Point(35, 15) + points.e = new Point(20, 10) + points.f = new Point(30, 10) + + paths.a = new Path().move(points.a).curve(points.b, points.c, points.d).hide() + + macro('bartackFractionAlong', { + path: paths.a, + start: 0.2, + end: 0.8, + }) + + macro('sprinkle', { + snippet: 'notch', + on: ['e', 'f'], + }) + + return box(part, 60, 30) + }, +} + +export const plugin_buttons = { + name: 'examples.plugin_buttons', + draft: ({ Point, snippets, Snippet, part }) => { + snippets.button = new Snippet('button', new Point(20, 10)) + snippets.buttonhole = new Snippet('buttonhole', new Point(40, 10)) + snippets.buttonholeStart = new Snippet('buttonhole-start', new Point(60, 10)) + snippets.buttonholeEnd = new Snippet('buttonhole-end', new Point(80, 10)) + snippets.snapMale = new Snippet('snap-stud', new Point(100, 10)) + snippets.snapFemale = new Snippet('snap-socket', new Point(120, 10)) + + return box(part, 140, 20) + }, +} + +export const plugin_cutonfold = { + name: 'examples.plugin_cutonfold', + draft: ({ Point, points, Path, paths, macro, part }) => { + points.topLeft = new Point(0, 0) + points.topRight = new Point(150, 0) + points.bottomRight = new Point(150, 30) + points.bottomLeft = new Point(0, 30) + + paths.box = new Path() + .move(points.topLeft) + .line(points.topRight) + .line(points.bottomRight) + .line(points.bottomLeft) + .close() + + macro('cutonfold', { + from: points.bottomLeft, + to: points.bottomRight, + grainline: true, + }) + + return part + }, +} + +export const plugin_dimension = { + name: 'examples.plugin_dimension', + draft: ({ Point, points, Path, paths, macro, part }) => { + points.A = new Point(0, 0) + points.B = new Point(0, 100) + points.C = new Point(50, 100) + points.D = new Point(100, 50) + points.DCp1 = new Point(100, 0) + + paths.box = new Path() + .move(points.A) + .line(points.B) + .line(points.C) + .line(points.D) + .curve(points.DCp1, points.A, points.A) + .close() + + macro('vd', { + from: points.A, + to: points.B, + x: points.A.x - 15, + }) + + macro('hd', { + from: points.B, + to: points.C, + y: points.B.y + 15, + }) + + macro('ld', { + from: points.C, + to: points.D, + d: -15, + }) + + macro('ld', { + from: points.C, + to: points.D, + d: -30, + text: 'Custom text', + }) + + macro('pd', { + path: new Path().move(points.A).curve(points.A, points.DCp1, points.D), + d: -15, + }) + + return part + }, +} + +export const plugin_gore = { + name: 'examples.plugin_gore', + draft: ({ Point, points, macro, part }) => { + points.anchor = new Point(0, 0) + + macro('gore', { + from: points.anchor, + radius: 60, + gores: 5, + extraLength: 20, + }) + + return part + }, +} + +export const plugin_grainline = { + name: 'examples.plugin_grainline', + draft: ({ Point, points, macro, part }) => { + points.grainlineFrom = new Point(10, 10) + points.grainlineTo = new Point(100, 10) + + macro('grainline', { + from: points.grainlineFrom, + to: points.grainlineTo, + }) + + return box(part, 110, 15) + }, +} + +export const plugin_logo = { + name: 'examples.plugin_logo', + draft: ({ points, Point, snippets, Snippet, part }) => { + points.anchor = new Point(50, 25) + + snippets.logo = new Snippet('logo', points.anchor).attr('data-scale', 0.666) + + return box(part, 100, 35) + }, +} + +export const plugin_mirror = { + name: 'examples.plugin_mirror', + draft: ({ Point, Path, points, paths, macro, part }) => { + points.a = new Point(5, 5) + points.b = new Point(45, 30) + points.c = new Point(5, 30) + points.d = new Point(45, 5) + points.mid = new Point(25, 15) + + paths.a = new Path().move(points.a).curve(points.b, points.c, points.d) + + macro('mirror', { + mirror: [points.b, points.d], + points: [points.mid], + paths: [paths.a], + }) + + macro('sprinkle', { + snippet: 'notch', + on: ['mid', 'mirroredMid'], + }) + + return box(part, 100, 40) + }, +} + +export const plugin_notches = { + name: 'examples.plugin_notches', + draft: ({ Point, snippets, Snippet, part }) => { + snippets.notch = new Snippet('notch', new Point(60, 10)) + snippets.bnotch = new Snippet('bnotch', new Point(80, 10)) + + return box(part, 140, 20) + }, +} + +export const plugin_round = { + name: 'examples.plugin_round', + draft: ({ Point, points, Path, paths, macro, part }) => { + points.topLeft = new Point(0, 0) + points.bottomLeft = new Point(0, 30) + points.topRight = new Point(100, 0) + points.bottomRight = new Point(100, 30) + + paths.demo = new Path() + .move(points.topLeft) + .line(points.bottomLeft) + .line(points.bottomRight) + .line(points.topRight) + .close() + .attr('class', 'note dashed') + + macro('round', { + from: points.topLeft, + to: points.bottomRight, + via: points.bottomLeft, + radius: 10, + prefix: 'bl', + }) + macro('round', { + from: points.bottomRight, + to: points.topLeft, + via: points.topRight, + radius: 20, + prefix: 'tr', + }) + + return part + }, +} + +export const plugin_scalebox = { + name: 'examples.plugin_scalebox', + draft: ({ Point, points, macro, part }) => { + points.anchor1 = new Point(0, 0) + points.anchor2 = new Point(70, 0) + + macro('scalebox', { at: points.anchor1 }) + macro('miniscale', { at: points.anchor2 }) + + return part + }, +} + +export const plugin_sprinkle = { + name: 'examples.plugin_sprinkle', + draft: ({ Point, points, macro, part }) => { + points.a = new Point(10, 10) + points.b = new Point(20, 15) + points.c = new Point(30, 10) + points.d = new Point(40, 15) + points.e = new Point(50, 10) + points.f = new Point(60, 15) + points.g = new Point(70, 10) + points.h = new Point(80, 15) + points.i = new Point(90, 10) + + macro('sprinkle', { + snippet: 'button', + on: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'], + }) + + return box(part, 100, 25) + }, +} + +export const plugin_title = { + name: 'examples.plugin_title', + draft: ({ Point, points, macro, part }) => { + points.title = new Point(90, 45) + + macro('title', { + at: points.title, + nr: 4, + title: 'sleeve', + prefix: 'test', + }) + + return box(part, 200, 70) + }, +} diff --git a/designs/examples/src/point.mjs b/designs/examples/src/point.mjs new file mode 100644 index 00000000000..ef299c4d345 --- /dev/null +++ b/designs/examples/src/point.mjs @@ -0,0 +1,457 @@ +import { box } from './shared.mjs' + +export const point_addcircle = { + name: 'examples.point_addcircle', + draft: ({ Point, points, part }) => { + points.a = new Point(30, 10).addCircle(3, 'lining dashed').addCircle(7, 'mark dashed') + + points.b = new Point(50, 10) + .addCircle(1, 'interfacing') + .addCircle(3, 'fabric') + .addCircle(5, 'lining') + .addCircle(7, 'mark') + .addCircle(9, 'note') + + points.c = new Point(70, 10).addCircle(3, 'interfacing').addCircle(7, 'mark lashed') + return box(part, 100, 20) + }, +} + +export const point_addtext = { + name: 'examples.point_addtext', + draft: ({ Point, points, part }) => { + points.anchor = new Point(100, 25) + .addText('supportFreesewingBecomeAPatron', 'center') + .addText('please?') + + return box(part, 200, 50) + }, +} + +export const point_angle = { + name: 'examples.point_angle', + draft: ({ Point, points, Path, paths, part }) => { + points.sun = new Point(10, 5) + points.moon = points.sun.shift(-15, 70) + points.text = points.sun + .shiftFractionTowards(points.moon, 0.8) + .attr('data-text', points.sun.angle(points.moon) + 'Β°') + .attr('data-text-class', 'text-sm fill-note center') + + paths.line = new Path().move(points.sun).line(points.moon).attr('class', 'dashed') + + return part + }, +} + +export const point_attr = { + name: 'examples.point_attr', + draft: ({ Point, points, part }) => { + points.anchor = new Point(100, 25) + .attr('data-text', 'supportFreesewingBecomeAPatron') + .attr('data-text-class', 'center') + + return box(part, 200, 50) + }, +} + +export const point_clone = { + name: 'examples.point_clone', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.A = new Point(25, 25) + .attr('data-text', 'Point A') + .attr('data-text-class', 'text-xl') + .attr('data-text-fill-opacity', '0.5') + points.B = points.A.clone().attr('data-text', 'Point B') + + snippets.x = new Snippet('notch', points.A) + + return box(part) + }, +} + +export const point_copy = { + name: 'examples.point_copy', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.A = new Point(50, 25).attr('data-text', 'Point A').attr('data-text-class', 'text-xl') + points.B = points.A.copy().attr('data-text', 'Point B') + + snippets.x = new Snippet('notch', points.A) + + return box(part) + }, +} + +export const point_dist = { + name: 'examples.point_dist', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 10) + points.to = new Point(80, 70) + + points.text = points.from + .shiftFractionTowards(points.to, 0.6) + .attr('data-text', points.from.dist(points.to) + 'mm') + .attr('data-text-class', 'text-sm fill-note center') + + paths.line = new Path().move(points.from).line(points.to).attr('class', 'dashed') + + return part + }, +} + +export const point_dx = { + name: 'examples.point_dx', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 10) + points.to = new Point(80, 70) + + paths.line = new Path().move(points.from).line(points.to).attr('class', 'dashed') + + points.totop = points.from.shift(0, points.from.dx(points.to)) + + points.text_dx = points.from + .shiftFractionTowards(points.totop, 0.6) + .shiftFractionTowards(points.to, 0.1) + .attr('data-text', points.from.dx(points.to) + 'mm') + .attr('data-text-class', 'text-sm fill-note center') + + paths.line_dx = new Path().move(points.from).line(points.totop).attr('class', 'dashed') + + paths.line_dy = new Path().move(points.to).line(points.totop).attr('class', 'dashed') + + return part + }, +} + +export const point_dy = { + name: 'examples.point_dy', + draft: ({ Point, points, Path, paths, part }) => { + points.from = new Point(10, 10) + points.to = new Point(80, 70) + + paths.line = new Path().move(points.from).line(points.to).attr('class', 'dashed') + + points.totop = points.from.shift(0, points.from.dx(points.to)) + + paths.line_dx = new Path().move(points.from).line(points.totop).attr('class', 'dashed') + + points.text_dy = points.totop + .shiftFractionTowards(points.to, 0.4) + .attr('data-text', points.from.dy(points.to) + 'mm') + .attr('data-text-class', 'text-sm fill-note right') + + paths.line_dy = new Path().move(points.to).line(points.totop).attr('class', 'dashed') + + return part + }, +} + +export const point_flipx = { + name: 'examples.point_flipy', + draft: ({ Point, points, Path, paths, part }) => { + points.top = new Point(50, 10) + points.out1 = new Point(70, 30) + points.in1 = new Point(55, 35) + points.out2 = new Point(75, 50) + points.in2 = new Point(60, 55) + points.out3 = new Point(80, 70) + points.in3 = new Point(55, 70) + points.trunkOut = new Point(55, 80) + points.trunkIn = new Point(50, 80) + + points._out1 = points.out1.flipX(points.top) + points._in1 = points.in1.flipX(points.top) + points._out2 = points.out2.flipX(points.top) + points._in2 = points.in2.flipX(points.top) + points._out3 = points.out3.flipX(points.top) + points._in3 = points.in3.flipX(points.top) + points._trunkOut = points.trunkOut.flipX(points.top) + + points.bottom = new Point(50, 80) + + paths.tree = new Path() + .move(points.top) + .line(points.out1) + .line(points.in1) + .line(points.out2) + .line(points.in2) + .line(points.out3) + .line(points.in3) + .line(points.trunkOut) + .line(points._trunkOut) + .line(points._in3) + .line(points._out3) + .line(points._in2) + .line(points._out2) + .line(points._in1) + .line(points._out1) + .close() + + paths.mirror = new Path().move(points.top).line(points.bottom).attr('class', 'note dashed') + + return part + }, +} + +export const point_flipy = { + name: 'examples.point_flipy', + draft: ({ Point, points, Path, paths, part }) => { + points.start = new Point(0, 50) + points.churchTowerWallLeft = new Point(10, 50) + points.churchTowerRoofLeft = new Point(10, 30) + points.churchTowerTop = new Point(15, 10) + points.churchTowerRoofRight = new Point(20, 30) + points.churchRoofRight = new Point(50, 30) + points.churchWallRight = new Point(50, 50) + points.houseWallLeft = new Point(65, 50) + points.houseRoofLeft = new Point(65, 35) + points.houseRoofTop = new Point(75, 25) + points.houseRoofRight = new Point(85, 35) + points.houseWallRight = new Point(85, 50) + points.end = new Point(95, 50) + + points.mirror = new Point(0, 60) + points.mirrorLineEnd = new Point(95, 60) + + points._start = points.start.flipY(points.mirror) + points._churchTowerWallLeft = points.churchTowerWallLeft.flipY(points.mirror) + points._churchTowerRoofLeft = points.churchTowerRoofLeft.flipY(points.mirror) + points._churchTowerTop = points.churchTowerTop.flipY(points.mirror) + points._churchTowerRoofRight = points.churchTowerRoofRight.flipY(points.mirror) + points._churchRoofRight = points.churchRoofRight.flipY(points.mirror) + points._churchWallRight = points.churchWallRight.flipY(points.mirror) + points._houseWallLeft = points.houseWallLeft.flipY(points.mirror) + points._houseRoofLeft = points.houseRoofLeft.flipY(points.mirror) + points._houseRoofTop = points.houseRoofTop.flipY(points.mirror) + points._houseRoofRight = points.houseRoofRight.flipY(points.mirror) + points._houseWallRight = points.houseWallRight.flipY(points.mirror) + points._end = points.end.flipY(points.mirror) + + paths.skylineTop = new Path() + .move(points.start) + .line(points.churchTowerWallLeft) + .line(points.churchTowerRoofLeft) + .line(points.churchTowerTop) + .line(points.churchTowerRoofRight) + .line(points.churchRoofRight) + .line(points.churchWallRight) + .line(points.houseWallLeft) + .line(points.houseRoofLeft) + .line(points.houseRoofTop) + .line(points.houseRoofRight) + .line(points.houseWallRight) + .line(points.end) + + paths.skylineBottom = new Path() + .move(points._start) + .line(points._churchTowerWallLeft) + .line(points._churchTowerRoofLeft) + .line(points._churchTowerTop) + .line(points._churchTowerRoofRight) + .line(points._churchRoofRight) + .line(points._churchWallRight) + .line(points._houseWallLeft) + .line(points._houseRoofLeft) + .line(points._houseRoofTop) + .line(points._houseRoofRight) + .line(points._houseWallRight) + .line(points._end) + + paths.mirrorLine = new Path() + .move(points.mirror) + .line(points.mirrorLineEnd) + .attr('class', 'note dashed') + + return part + }, +} + +export const point_rotate = { + name: 'examples.point_rotate', + draft: ({ Point, points, Path, paths, part }) => { + points.sun = new Point(40, 40) + points.moon = new Point(70, 40) + let step = 360 / 36 + for (let i = 1; i < 37; i++) { + let angle = step * i + points[`moon${i}`] = points.moon.rotate(angle, points.sun) + paths[`moon${i}`] = new Path().move(points.sun).line(points[`moon${i}`]) + } + + return part + }, +} + +export const point_setcircle = { + name: 'examples.point_setcircle', + draft: ({ Point, points, part }) => { + points.a = new Point(30, 10).setCircle(3, 'lining dashed').setCircle(7, 'mark dashed') + + points.b = new Point(50, 10) + .setCircle(1, 'interfacing') + .setCircle(3, 'fabric') + .setCircle(5, 'lining') + .setCircle(7, 'mark') + .setCircle(9, 'note') + + points.c = new Point(70, 10).setCircle(3, 'interfacing').setCircle(7, 'mark lashed') + return box(part, 100, 20) + }, +} + +export const point_settext = { + name: 'examples.point_settext', + draft: ({ Point, points, part }) => { + points.anchor = new Point(100, 25) + .setText('supportFreesewingBecomeAPatron', 'center') + .setText('please?') + + return box(part, 200, 50) + }, +} + +export const point_shift = { + name: 'examples.point_shift', + draft: ({ Point, points, macro, part }) => { + points.A = new Point(90, 40).attr('data-text', 'Point A').attr('data-text-class', 'right') + points.B = points.A.shift(155, 70) + .attr('data-text', 'Point B is point A shifted 7cm\nat a 155 degree angle') + .attr('data-text-lineheight', 6) + + macro('ld', { + from: points.B, + to: points.A, + d: -10, + }) + + return box(part, 100, 45) + }, +} + +export const point_shiftfractiontowards = { + name: 'examples.point_shiftfractiontowards', + draft: ({ Point, points, Path, paths, macro, part }) => { + points.A = new Point(90, 70).attr('data-text', 'Point A') + points.B = new Point(10, 10).attr('data-text', 'Point B') + points.C = points.A.shiftFractionTowards(points.B, 0.5) + .attr('data-text', 'Point C is point A shifted 50%\nin the direction of point B') + .attr('data-text-class', 'center') + .attr('data-text-lineheight', 6) + + paths.direction = new Path().move(points.A).line(points.B).attr('class', 'note dashed') + + macro('ld', { + from: points.C, + to: points.A, + d: -10, + }) + + macro('ld', { + from: points.B, + to: points.A, + d: 20, + }) + + return part + }, +} + +export const point_shiftoutwards = { + name: 'examples.point_shiftoutwards', + draft: ({ Point, points, Path, paths, macro, part }) => { + points.A = new Point(90, 70).attr('data-text', 'Point A') + points.B = new Point(30, 30).attr('data-text', 'Point B') + points.C = points.A.shiftOutwards(points.B, 30) + .attr('data-text', 'Point C is point A shifted 3cm\nbeyond point B') + .attr('data-text-lineheight', 6) + + paths.direction = new Path().move(points.A).line(points.C).attr('class', 'note dashed') + + macro('ld', { + from: points.C, + to: points.B, + d: -10, + }) + + return box(part, 110, 75) + }, +} + +export const point_shifttowards = { + name: 'examples.point_shifttowards', + draft: ({ Point, points, Path, paths, macro, part }) => { + points.A = new Point(90, 70).attr('data-text', 'Point A') + points.B = new Point(10, 10).attr('data-text', 'Point B') + points.C = points.A.shiftTowards(points.B, 35) + .attr('data-text', 'Point C is point A shifted 3.5cm\nin the direction of point B') + .attr('data-text-class', 'center') + .attr('data-text-lineheight', 6) + + paths.direction = new Path().move(points.A).line(points.B).attr('class', 'note dashed') + + macro('ld', { + from: points.C, + to: points.A, + d: -10, + }) + + return box(part, 110, 80) + }, +} + +export const point_sitson = { + name: 'examples.point_sitson', + draft: ({ Point, points, Snippet, snippets, part }) => { + let s + for (let i = 0; i < 10; i++) { + points[`a${i}`] = new Point(i * 10, 40) + points[`b${i}`] = new Point(i * 10, i * 8) + if (points[`a${i}`].sitsOn(points[`b${i}`])) s = 'notch' + else s = 'bnotch' + snippets[`b${i}`] = new Snippet(s, points[`b${i}`]) + snippets[`a${i}`] = new Snippet(s, points[`a${i}`]) + } + + return box(part) + }, +} + +export const point_sitsroughlyon = { + name: 'examples.point_sitsroughlyon', + draft: ({ Point, points, Snippet, snippets, part }) => { + box(part) + + let s + for (let i = 0; i < 10; i++) { + points[`a${i}`] = new Point(i * 10, 40) + points[`b${i}`] = new Point(i * 10, i * 8) + if (points[`a${i}`].sitsRoughlyOn(points[`b${i}`])) s = 'notch' + else s = 'bnotch' + snippets[`b${i}`] = new Snippet(s, points[`b${i}`]) + snippets[`a${i}`] = new Snippet(s, points[`a${i}`]) + } + + return part + }, +} + +export const point_translate = { + name: 'examples.point_translate', + draft: ({ Point, points, macro, part }) => { + points.A = new Point(20, 20).attr('data-text', 'Point A') + points.B = points.A.translate(120, 60) + .attr('data-text', 'Point B is point A with a\ntranslate(120, 60)\ntransform applied') + .attr('data-text-class', 'right') + .attr('data-text-dy', -6) + .attr('data-text-lineheight', 6) + + macro('ld', { + from: points.A, + to: points.B, + text: 'translate(120,60)', + noStartMarker: true, + }) + + return box(part, 150, 85) + }, +} diff --git a/designs/examples/src/settings.mjs b/designs/examples/src/settings.mjs new file mode 100644 index 00000000000..a8ffe9ea574 --- /dev/null +++ b/designs/examples/src/settings.mjs @@ -0,0 +1,22 @@ +export const settings_sa = { + name: 'examples.settings_sa', + draft: ({ Point, points, Path, paths, part }) => { + points.A = new Point(45, 60) + points.B = new Point(10, 30) + points.BCp2 = new Point(40, 20) + points.C = new Point(90, 30) + points.CCp1 = new Point(50, -30) + + paths.example = new Path() + .move(points.A) + .line(points.B) + .curve(points.BCp2, points.CCp1, points.C) + .line(points.A) + .close() + .attr('class', 'fabric') + + paths.offset = paths.example.offset(-10).attr('class', 'fabric sa') + + return part + }, +} diff --git a/designs/examples/src/shared.mjs b/designs/examples/src/shared.mjs new file mode 100644 index 00000000000..e99bb3fbd3c --- /dev/null +++ b/designs/examples/src/shared.mjs @@ -0,0 +1,13 @@ +/** + * This draws a (diagonal in a) box + * with with w and height h with a non-visible line. + * This is to force our examples parts to a certain size + */ +export function box(part, w = 100, h = 50) { + part.paths.box = new part.Path() + .move(new part.Point(0, 0)) + .line(new part.Point(w, h)) + .setClass('hidden noxray') + + return part +} diff --git a/designs/examples/src/snippet.mjs b/designs/examples/src/snippet.mjs new file mode 100644 index 00000000000..152a6635f07 --- /dev/null +++ b/designs/examples/src/snippet.mjs @@ -0,0 +1,39 @@ +import { box } from './shared.mjs' + +export const snippet = { + name: 'examples.snippet', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor1 = new Point(20, 15) + points.anchor2 = new Point(50, 15) + points.anchor3 = new Point(80, 15) + snippets.demo1 = new Snippet('button', points.anchor1) + snippets.demo2 = new Snippet('buttonhole', points.anchor2) + snippets.demo3 = new Snippet('logo', points.anchor3).attr('data-scale', 0.5) + + return box(part) + }, +} + +export const snippet_attr = { + name: 'examples.snippet_attr', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 15) + snippets.demo = new Snippet('logo', points.anchor) + .attr('data-scale', 0.8) + .attr('data-rotate', 180) + + return box(part) + }, +} + +export const snippet_clone = { + name: 'examples.snippet_clone', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(35, 35) + snippets.demo = new Snippet('logo', points.anchor).attr('style', 'color: #f006') + + snippets.clone = snippets.demo.clone().attr('data-scale', 0.5) + + return box(part) + }, +} diff --git a/designs/examples/src/snippets.mjs b/designs/examples/src/snippets.mjs new file mode 100644 index 00000000000..95c2e3d3ea4 --- /dev/null +++ b/designs/examples/src/snippets.mjs @@ -0,0 +1,91 @@ +import { box } from './shared.mjs' + +export const snippet_bnotch = { + name: 'examples.snippet_bnotch', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 5) + snippets.demo = new Snippet('bnotch', points.anchor) + + return box(part, 100, 10) + }, +} + +export const snippet_button = { + name: 'examples.snippet_button', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 5) + snippets.demo = new Snippet('button', points.anchor) + + return box(part, 100, 10) + }, +} + +export const snippet_buttonholeend = { + name: 'examples.snippet_buttonholeend', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 0) + snippets.demo = new Snippet('buttonhole-end', points.anchor) + + return box(part, 100, 10) + }, +} + +export const snippet_buttonholestart = { + name: 'examples.snippet_buttonholestart', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 10) + snippets.demo = new Snippet('buttonhole-start', points.anchor) + + return box(part, 100, 10) + }, +} + +export const snippet_buttonhole = { + name: 'examples.snippet_buttonhole', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 5) + snippets.demo = new Snippet('buttonhole', points.anchor) + + return box(part, 100, 10) + }, +} + +export const snippet_logo = { + name: 'examples.snippet_logo', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 35) + snippets.demo = new Snippet('logo', points.anchor) + + return box(part, 100, 50) + }, +} + +export const snippet_notch = { + name: 'examples.snippet_notch', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 5) + snippets.demo = new Snippet('notch', points.anchor) + + return box(part, 100, 10) + }, +} + +export const snippet_snapsocket = { + name: 'examples.snippet_snapsocket', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 5) + snippets.demo = new Snippet('snap-socket', points.anchor) + + return box(part, 100, 10) + }, +} + +export const snippet_snapstud = { + name: 'examples.snippet_snapstud', + draft: ({ Point, points, Snippet, snippets, part }) => { + points.anchor = new Point(50, 5) + snippets.demo = new Snippet('snap-stud', points.anchor) + + return box(part, 100, 10) + }, +} diff --git a/designs/examples/src/stacks.mjs b/designs/examples/src/stacks.mjs new file mode 100644 index 00000000000..8b0cd0255f6 --- /dev/null +++ b/designs/examples/src/stacks.mjs @@ -0,0 +1,128 @@ +const stack = (settings, partName) => { + if (settings?.options?.stackIt === 'Do stack') return 'example' + else return partName +} + +export const stacks_top = { + name: 'examples.stacks_top', + stack, + measurements: ['head'], + options: { + size: { pct: 50, min: 5, max: 100, menu: 'stack' }, + x: { pct: 0, min: -100, max: 100, menu: 'stack' }, + y: { pct: 0, min: -100, max: 100, menu: 'stack' }, + stackIt: { dflt: 'Do stack', list: ['Do stack', 'Do not stack'], menu: 'stack' }, + }, + draft: ({ store, Point, points, Path, paths, options, measurements, part }) => { + store.set('size', measurements.head * options.size) + store.set('x', measurements.head * options.x) + store.set('y', measurements.head * options.y) + points.from = new Point(store.get('x'), store.get('y')) + points.to = points.from.shift(0, store.get('size')) + paths.line = new Path().move(points.from).line(points.to).attr('class', 'fabric stroke-4xl') + + return part + }, +} + +export const stacks_right = { + name: 'examples.stacks_right', + stack, + after: stacks_top, + draft: ({ store, Point, points, Path, paths, part }) => { + points.from = new Point(store.get('x') + store.get('size'), store.get('y')) + points.to = points.from.shift(-90, store.get('size')) + paths.line = new Path().move(points.from).line(points.to).attr('class', 'fabric stroke-4xl') + + return part + }, +} + +export const stacks_bottom = { + name: 'examples.stacks_bottom', + stack, + after: stacks_top, + draft: ({ store, Point, points, Path, paths, part }) => { + points.from = new Point(store.get('x') + store.get('size'), store.get('y') + store.get('size')) + points.to = points.from.shift(180, store.get('size')) + paths.line = new Path().move(points.from).line(points.to).attr('class', 'fabric stroke-4xl') + + return part + }, +} + +export const stacks_left = { + name: 'examples.stacks_left', + stack, + after: stacks_top, + draft: ({ store, Point, points, Path, paths, part }) => { + points.from = new Point(store.get('x'), store.get('y') + store.get('size')) + points.to = points.from.shift(90, store.get('size')) + paths.line = new Path().move(points.from).line(points.to).attr('class', 'fabric stroke-4xl') + + return part + }, +} + +export const stacks_leftEye = { + name: 'examples.stacks_leftEye', + stack, + after: stacks_top, + draft: ({ store, Point, points, part }) => { + points.leftEye = new Point( + store.get('x') + store.get('size') * 0.35, + store.get('y') + store.get('size') * 0.4 + ) + .attr('data-circle', store.get('size') * 0.1) + .attr('data-circle-class', 'stroke-6xl') + + return part + }, +} + +export const stacks_rightEye = { + name: 'examples.stacks_rightEye', + stack, + after: stacks_top, + draft: ({ store, Point, points, part }) => { + points.rightEye = new Point( + store.get('x') + store.get('size') * 0.65, + store.get('y') + store.get('size') * 0.4 + ) + .attr('data-circle', store.get('size') * 0.08) + .attr('data-circle-class', 'stroke-7xl') + + return part + }, +} + +export const stacks_mouth = { + name: 'examples.stacks_mouth', + stack, + after: stacks_top, + draft: ({ store, Point, points, paths, Path, part }) => { + points.left = new Point( + store.get('x') + store.get('size') * 0.15, + store.get('y') + store.get('size') * 0.5 + ) + points.right = new Point( + store.get('x') + store.get('size') * 0.85, + store.get('y') + store.get('size') * 0.5 + ) + points.leftCp = new Point( + store.get('x') + store.get('size') * 0.35, + store.get('y') + store.get('size') * 0.8 + ) + points.rightCp = new Point( + store.get('x') + store.get('size') * 0.65, + store.get('y') + store.get('size') * 0.8 + ) + + paths.mouth = new Path() + .move(points.left) + .curve(points.leftCp, points.rightCp, points.right) + .attr('class', 'fabric stroke-7xl') + + return part + }, +} diff --git a/designs/examples/src/utils.mjs b/designs/examples/src/utils.mjs new file mode 100644 index 00000000000..201fa7d40f0 --- /dev/null +++ b/designs/examples/src/utils.mjs @@ -0,0 +1,445 @@ +import { box } from './shared.mjs' + +export const utils_beamintersectscircle = { + name: 'examples.utils_beamintersectscircle', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.A = new Point(95, 45).attr('data-circle', 35).attr('data-circle-class', 'fabric') + points.B = new Point(55, 50) + points.C = new Point(75, 30) + points.D = new Point(55, 65) + points.E = new Point(115, 5) + points.F = new Point(65, 75) + points.G = new Point(125, 15) + + paths.line1 = new Path().move(points.B).line(points.C) + paths.line2 = new Path().move(points.D).line(points.E) + paths.line3 = new Path().move(points.F).line(points.G) + + let intersections1 = utils.beamIntersectsCircle( + points.A, + points.A.attributes.get('data-circle'), + points.B, + points.C + ) + let intersections2 = utils.beamIntersectsCircle( + points.A, + points.A.attributes.get('data-circle'), + points.D, + points.E, + 'y' + ) + let intersections3 = utils.beamIntersectsCircle( + points.A, + points.A.attributes.get('data-circle'), + points.F, + points.G + ) + + snippets.first1 = new Snippet('bnotch', intersections1[0]) + snippets.second1 = new Snippet('notch', intersections1[1]) + snippets.first2 = new Snippet('bnotch', intersections2[0]) + snippets.second2 = new Snippet('notch', intersections2[1]) + snippets.first3 = new Snippet('bnotch', intersections3[0]) + snippets.second3 = new Snippet('notch', intersections3[1]) + + return box(part, 200, 80) + }, +} + +export const utils_beamintersectsx = { + name: 'examples.utils_beamintersectsx', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.A = new Point(10, 10) + points.B = new Point(90, 30) + + paths.AB = new Path().move(points.A).line(points.B) + + snippets.x = new Snippet('notch', utils.beamIntersectsX(points.A, points.B, 40)) + + paths.help = new Path() + .move(new Point(40, 5)) + .line(new Point(40, 35)) + .attr('class', 'note dashed') + + return part + }, +} + +export const utils_beamintersectsy = { + name: 'examples.utils_beamintersectsy', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.A = new Point(10, 10) + points.B = new Point(50, 40) + + paths.AB = new Path().move(points.A).line(points.B) + + snippets.x = new Snippet('notch', utils.beamIntersectsY(points.A, points.B, 30)) + + paths.help = new Path() + .move(new Point(0, 30)) + .line(new Point(50, 30)) + .attr('class', 'note dashed') + + return part + }, +} + +export const utils_beamsintersect = { + name: 'examples.utils_beamsintersect', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.A = new Point(10, 10) + points.B = new Point(50, 40) + points.C = new Point(45, 20) + points.D = new Point(60, 15) + + paths.AB = new Path().move(points.A).line(points.B) + paths.CD = new Path().move(points.C).line(points.D) + + snippets.x = new Snippet('notch', utils.beamsIntersect(points.A, points.B, points.C, points.D)) + + return part + }, +} + +export const utils_circlesintersect = { + name: 'examples.utils_circlesintersect', + draft: ({ Point, points, Snippet, snippets, utils, part }) => { + points.A = new Point(10, 10).attr('data-circle', 15).attr('data-circle-class', 'fabric') + points.B = new Point(30, 30).attr('data-circle', 35).attr('data-circle-class', 'fabric') + points.C = new Point(90, 10).attr('data-circle', 15).attr('data-circle-class', 'various') + points.D = new Point(110, 30).attr('data-circle', 35).attr('data-circle-class', 'various') + + let intersections1 = utils.circlesIntersect( + points.A, + points.A.attributes.get('data-circle'), + points.B, + points.B.attributes.get('data-circle') + ) + let intersections2 = utils.circlesIntersect( + points.C, + points.C.attributes.get('data-circle'), + points.D, + points.D.attributes.get('data-circle'), + 'y' + ) + + snippets.first1 = new Snippet('bnotch', intersections1[0]) + snippets.second1 = new Snippet('notch', intersections1[1]) + snippets.first2 = new Snippet('bnotch', intersections2[0]) + snippets.second2 = new Snippet('notch', intersections2[1]) + + return part + }, +} + +export const utils_curveintersectsx = { + name: 'examples.utils_curveintersectsx', + draft: ({ Point, points, Path, paths, utils, snippets, Snippet, part }) => { + points.start = new Point(10, 15) + points.cp1 = new Point(80, 10) + points.cp2 = new Point(-50, 80) + points.end = new Point(110, 70) + + paths.curve = new Path().move(points.start).curve(points.cp1, points.cp2, points.end) + + for (let x of [30, 40]) { + points['from' + x] = new Point(x, 10) + points['to' + x] = new Point(x, 80) + paths['line' + x] = new Path() + .move(points['from' + x]) + .line(points['to' + x]) + .attr('class', 'lining dashed') + } + + snippets.i40 = new Snippet( + 'notch', + utils.curveIntersectsX(points.start, points.cp1, points.cp2, points.end, 40) + ) + + for (let p of utils.curveIntersectsX(points.start, points.cp1, points.cp2, points.end, 30)) + snippets[p.y] = new Snippet('notch', p) + + return part + }, +} + +export const utils_curveintersectsy = { + name: 'examples.utils_curveintersectsy', + draft: ({ Point, points, Path, paths, utils, snippets, Snippet, part }) => { + points.start = new Point(10, 45) + points.cp1 = new Point(50, 10) + points.cp2 = new Point(0, 80) + points.end = new Point(110, 70) + + paths.curve = new Path().move(points.start).curve(points.cp1, points.cp2, points.end) + + for (let y of [40, 50]) { + points['from' + y] = new Point(10, y) + points['to' + y] = new Point(110, y) + paths['line' + y] = new Path() + .move(points['from' + y]) + .line(points['to' + y]) + .attr('class', 'lining dashed') + } + + snippets.i50 = new Snippet( + 'notch', + utils.curveIntersectsY(points.start, points.cp1, points.cp2, points.end, 50) + ) + + for (let p of utils.curveIntersectsY(points.start, points.cp1, points.cp2, points.end, 40)) + snippets[p.x] = new Snippet('notch', p) + + return part + }, +} + +export const utils_curvesintersect = { + name: 'examples.utils_curvesintersect', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.A = new Point(10, 10) + points.Acp = new Point(310, 40) + points.B = new Point(110, 70) + points.Bcp = new Point(-210, 40) + + points.C = new Point(20, -5) + points.Ccp = new Point(60, 300) + points.D = new Point(100, 85) + points.Dcp = new Point(70, -220) + paths.curveA = new Path().move(points.A).curve(points.Acp, points.Bcp, points.B) + paths.curveB = new Path().move(points.C).curve(points.Ccp, points.Dcp, points.D) + + for (let p of utils.curvesIntersect( + points.A, + points.Acp, + points.Bcp, + points.B, + points.C, + points.Ccp, + points.Dcp, + points.D + )) { + snippets[part.getId()] = new Snippet('notch', p) + } + + return part + }, +} + +export const utils_lineintersectscircle = { + name: 'examples.utils_lineintersectscircle', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.A = new Point(95, 45).attr('data-circle', 35).attr('data-circle-class', 'fabric') + points.B = new Point(55, 50) + points.C = new Point(75, 30) + + points.D = new Point(55, 65) + points.E = new Point(115, 5) + points.F = new Point(65, 75) + points.G = new Point(125, 15) + + paths.line1 = new Path().move(points.B).line(points.C) + paths.line2 = new Path().move(points.D).line(points.E) + paths.line3 = new Path().move(points.F).line(points.G) + + let intersections1 = utils.lineIntersectsCircle( + points.A, + points.A.attributes.get('data-circle'), + points.B, + points.C + ) + let intersections2 = utils.lineIntersectsCircle( + points.A, + points.A.attributes.get('data-circle'), + points.D, + points.E, + 'y' + ) + let intersections3 = utils.lineIntersectsCircle( + points.A, + points.A.attributes.get('data-circle'), + points.F, + points.G + ) + snippets.first1 = new Snippet('bnotch', intersections1[0]) + snippets.first2 = new Snippet('bnotch', intersections2[0]) + snippets.second2 = new Snippet('notch', intersections2[1]) + snippets.first3 = new Snippet('bnotch', intersections3[0]) + snippets.second3 = new Snippet('notch', intersections3[1]) + + return box(part, 200, 80) + }, +} + +export const utils_lineintersectscurve = { + name: 'examples.utils_lineintersectscurve', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.A = new Point(10, 10) + points.Acp = new Point(310, 40) + points.B = new Point(110, 70) + points.Bcp = new Point(-210, 40) + points.E = new Point(20, -5) + points.D = new Point(100, 85) + paths.curve = new Path().move(points.A).curve(points.Acp, points.Bcp, points.B) + paths.line = new Path().move(points.E).line(points.D) + + for (let p of utils.lineIntersectsCurve( + points.D, + points.E, + points.A, + points.Acp, + points.Bcp, + points.B + )) { + snippets[part.getId()] = new Snippet('notch', p) + } + + return part + }, +} + +export const utils_linesintersect = { + name: 'examples.utils_linesintersect', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.A = new Point(10, 10) + points.B = new Point(50, 40) + points.C = new Point(15, 30) + points.D = new Point(60, 15) + + paths.AB = new Path().move(points.A).line(points.B) + paths.CD = new Path().move(points.C).line(points.D) + + snippets.X = new Snippet('notch', utils.linesIntersect(points.A, points.B, points.C, points.D)) + + return part + }, +} + +export const utils_pointonbeam = { + name: 'examples.utils_pointonbeam', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.from1 = new Point(10, 10) + points.to1 = new Point(90, 60) + points.from2 = new Point(10, 30) + points.to2 = new Point(90, 80) + points.b1 = new Point(170, 110) + points.b2 = new Point(170, 130) + + let scatter = [] + for (let i = 1; i < 36; i++) { + for (let j = 1; j < 27; j++) { + scatter.push(new Point(i * 10, j * 10)) + } + } + let snippet + for (let point of scatter) { + if (utils.pointOnBeam(points.from1, points.to1, point)) snippet = 'notch' + else snippet = 'bnotch' + snippets[part.getId()] = new Snippet(snippet, point) + if (utils.pointOnBeam(points.from2, points.to2, point, 0.01)) { + snippet = 'notch' + } else snippet = 'bnotch' + snippets[part.getId()] = new Snippet(snippet, point) + } + paths.line1 = new Path().move(points.from1).line(points.to1).attr('class', 'fabric stroke-lg') + paths.lne1 = new Path().move(points.to1).line(points.b1).attr('class', 'fabric dashed') + paths.line2 = new Path().move(points.from2).line(points.to2).attr('class', 'fabric stroke-lg') + paths.lne2 = new Path().move(points.to2).line(points.b2).attr('class', 'fabric dashed') + + return part + }, +} + +export const utils_pointoncurve = { + name: 'examples.utils_pointoncurve', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.start = new Point(10, 10) + points.cp1 = new Point(90, 10) + points.cp2 = new Point(10, 60) + points.end = new Point(90, 60) + + let scatter = [] + for (let i = 1; i < 19; i++) { + for (let j = 1; j < 14; j++) { + scatter.push(new Point(i * 10, j * 10)) + } + } + let snippet + for (let point of scatter) { + if (utils.pointOnCurve(points.start, points.cp1, points.cp2, points.end, point)) { + snippet = 'notch' + } else snippet = 'bnotch' + snippets[part.getId()] = new Snippet(snippet, point) + } + paths.curve = new Path() + .move(points.start) + .curve(points.cp1, points.cp2, points.end) + .attr('class', 'fabric stroke-lg') + + return part + }, +} + +export const utils_pointonline = { + name: 'examples.utils_pointonline', + draft: ({ Point, points, Path, paths, Snippet, snippets, utils, part }) => { + points.from1 = new Point(10, 10) + points.to1 = new Point(90, 60) + points.from2 = new Point(10, 30) + points.to2 = new Point(90, 80) + points.b1 = new Point(170, 110) + points.b2 = new Point(170, 130) + + let scatter = [] + for (let i = 1; i < 36; i++) { + for (let j = 1; j < 27; j++) { + scatter.push(new Point(i * 10, j * 10)) + } + } + let snippet + for (let point of scatter) { + if (utils.pointOnLine(points.from1, points.to1, point)) snippet = 'notch' + else snippet = 'bnotch' + snippets[part.getId()] = new Snippet(snippet, point) + if (utils.pointOnLine(points.from2, points.to2, point, 0.01)) { + snippet = 'notch' + } else snippet = 'bnotch' + snippets[part.getId()] = new Snippet(snippet, point) + } + paths.line1 = new Path().move(points.from1).line(points.to1).attr('class', 'fabric stroke-lg') + paths.lne1 = new Path().move(points.to1).line(points.b1).attr('class', 'fabric dashed') + paths.line2 = new Path().move(points.from2).line(points.to2).attr('class', 'fabric stroke-lg') + paths.lne2 = new Path().move(points.to2).line(points.b2).attr('class', 'fabric dashed') + + return part + }, +} + +export const utils_splitcurve = { + name: 'examples.utils_splitcurve', + draft: ({ Point, points, Path, paths, utils, part }) => { + points.from = new Point(40, 10) + points.to = new Point(40, 80) + paths.line = new Path().move(points.from).line(points.to).attr('class', 'lining dashed') + + points.start = new Point(10, 15) + points.cp1 = new Point(80, 10) + points.cp2 = new Point(-50, 80) + points.end = new Point(110, 70) + + points.i40 = utils.curveIntersectsX(points.start, points.cp1, points.cp2, points.end, 40) + + let parts = utils.splitCurve(points.start, points.cp1, points.cp2, points.end, points.i40) + + let colors = ['lining', 'interfacing'] + for (let p of parts) { + let color = colors.pop() + paths[color] = new Path() + .move(p.start) + .curve(p.cp1, p.cp2, p.end) + .attr('class', 'stroke-xl ' + color) + } + + return part + }, +} diff --git a/designs/examples/tests/shared.test.mjs b/designs/examples/tests/shared.test.mjs new file mode 100644 index 00000000000..88702efb737 --- /dev/null +++ b/designs/examples/tests/shared.test.mjs @@ -0,0 +1,16 @@ +// This file is auto-generated | Any changes you make will be overwritten. +import { Examples } from '../src/index.mjs' + +// Shared tests +import { testPatternConfig } from '../../../tests/designs/config.mjs' +import { testPatternDrafting } from '../../../tests/designs/drafting.mjs' +//import { testPatternSampling } from '../../../tests/designs/sampling.mjs' + +// Test config +testPatternConfig(Examples) + +// Test drafting - Change the second parameter to `true` to log errors +testPatternDrafting(Examples, false) + +// Test sampling - Change the second parameter to `true` to log errors +//testPatternSampling(Examples, false)