Merge branch 'develop' into eriese-fix-builds
This commit is contained in:
commit
14db0afec0
219 changed files with 2228 additions and 4119 deletions
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: FreeSewing v3 Migration Guide
|
||||
---
|
||||
|
||||
## About this guide
|
||||
|
||||
This guide is intended for people who are using FreeSewing v2 and want to know what changes are required for FreeSewing version 3.
|
||||
If your experience with/exposure to FreeSewing started with version 3, you can safely ignore this guide.
|
||||
|
||||
## Part-based configuration
|
||||
|
||||
### Motivation
|
||||
|
||||
Onn
|
|
@ -1,14 +1,147 @@
|
|||
---
|
||||
title: Migration guide
|
||||
title: FreeSewing version 3
|
||||
---
|
||||
|
||||
- named exports
|
||||
- ESM only
|
||||
Since August 2022, we've been working on the next major version of FreeSewing: version 3 (v3).
|
||||
This guides gives a high level overview of the changes that are going into v3, why we're making them, and what to expect.
|
||||
|
||||
If you're looking for a more hands-on list of changes between v2 and v3, please refer to [the v3 migration guide](/guides/v3/migration).
|
||||
|
||||
Once v3 is in production, these guides will become less relevant. For the time being, that is not the case though, so things could still change. That being said, here's the inside scoop on v3.
|
||||
|
||||
## Why a version 3 in the first place?
|
||||
|
||||
Before diving into the details, let's take a moment to go over some of the reasons why we decided to start work on v3, rather than put keep working on the v2 branch of FreeSewing.
|
||||
|
||||
FreeSewing practices [semantic versioning](https://semver.org/), which means that any breaking changes require a new major version.
|
||||
In more practical terms, it means that new features or ideas that would require breaking changes are put on the back burner until enough of them accumulate that they start making a compelling case for putting out a new major version.
|
||||
|
||||
For FreeSewing v3, [our contributor call on 20 August 2022](https://github.com/freesewing/freesewing/discussions/2582) marks the moment that we decided enough of our plans and ambitions were being held back by our inability to introduce breaking changes that we decided to turn the page and start working on v3.
|
||||
|
||||
## High-level goals
|
||||
|
||||
### Support for packs
|
||||
|
||||
The main driver for v3 was what was listed on [our roadmap](https://github.com/freesewing/freesewing/discussions/1278) as *Support for packs*. The idea initially focussed on publishing collections of re-usable pattern parts such as a *sleeve pack* or a *collar pack* and so on. You would then be able to create new designs by pulling in a collar from the collar pack, some sleeves from the sleeve pack and so on.
|
||||
|
||||
As we itterated on this idea, it became clear that there was little added value in creating another type of container (a *pack*) and that it would be better of we made it easier to treat each design as a *pack*. In other words, allow people to combine parts from different designs in a seamless way.
|
||||
|
||||
Design inheritance was already possible in v2, but because the configuration was handled on the design level, it required careful re-confiruration of (required) measuremetns, options, part dependencies, and so on. It was possible, but came with a lot of friction.
|
||||
|
||||
So in v3, all configuration is moved to the part level, and a design is now not much more than a container object for a collection of parts.Its the parts themselves that configure what they need. Anything from the measurements they require, the options they provide, the plugins they use, and so on.
|
||||
|
||||
This way, you can pull a part out of a design and all of its configuration, dependencies, plugins, and so on will follow it.
|
||||
|
||||
This migration of the configuration to the part level (from the design level) is the biggest and most fundamental change between v2 and v3. It is also where most of the work needs to be done to port existing designs from v2 to v3.
|
||||
|
||||
### Improved developer experience.
|
||||
|
||||
In version 2, we ship both CJS and ESM modules, and we rely on default exports.
|
||||
In version 3, FreeSewing is ESM-only and we have also migrated to only use named exports in the code we publish as they provide better IDE integration.
|
||||
|
||||
As part of our move to v3, we've switched from Rollup to Esbuild as our bundles, and in the process dumped Babel.
|
||||
|
||||
For many of our users, these choices are deep enough under the hood that they are unconcerned by them.
|
||||
Together, they only speed up our builds, they also improve the developer experience, which has been another big driver in v3.
|
||||
|
||||
### Multisets, Stacks, and better support for sampling
|
||||
|
||||
Sampling is when FreeSewing drafts a number of variations of a given pattern and allows you to compare them by stacking the parts on top of each other. In v2 this was handled in a sort of hackish way as it was very much bolted on as an afterthought.
|
||||
|
||||
To handle this type of use-case in v3, we've added two new features that together open up a range of possibilities.
|
||||
One is support for multisets, the other is support for stacks.
|
||||
|
||||
Multisets means you can pass a number of different sets of settings to a pattern and core will draft the pattern for each set of settings.
|
||||
|
||||
Stacks allow you to designate different parts of your pattern --- or parts across different sets of settings --- as belonging to the same stack. When it's time to layout your pattern, core will stack them on top of each other, a bit like layers.
|
||||
|
||||
These two new features not only make sampling a lot more straight-forward, they also allow other possibilities such as drafting a pattern for two sets of measurements which can be handy when dealing with an assymetric body for example.
|
||||
|
||||
### Provide more generic extending capabilities, rather than tight-coupling with our frontend
|
||||
|
||||
This is something that works on two different levels.
|
||||
|
||||
One one hand, we've had some feature requests in v2 that were good use cases, but a bit too specific to the user's use-case for us to add them to core.
|
||||
|
||||
On the other hand, there are things in core and in a design's configuration that are tightly coupled to FreeSewing's own frontend (on FreeSewing.org) and not really relevant to people using our sortware for other purposes.
|
||||
|
||||
In v3, we wanted to get rid of the FreeSewing.org specific stuff and instead give all our users, including ourselves, the possibility to extend the software with the features they needed for frontend integration.
|
||||
|
||||
Designs now no longer ship with any freesewing.org specific info, but more importantly, plugins can now further extend core with *store methods*. We've also extended to available lifecycle hooks to let people hook into the drafting process at different times in a pattern's lifecycle.
|
||||
|
||||
We also allow overloading of both options and the store with additional information to facilitate frontend integration.
|
||||
|
||||
Last but not least, we've improved the logging process as well as allow people to plug in their own log handlers.
|
||||
|
||||
## New in the core API
|
||||
|
||||
The core API is -- for the most part -- unchanged in v3. What's changed is covered in [the migration guide](/guides/v3/migration).
|
||||
But there's a bunch of new things, and here is the list:
|
||||
|
||||
### New attributes
|
||||
|
||||
The following attributes have been added to the core API in v3:
|
||||
|
||||
#### On the `Pattern` object
|
||||
|
||||
- [Pattern.designConfig](/reference/api/pattern#pattern-attributes)
|
||||
- [Pattern.patternConfig](/reference/api/pattern#pattern-attributes)
|
||||
- [Pattern.setStores](/reference/api/pattern#pattern-attributes)
|
||||
|
||||
### New methods
|
||||
|
||||
The following methods have been added to the core API in v3:
|
||||
|
||||
#### On the `Attributes` object
|
||||
|
||||
- [Attributes.addClass](/reference/api/attributes/addclass)
|
||||
- [Attributes.asPropIfPrefixIs](/reference/api/attributes/aspropifprefixis)
|
||||
- [Attributes.render](/reference/api/attributes/render)
|
||||
- [Attributes.renderAsCss](/reference/api/attributes/renderascss)
|
||||
- [Attributes.renderIfPrefixIs](/reference/api/attributes/renderifprefixis)
|
||||
|
||||
#### On the `Part` object
|
||||
|
||||
- [Part.hide](/reference/api/part/hide)
|
||||
- [Part.setHidden](/reference/api/part/sethidden)
|
||||
- [Part.unhide](/reference/api/part/unhide)
|
||||
|
||||
#### On the `Path` object
|
||||
|
||||
- [Path.addClass](/reference/api/path/addclass)
|
||||
- [Path.addText](/reference/api/path/addtext)
|
||||
- [Path.hide](/reference/api/path/hide)
|
||||
- [Path.setClass](/reference/api/path/setclass)
|
||||
- [Path.setText](/reference/api/path/settext)
|
||||
- [Path.setHidden](/reference/api/path/sethidden)
|
||||
- [Path.smurve](/reference/api/path/smurve)
|
||||
- [Path.smurve_](/reference/api/path/smurve_)
|
||||
- [Path.unhide](/reference/api/path/unhide)
|
||||
|
||||
#### On the `Pattern` object
|
||||
|
||||
- [Pattern.addPart](/reference/api/pattern/addPart)
|
||||
- [Pattern.getConfig](/reference/api/pattern/getConfig)
|
||||
|
||||
|
||||
new:
|
||||
- point.addCircle
|
||||
- point.addText
|
||||
- point.setCircle
|
||||
- point.setText
|
||||
#### On the `Point` object
|
||||
|
||||
- [Point.addCircle](/reference/api/point/addcircle)
|
||||
- [Point.addText](/reference/api/point/addtext)
|
||||
- [Point.setCircle](/reference/api/point/setcircle)
|
||||
- [Point.setText](/reference/api/point/settext)
|
||||
|
||||
#### On the `Store` object
|
||||
|
||||
- [Store.extend](/reference/api/store/extend)
|
||||
- [Store.push](/reference/api/store/push)
|
||||
- [Store.remove](/reference/api/store/remove)
|
||||
|
||||
## Changes for developers
|
||||
|
||||
- FreeSewing is now ESM-only
|
||||
- We use named exports instead of default experts
|
||||
- We've switched from Rollup to Esbuild for our bundler
|
||||
- FreeSewing v3 requires NodeJS 16 or more recent
|
||||
|
||||
<Fixme compact>This guide is a work in process</Fixme>
|
||||
|
|
96
markdown/dev/guides/v3/migration/en.md
Normal file
96
markdown/dev/guides/v3/migration/en.md
Normal file
|
@ -0,0 +1,96 @@
|
|||
---
|
||||
title: V3 migration guide
|
||||
---
|
||||
|
||||
This guide covers the migration from FreeSewing version 2 (v2) to FreeSewing
|
||||
version 3 (v3). It is intended for pattern designers and developers using our
|
||||
core library. But it is also a good source of information for anybody who wants
|
||||
to learn more about what's changed between v2 and v3 of FreeSewing.
|
||||
|
||||
The focus on this guide is on our core library, our designs, our monorepo, and other topics of interest to developers.
|
||||
It does not cover any changes to our website(s) or other more user-facing aspects.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
### EMS only
|
||||
|
||||
FreeSewing is now ESM only. We no longer publish CJS modules.
|
||||
|
||||
To make this explicit, we now use `.mjs` as file extention for our source code.
|
||||
|
||||
### Named exports only
|
||||
|
||||
All our published packages now have only named exports, and no longer any default exports.
|
||||
|
||||
Please refer to [the reference documentation](/reference/api/core) to see what named exports are available.
|
||||
|
||||
### NodeJS 16 or more recent
|
||||
|
||||
FreeSewing now requires NodeJS version 16 or more recent.
|
||||
|
||||
<Note compact>This does not apply if you're using FreeSewing exclusively in the browser.</Note>
|
||||
|
||||
### Removed packages
|
||||
|
||||
The following packages have been removed in v3:
|
||||
|
||||
- @freesewing/pattern-info
|
||||
- gatsby-remark-jargon: We no longer use gatsby
|
||||
- remark-jargon: Use rehype-jargon instead
|
||||
- @freesewing/mui-theme: We no longer use Material-UI
|
||||
- @freesewing/css-theme: We now use TailwindCSS
|
||||
- @freesewing/components: These were depending on Material-UI and we no longer use it
|
||||
- @freesewing/utils: We no longer use these, or they are included elsewhere
|
||||
- @freesewing/plugin-export-dxf: DXF is kinda garbage, you deserve better
|
||||
- @freesewing/plugin-validate
|
||||
|
||||
## Migrating designs
|
||||
|
||||
### Design configuration
|
||||
|
||||
In v2, a design had its own confifuration which contained all the info about the design.
|
||||
In v3, all of that is migrated to the part level. A design is now merely a container of parts, but also allows you to pass in additional data:
|
||||
|
||||
```js
|
||||
import { Design } from '@freesewing/core' // Note: named export
|
||||
import { myPart1, myPart2 } from './parts.mjs'
|
||||
|
||||
export const MyDesign = new Design({
|
||||
parts: [ myPart1, myPart2 ],
|
||||
data: {
|
||||
anything: 'goes',
|
||||
this: {
|
||||
is: ['here', 'to', 'use' ]
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You pass the Design contructor a single object where the only required property is the `parts` key that holds an array of part objects.
|
||||
The `data` property is optional, and allows you to add data/information to the design that you can use to facilitate frontend integration or a host of other things. Anything under `data` will be made available in the pattern store.
|
||||
|
||||
Obviously, we still need to know what measurements the design requires, what plugins it uses, what options it offers, and so on.
|
||||
|
||||
All of that is now configured at the part level.
|
||||
|
||||
### Part configuration
|
||||
|
||||
In v3 of FreeSewing __all__ configuration happens at the part level.
|
||||
|
||||
Refer to [the part configuration docs](/reference/api/part/config) for details on configuring parts.
|
||||
|
||||
Apart from being attached at the part level, changes in comparison to v2 include:
|
||||
|
||||
- The `name` property is mandatory in v3
|
||||
- The `dependencies` property v2 is named `after` in v3
|
||||
- The `inject` property in v2 is named `from` in v3
|
||||
- The `hide` property in v2 is now one of `hide`, `hideDependencies`, or `hideAll`
|
||||
- The `plugins` property is new
|
||||
|
||||
### File and directory structure changes
|
||||
|
||||
- We no longer use a `config` folder, instead keep the config next to the parts.
|
||||
- We use `.mjs` extentions rather than `.js`
|
||||
|
||||
<Fixme compact>This guide is a work in process</Fixme>
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
---
|
||||
title: dependencies
|
||||
---
|
||||
|
||||
The `dependencies` key in the pattern configuration file allow you to configure
|
||||
dependencies between different parts of your pattern.
|
||||
For example, you may only be able to draft the sleeve after having drafted the
|
||||
part that contains the armhole the sleeve should fit in.
|
||||
|
||||
Dependencies control the order in which parts get drafted, but are also used
|
||||
when users requests to [only draft some parts of a
|
||||
pattern](/reference/api/settings/only).
|
||||
Behind the scenes, FreeSewing will draft all dependencies, and make sure to not
|
||||
render them if they were not requested.
|
||||
|
||||
## Structure
|
||||
|
||||
A plain object of `key`-`value` pairs that controls the order in which pattern
|
||||
parts will get drafted.
|
||||
The value can either be a string, or an array of strings.
|
||||
Those strings should be part names.
|
||||
|
||||
You read the configuration as: `key` depends on `value`.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
dependencies: {
|
||||
front: "back",
|
||||
sleeveplacket: ["sleeve", "cuff"]
|
||||
}
|
||||
```
|
||||
|
||||
In this example:
|
||||
|
||||
- The `front` part depends on the `back` part
|
||||
- The `sleeveplacket` part depends on the `sleeve` and `cuff` parts.
|
||||
|
||||
<Tip>
|
||||
|
||||
See [Part dependencies](/advanced/dependencies) for more in-depth information on dependencies.
|
||||
|
||||
</Tip>
|
|
@ -1,38 +0,0 @@
|
|||
---
|
||||
title: Pattern configuration file
|
||||
---
|
||||
|
||||
The pattern configuration file holds a variety of information about the
|
||||
pattern, its various parts, what measurements it requires, the options it
|
||||
accepts and so on.
|
||||
|
||||
It is part of the initial design and as such static in nature.
|
||||
|
||||
<Note>
|
||||
|
||||
This is about the pattern configuration file, used at build-time.
|
||||
|
||||
For run-time configuration, see [Pattern settings](/reference/api/settings).
|
||||
|
||||
</Note>
|
||||
|
||||
## Structure
|
||||
|
||||
The pattern configuration is a plain object with one or more of the following
|
||||
properties:
|
||||
|
||||
<ReadMore />
|
||||
|
||||
## Example
|
||||
|
||||
Below is a minimal example. Look at [the Aaron config file][aaron] for a full example.
|
||||
|
||||
```js
|
||||
const config = {
|
||||
version: '0.0.1',
|
||||
name: "sorcha",
|
||||
// More configuration here
|
||||
}
|
||||
```
|
||||
|
||||
[aaron]: https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/aaron/config/index.js
|
|
@ -1,26 +0,0 @@
|
|||
---
|
||||
title: hide
|
||||
---
|
||||
|
||||
The `hide` key in the pattern configuration file allow you to configure
|
||||
parts that should be hidden by default.
|
||||
_Hidden_ means that they will be drafted, but not rendered. This is
|
||||
typically used for a base part on which other parts are built.
|
||||
|
||||
Note that hidden parts will be rendered when the user requests
|
||||
to [only draft some parts of a pattern](/reference/api/settings/only)
|
||||
and includes the hidden part(s).
|
||||
|
||||
## Structure
|
||||
|
||||
An array of strings that holds part names.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
hide: [
|
||||
"base"
|
||||
]
|
||||
```
|
||||
|
||||
In the configuration above, the `base` part will be hidden by default.
|
|
@ -1,30 +0,0 @@
|
|||
---
|
||||
title: inject
|
||||
---
|
||||
|
||||
The `inject` key in the pattern configuration file allow you to configure
|
||||
the rules for injecting one part into another.
|
||||
By _injecting_ we mean that rather than starting out with a fresh part,
|
||||
you'll get a part that has the points, paths, and snippets of the injected part.
|
||||
|
||||
## Structure
|
||||
|
||||
A plain object of key/value pairs of parts.
|
||||
The `value` part will be injected in the `key` part.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
inject: {
|
||||
front: "back"
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the `back` part will be injected in the `front` part.
|
||||
In doing so, the `front` part will start out as a copy of the `back` part.
|
||||
|
||||
<Tip>
|
||||
|
||||
See [the Howto on Part inheritance](/howtos/code/inject) for a hands-on example.
|
||||
|
||||
</Tip>
|
|
@ -1,38 +0,0 @@
|
|||
---
|
||||
title: measurements
|
||||
---
|
||||
|
||||
The `measurements` key in the pattern configuration file allows you to configure
|
||||
the measurments that are required to draft the pattern.
|
||||
|
||||
## Structure
|
||||
|
||||
An array of strings where the strings are the names of the measurements
|
||||
required to draft this pattern.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
measurements: [
|
||||
"bicepsCircumference",
|
||||
"centerBackNeckToWaist"
|
||||
]
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
###### Don't just make up names
|
||||
|
||||
See [freesewing models](https://freesewing.dev/reference/packages/models)
|
||||
for a list of measurement names already used in freesewing patterns.
|
||||
It is a [best practice](/guides/best-practices/reuse-measurements/) to stick to these names.
|
||||
|
||||
</Note>
|
||||
|
||||
<Related>
|
||||
|
||||
This configuration is for **required measurements** only.
|
||||
There is a also a way to configure [optional
|
||||
measurements](/reference/api/config/optionalmeasurements)
|
||||
|
||||
</Related>
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
title: name
|
||||
---
|
||||
|
||||
The `name` key in the pattern configuration holds the name of your design.
|
||||
|
||||
## Structure
|
||||
|
||||
The value should hold a string that is also a [valid NPM package
|
||||
name](https://github.com/npm/validate-npm-package-name).
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
name: "sorcha"
|
||||
```
|
||||
|
||||
In this example, the pattern is named **sorcha**.
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
title: optionalMeasurements
|
||||
---
|
||||
|
||||
The `optionalMeasurements` key in the pattern configuration file allows
|
||||
you to configure measurements that are optional to draft the pattern.
|
||||
|
||||
## Structure
|
||||
|
||||
An array of strings where the strings are the names of the optional
|
||||
measurements.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
optionalMeasurements: [
|
||||
'highBust'
|
||||
]
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
###### Why would you want optional measurements?
|
||||
|
||||
This is often used in combination with [the bust plugin](/reference/plugins/bust/) to
|
||||
allow a pattern to be drafted to the `highBust` measurement rather than the
|
||||
`chest` measurement, thereby providing better fit for people with breasts.
|
||||
|
||||
</Note>
|
|
@ -1,64 +0,0 @@
|
|||
---
|
||||
title: optionGroups
|
||||
---
|
||||
|
||||
Option groups allow you to group options together when presenting them
|
||||
to the user. They also support (one) level of sub-grouping which is
|
||||
useful when your design has many options.
|
||||
|
||||
<Note>
|
||||
|
||||
##### This section applies to frontend integration
|
||||
|
||||
When you use FreeSewing patterns via the API -- in a backend NodeJS system
|
||||
or on the command line for example -- all options can be used.
|
||||
|
||||
The conditional display of options is intended for frontend integration.
|
||||
It is what's used on FreeSewing.org and our development environment alike, but
|
||||
it is not intended as a way to block access to a given option. It merely hides it.
|
||||
|
||||
</Note>
|
||||
|
||||
## Structure
|
||||
|
||||
Option groups are stored under the `optionGroups` key in the pattern
|
||||
configuration file.
|
||||
|
||||
They hold a plain object where each property can hold:
|
||||
|
||||
- An array of strings that are the names of the options to include in the group
|
||||
- A plain object whose properties hold an array of strings that are the names
|
||||
of the options to include in the group. (this creates a subgroup)
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
optionGroups: {
|
||||
fit: [
|
||||
'chestEase',
|
||||
'waistEase',
|
||||
],
|
||||
style: [
|
||||
'cuffStyle',
|
||||
'hemStyle',
|
||||
{
|
||||
collar: [
|
||||
'collarHeight',
|
||||
'collarShape'
|
||||
]
|
||||
}
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
The configuration above will create the following structure:
|
||||
|
||||
- **fit**
|
||||
- `chestEase`
|
||||
- `waistEase`
|
||||
- **style**
|
||||
- `cuffStyle`
|
||||
- `hemStyle`
|
||||
- **collar**
|
||||
- `collarHeight`
|
||||
- `collarShape`
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
title: boolean
|
||||
---
|
||||
|
||||
For options where the choice is either `true` or `false`, **on** or **off**,
|
||||
or **yes** or **no**, use a boolean option.
|
||||
|
||||
## Structure
|
||||
|
||||
A boolean option is a plain object with these properties:
|
||||
|
||||
- `bool` : Either `true` or `false` which will be the default
|
||||
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
|
||||
|
||||
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
withLining: {
|
||||
bool: true
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,36 +0,0 @@
|
|||
---
|
||||
title: constant
|
||||
---
|
||||
|
||||
If your option is a scalar value (like a string or a number),
|
||||
it will be treated as a constant. Constant options are never
|
||||
exposed in the frontend, but can still be set when using FreeSewing
|
||||
via the API.
|
||||
|
||||
## Structure
|
||||
|
||||
Any option holding a scalar value is a constant option.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
collarFactor: 4.8,
|
||||
fitCollar: false,
|
||||
}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
##### Why would you use this?
|
||||
|
||||
There are typically two use-cases for constant options:
|
||||
|
||||
- Rather than define constants in your code, it's good practice to set
|
||||
them in your configuration file. This way, people who extend your
|
||||
pattern can change them if they would like to.
|
||||
- A constant option can be used as a feature-flag. Enabling or disabling
|
||||
parts of the code beyond the control of the end user, but accessible to
|
||||
developers.
|
||||
|
||||
</Tip>
|
|
@ -1,29 +0,0 @@
|
|||
---
|
||||
title: counter
|
||||
---
|
||||
|
||||
For a given number of things, use a counter option.
|
||||
Counters are for integers only. Things like number of buttons and so on.
|
||||
|
||||
## Structure
|
||||
|
||||
Your counter option should be a plain object with these properties:
|
||||
|
||||
- `count` : The default integer value
|
||||
- `min` : The minimal integer value that's allowed
|
||||
- `max` : The maximum integer value that's allowed
|
||||
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
|
||||
|
||||
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
butttons: {
|
||||
count: 7,
|
||||
min: 4,
|
||||
max: 12
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
title: degrees
|
||||
---
|
||||
|
||||
For angles, use a degree option.
|
||||
|
||||
## Structure
|
||||
|
||||
Your degree option should be a plain object with these properties:
|
||||
|
||||
- `deg` : The default value in degrees
|
||||
- `min` : The minimul that's allowed
|
||||
- `max` : The maximum that's allowed
|
||||
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
|
||||
|
||||
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
collarAngle: {
|
||||
deg: 85,
|
||||
min: 60
|
||||
max: 130
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,140 +0,0 @@
|
|||
---
|
||||
title: options
|
||||
---
|
||||
|
||||
The design options stored under the `options` key in the pattern configuration
|
||||
file give designers flexility to make one pattern with different variations.
|
||||
|
||||
## The use case for (design) options
|
||||
|
||||
One of the things that sets FreeSewing apart is that sewing patterns are not
|
||||
static. Each pattern is generated on the spot to accommodate the input
|
||||
provided by the user. Input that typically includes their measurments.
|
||||
|
||||
This _made-to-measure_ approach is sort of _our thing_ at FreeSewing,
|
||||
but why stop there?
|
||||
There's a lot of things that can be left up to the user and taken into
|
||||
consideration when drafting the pattern. Things like how many buttons to use,
|
||||
whether or not to include pockets, shape of the collar, and so on. The only
|
||||
limit really is the creativity of the designer.
|
||||
|
||||
The `options` section in a pattern's configuration file is what makes this
|
||||
possible.
|
||||
|
||||
## The five option types you should know
|
||||
|
||||
There are the five option types that an aspiring pattern designer should be
|
||||
familiar with:
|
||||
|
||||
1. [**boolean** options][bool] are for yes/no choices
|
||||
2. [**counter** options][count] are for integer values
|
||||
3. [**degree** options][deg] are for degrees
|
||||
4. [**list** options][list] are for a list of possible choices
|
||||
5. [**percentage** options][pct] are for percentages
|
||||
|
||||
<Tip>
|
||||
|
||||
In parametric design, percentage options are by far the most common.
|
||||
They also have the most features and flexibility.
|
||||
|
||||
</Tip>
|
||||
|
||||
<Related>
|
||||
|
||||
For the sake of completeness, here are the two other types of options:
|
||||
|
||||
6. [**constant** options][const] are used as
|
||||
[feature flags](https://en.wikipedia.org/wiki/Feature_toggle)
|
||||
7. [**millimeter** options][const] are **deprecated** (in favor of [snapped
|
||||
percentage options][snapped])
|
||||
|
||||
</Related>
|
||||
|
||||
## Features all five option types share
|
||||
|
||||
The five options types listed above (and the millimeter option to be complete)
|
||||
share the following features:
|
||||
|
||||
### Default value
|
||||
|
||||
Each option has a default value. If the user does not specify a preference
|
||||
the default value is what will be used to draft the pattern.
|
||||
|
||||
<Note>
|
||||
|
||||
How you configure the default value depends on the option type
|
||||
|
||||
</Note>
|
||||
|
||||
### Optionally hide options by configuring a `hide()` method
|
||||
|
||||
<Note>
|
||||
|
||||
##### This section applies to frontend integration
|
||||
|
||||
When you use FreeSewing patterns via the API -- in a backend NodeJS system
|
||||
or on the command line for example -- all options can be used.
|
||||
|
||||
The conditional display of options is intended for frontend integration.
|
||||
It is what's used on FreeSewing.org and our development environment alike, but
|
||||
it is not intended as a way to block access to a given option. It merely hides it.
|
||||
|
||||
</Note>
|
||||
|
||||
By default options are shown to the user when:
|
||||
|
||||
- They are not a constant option
|
||||
- **and**
|
||||
- They are included in an optionGroup
|
||||
|
||||
You can further control the optional display of options by adding a method
|
||||
to the `hide` key under you option, as such:
|
||||
|
||||
```js
|
||||
myOption: {
|
||||
pct: 50,
|
||||
min: 0,
|
||||
max: 100,
|
||||
hide: function(settings) {
|
||||
if (settings.measurments.chest > 100) return true
|
||||
else return false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Your `hide` method will receive one parameter that holds the run-time confguration
|
||||
of your pattern, which we typically refer to as [the settings](/reference/api/settings).
|
||||
|
||||
It contains among other things all measurements and options chosen by the user.
|
||||
So you can make a choice whether to show the option or not.
|
||||
|
||||
If it's not obvious from the name, your `hide()` method you should:
|
||||
|
||||
- Return `true` or a truthy value to hide the option
|
||||
- Return `false` or a falsy value to show the option
|
||||
|
||||
<Tip>
|
||||
|
||||
##### A `hide()` method is always present on your option
|
||||
|
||||
If you do not specify a `hide()` method, it will be populated with the default
|
||||
`hide()` method -- which always returns `false` thus always showing the option.
|
||||
|
||||
In other words, the `hide()` option is always there and will always get called
|
||||
to determine whether an option should be shown or not.
|
||||
|
||||
</Tip>
|
||||
|
||||
[bool]: /reference/api/config/options/bool
|
||||
|
||||
[const]: /reference/api/config/options/const
|
||||
|
||||
[count]: /reference/api/config/options/counter
|
||||
|
||||
[deg]: /reference/api/config/options/deg
|
||||
|
||||
[list]: /reference/api/config/options/list
|
||||
|
||||
[pct]: /reference/api/config/options/pct
|
||||
|
||||
[snapped]: /reference/api/config/options/pct/snap
|
|
@ -1,76 +0,0 @@
|
|||
---
|
||||
title: list
|
||||
---
|
||||
|
||||
Use a list option when you want to offer an array of choices.
|
||||
|
||||
## Structure
|
||||
|
||||
Your list option should be a plain object with these properties:
|
||||
|
||||
- `dflt` : The default for this option
|
||||
- `list` : An array of available values options
|
||||
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
|
||||
|
||||
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
cuffStyle: {
|
||||
dflt: "angledBarrelCuff",
|
||||
list: [
|
||||
"roundedBarrelCuff",
|
||||
"angledBarrelCuff"
|
||||
"straightBarrelCuff"
|
||||
"roundedFrenchCuff"
|
||||
"angledFrenchCuff"
|
||||
"straightFrenchCuff"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Suppress translation
|
||||
|
||||
In the example above, you want the different `list` options to be translated.
|
||||
But sometimes, there is no need for that, like in this example from Breanna:
|
||||
|
||||
```js
|
||||
options: {
|
||||
primaryBustDart: {
|
||||
list: [
|
||||
'06:00',
|
||||
'07:00',
|
||||
'08:00',
|
||||
'09:00',
|
||||
'10:00',
|
||||
'11:00',
|
||||
'11:30',
|
||||
'12:00',
|
||||
'12:30',
|
||||
'13:00',
|
||||
'13:30',
|
||||
'14:00',
|
||||
'15:00',
|
||||
'16:00',
|
||||
'17:00',
|
||||
],
|
||||
dflt: '06:00',
|
||||
doNotTranslate: true,
|
||||
},
|
||||
// More here
|
||||
}
|
||||
```
|
||||
|
||||
As you can see above, you can set the `doNotTranslate` property to `true` and to indicate this.
|
||||
|
||||
<Note>
|
||||
|
||||
##### This is not a core feature
|
||||
|
||||
To be clear, setting this here does not do anything in core. It's merely extra
|
||||
metadata you can add on the option to facilitate frontend integration.
|
||||
|
||||
</Note>
|
|
@ -1,52 +0,0 @@
|
|||
---
|
||||
title: millimeter
|
||||
---
|
||||
|
||||
While FreeSewing supports millimeter options, we recommend
|
||||
using [percentage options][1] and will not accept
|
||||
contributions that use millimeter options.
|
||||
|
||||
## Structure
|
||||
|
||||
A millimeter option should be a plain object with these properties:
|
||||
|
||||
- `mm` : The default value in millimeter
|
||||
- `min` : The minimul that's allowed
|
||||
- `max` : The maximum that's allowed
|
||||
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
|
||||
|
||||
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
elasticWidth: {
|
||||
mm: 35,
|
||||
min: 5,
|
||||
max: 80
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Comment by="joost">
|
||||
|
||||
##### What's wrong with millimeter options?
|
||||
|
||||
Millimeter options do not scale.
|
||||
Parametric design is the _raison d'être_ of FreeSewing and that core belief
|
||||
that things should seamlessly adapt goes out the window when you use a `mm`
|
||||
option because now you have a value that will not change based on the
|
||||
input measurements.
|
||||
|
||||
You could argue that it's fine because _you can just lower the option_
|
||||
but that breaks the principle of _sensible defaults_ (aka no surprises).
|
||||
The fact that you can sidestep the bullet does not mean you're not creating
|
||||
a footgun.
|
||||
|
||||
When you need a millimeter option, reach for a [snapped
|
||||
percentage option][1] instead.
|
||||
|
||||
</Comment>
|
||||
|
||||
[1]: /reference/api/config/options/pct
|
|
@ -1,63 +0,0 @@
|
|||
---
|
||||
title: percentage
|
||||
---
|
||||
|
||||
Percentage options are the bread and butter of freesewing.
|
||||
Almost all your options will most likely be percentage options as
|
||||
they ensure that your pattern will scale regardless of size.
|
||||
|
||||
## Structure
|
||||
|
||||
Your percentage option should be a plain object with these properties:
|
||||
|
||||
- `pct` : The default percentage
|
||||
- `min` : The minimum percentage that's allowed
|
||||
- `max` : The maximum percentage that's allowed
|
||||
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
|
||||
- `fromAbs` <small>(optional)</small> : A method to [determine the percentage based on a value in millimeter][fromabs]
|
||||
- `toAbs` <small>(optional)</small> : A method to [return the option value in millimeter][toabs]
|
||||
- `snap` <small>(optional)</small> : The configuration to control [snapping of percentage options][snap]
|
||||
|
||||
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
|
||||
|
||||
[fromabs]: /reference/api/config/options/pct/fromabs
|
||||
|
||||
[toabs]: /reference/api/config/options/pct/toabs
|
||||
|
||||
[snap]: /reference/api/config/options/pct/snap
|
||||
|
||||
<Note>
|
||||
|
||||
###### Percentage options will be divided by 100 when loaded
|
||||
|
||||
You specify percentages in your config file. For example, `50` means 50%.
|
||||
When your configuration is loaded, those percentages will be divided by 100.
|
||||
|
||||
So a percentage of `50` in your config file will be `0.5` when you read out that option in your pattern.
|
||||
|
||||
###### Percentage options are not limited to the range 0-100
|
||||
|
||||
The minimum and maximum (and default) percentages are not restricted to the range from `0%` to `100%`.
|
||||
A percentage option that spans from `-25%` to `135%` is just as valid.
|
||||
|
||||
</Note>
|
||||
|
||||
## Example
|
||||
|
||||
Below is a simple example:
|
||||
|
||||
```js
|
||||
options: {
|
||||
acrossBackFactor: {
|
||||
pct: 97,
|
||||
min: 93,
|
||||
max: 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced use
|
||||
|
||||
Percentage options have a few more tricks up their sleeve:
|
||||
|
||||
<ReadMore />
|
|
@ -1,97 +0,0 @@
|
|||
---
|
||||
title: Setting a value in millimeter as a percentage option
|
||||
---
|
||||
|
||||
Percentage options are great for parametric desing, but not always
|
||||
very intuitive for the user. For example: A user may desire 13
|
||||
centimeters (5 inches) of chest ease. But what percentage should
|
||||
they set the `chestEase` option to to accomplish this?
|
||||
|
||||
To address this common grievance, FreeSewing allows you to add a
|
||||
`fromAbs` method that should take a value in millimeter and
|
||||
return the percentage the option should be set to to result in this
|
||||
value.
|
||||
|
||||
<Note>
|
||||
|
||||
Note that this method will not change the percentage of the option.
|
||||
It will merely return return a percentage value. It is up to the
|
||||
frontend designer to then either set this value, or suggest it to
|
||||
the user.
|
||||
|
||||
</Note>
|
||||
|
||||
## Structure
|
||||
|
||||
The `fromAbs` property should hold a function with the following
|
||||
signature:
|
||||
|
||||
```js
|
||||
function toAbs(millimeter, settings) {
|
||||
// return a percentage here (0.5 is 50%)
|
||||
}
|
||||
```
|
||||
|
||||
The first parameter is the desired value in millimeter (for example
|
||||
`130` for `13cm`).
|
||||
The second parameter is the pattern's run-time configuration
|
||||
or [settings](/reference/api/settings) which holds -- among other things -- the
|
||||
measurements provided by the user.
|
||||
|
||||
## Example
|
||||
|
||||
In our example above, let's say that the `chestEase` option is
|
||||
a simple percentage of the `chest` measurement. Our option
|
||||
configuration could like like this:
|
||||
|
||||
```js
|
||||
chestEase: {
|
||||
pct: 8,
|
||||
min: 0,
|
||||
max: 20,
|
||||
fromAbs: function(millimeter, settings) {
|
||||
return millimeter / settings.measurements.chest
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With object destructuring and fat-arrow notation,
|
||||
you can write it a bit terser like this:
|
||||
|
||||
```js
|
||||
fromAbs: (val, { measurements }) => val /measurements.chest
|
||||
```
|
||||
|
||||
## Using pctBasedOn for simple measurement fractions
|
||||
|
||||
Many percentage options represent a simple fraction of a measurement
|
||||
(chest circumference in the example above).
|
||||
|
||||
As this scenario is so common, `@freesewing/core` exports a `pctBasedOn` method
|
||||
that will do the work for you:
|
||||
|
||||
```js
|
||||
// First import the method
|
||||
import { pctBasedOn } from '@freesewing/core'
|
||||
|
||||
const config = {
|
||||
// ...
|
||||
options: {
|
||||
chestEase: {
|
||||
pct: 8,
|
||||
min: 0,
|
||||
max: 20,
|
||||
// Pass the measurement name as parameter
|
||||
// and spread the return value into your option
|
||||
...pctBasedOn('chest')
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will not only add an `fromAbs()` method to your option --
|
||||
one that will return the percentage of any millimeter value passed into it --
|
||||
it will also add a `toAbs()` method that does the inverse: return the
|
||||
value in millimeter of whatever percentage the option is set to.
|
||||
See [Reporting a percentage option value in
|
||||
millimeter](/reference/api/config/options/pct/toabs) for details.
|
|
@ -1,244 +0,0 @@
|
|||
---
|
||||
title: Snapped percentage options
|
||||
---
|
||||
|
||||
Snapped percentage options are a hybrid between [list options][list] and
|
||||
[percentage options][pct]. By combining traits of both, they create a
|
||||
sort of _smart list option_ that will select the most appropriate value
|
||||
from the list, and also allow a pure parametric value if no close match
|
||||
is found.
|
||||
|
||||
## Structure
|
||||
|
||||
Your snapped percentage option should be a plain object with these properties:
|
||||
|
||||
- `pct` : The default percentage
|
||||
- `min` : The minimum percentage that's allowed
|
||||
- `max` : The maximum percentage that's allowed
|
||||
- `snap`: Holds the snap configuration (see [Snap configuration](#))
|
||||
- `toAbs`: a method returning the **millimeter value** of the option ([see `toAbs()`][toabs])
|
||||
- `hide` <small>(optional)</small> : A method to [control the optional display of the option][hide]
|
||||
|
||||
## Snap configuration
|
||||
|
||||
A snapped percentage option requires a `snap` property that will determine
|
||||
what values to snap to.
|
||||
|
||||
There are three different scenarios:
|
||||
|
||||
### snap holds a number
|
||||
|
||||
When `snap` holds a number, the option will be _snapped_ to a
|
||||
multiple of this value.
|
||||
|
||||
In the example below, the absolute value of this option will be set to a multiple of `7`
|
||||
(so one of `7`, `14`, `21`, `28`, `35`, ...).
|
||||
|
||||
```js
|
||||
myOption: {
|
||||
pct:5,
|
||||
min: 0
|
||||
max: 35,
|
||||
snap: 7,
|
||||
toAbs: (pct, { measurements }) => measurements.waistToFloor * pct
|
||||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
In a case like this, the value will **always** be snapped,
|
||||
because the snap points will be distributed equally across the entire range
|
||||
of all possible inputs.
|
||||
|
||||
</Note>
|
||||
|
||||
### snap holds an array of numbers
|
||||
|
||||
When snap holds an array of numbers, the option will be _snapped_ to one of
|
||||
the numbers unless it's further away than half the distance to its closest neighbor.
|
||||
|
||||
In the example below, if the absolute value returned by `toAbs()` is in the
|
||||
region of influence -- in this example between 4.5 and 69.5 -- the nearest snap value
|
||||
will be used. If instead it is outside the region of influence, the result of
|
||||
`toAbs()` will be uses as-is.
|
||||
|
||||
```js
|
||||
myOption: {
|
||||
pct:5,
|
||||
min: 0
|
||||
max: 35,
|
||||
snap: [7, 12, 21, 34, 53, 64 ]
|
||||
toAbs: (pct, { measurements }) => measurements.waistToFloor * pct
|
||||
}
|
||||
```
|
||||
|
||||
### snap is a plain object with `metric` and `imperial` properties that each hold an array of numbers
|
||||
|
||||
In this case, the behavior is exaxtle the same as when `snap` holds an array
|
||||
of numbers.
|
||||
|
||||
The differnce is that this allows you to supply a different list of snap values
|
||||
for users using metric or imperial units.
|
||||
|
||||
In the example below, the value of [settings.units](/api/settings/units) will
|
||||
determine which list of snap values gets used.
|
||||
|
||||
Then, if the absolute value returned by `toAbs()` is in the
|
||||
region of influence -- in this example between 4.5 and 69.5 -- the nearest snap value
|
||||
will be used. If instead it is outside the region of influence, the result of
|
||||
`toAbs()` will be uses as-is.
|
||||
|
||||
```js
|
||||
myOption: {
|
||||
pct:5,
|
||||
min: 0
|
||||
max: 35,
|
||||
snap: {
|
||||
metric: [7, 12, 21, 34, 53, 64 ],
|
||||
imperial: [25.4, 50.8, 76.3 ],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Comment by="joost">
|
||||
|
||||
##### Read on for an in-depth look at snapped percentage options
|
||||
|
||||
While this information above tells you how to use snapped percentage options,
|
||||
it does not explain why or when you should use them, or how they work.
|
||||
|
||||
Read on if you'd like to learn more about that.
|
||||
|
||||
</Comment>
|
||||
|
||||
## Example use-case
|
||||
|
||||
To understand the need that snapped percentage options are addressing,
|
||||
we'll use an example use-case: We'll be designing a pajama pants pattern
|
||||
with an elasticated waist.
|
||||
|
||||
In our design, the `waistbandWidth` option should match the width of the
|
||||
elastic we're going to use so we can construct the waistband accordingly.
|
||||
|
||||
We have a few different ways we can approach this:
|
||||
|
||||
### Approach A: We use a percentage option
|
||||
|
||||
We use a percentage option based on a vertical measurement, like
|
||||
`waistToFloor`.
|
||||
|
||||
The elastic width people end up with is something like 34.12mm for
|
||||
user A and 27.83mm for user B.
|
||||
|
||||
Those are not widths for sale in the store, so that's not great.
|
||||
|
||||
### Approach B: We use a list option
|
||||
|
||||
We use a list option with a selection of standard elastic
|
||||
widths to choose from: from half and inch to 3 inches
|
||||
in 0.5 inch increments.
|
||||
|
||||
User A is a doll enthusiasts and 0.5 inch is too big.
|
||||
User B is working on a giant to go on a float in a parade, and 3 inch
|
||||
is way too small.
|
||||
|
||||
While it would probably work for most people somewhat in the middle,
|
||||
our solution does not scale.
|
||||
|
||||
### Approach C: We use a snapped percentage option
|
||||
|
||||
We combine approaches A and B and configure a snapped percentage option
|
||||
with:
|
||||
|
||||
- A percentage based on `waistToFloor`
|
||||
- Our list of standard elastic widths as _snaps_
|
||||
|
||||
For typical humans, our options will _snap_ to the closest match in our
|
||||
list and behave just like Approach A (with a list option).
|
||||
|
||||
For dolls and giants, the option will revert to the parametric value and
|
||||
behave just like Approach B (with a percentage option).
|
||||
|
||||
Sweet!
|
||||
|
||||
## How snapped percentage options work
|
||||
|
||||
Before we wade into the details, let's first agree on terminology:
|
||||
|
||||
- The **percentage value** is the page passed by the user for the option.
|
||||
Its value always represents a percentage.
|
||||
- The **millimeter value** is the result of feeding the **percentage value** to
|
||||
the `toAbs()` method. Its value always represents millimeters.
|
||||
- The **snap values** are the values provided by the snap confguration.
|
||||
Each of the values always represents millimeters.
|
||||
|
||||
Under the hood, and snapped percentage option will:
|
||||
|
||||
- Use `toAbs()` to calculate the **millimeter value** from the **percentage value**
|
||||
- See whether the **millimeter value** approaches one of the **snap values**
|
||||
- If so, use the snap value (in millimeter) as provided by one of the **snap values**
|
||||
- If not, use the **millimeter value** as-is
|
||||
|
||||
If you're head's spinning, here's an image that will hopefully clarify things a bit:
|
||||
|
||||

|
||||
|
||||
The gradient box represents the range of any given measurement,
|
||||
from dolls all the way on the left, to giants all the way on the right.
|
||||
The sort of middle green-colored region is what the designer had in mind
|
||||
when designing the pattern, and they have set up snap values -- marked by
|
||||
a red dot -- for values that they feel make sense.
|
||||
|
||||
The region of influence of any given snap point will extend 50% towards its
|
||||
neighbor on both sides (indicated by the dashed lines).This means that the
|
||||
region of snap points is continuous, once you're in, you're going to be
|
||||
snapped to one of the snap points.
|
||||
|
||||
However, when you venture out into the area where the designer did not
|
||||
configure any snap points, the absolute value will be used as-is, without
|
||||
snapping, just as it would in a normal percentage option.
|
||||
|
||||
This system results in the best of both worlds:
|
||||
|
||||
- Things like elastic widths and so on can be configured to be fixed values,
|
||||
of common elastic widths for example
|
||||
- The absolute value will still scale up and down, but will snap to the closest
|
||||
fixed value when appropriate.
|
||||
- When the input measurements go somewhere the designer did not anticipate,
|
||||
the option will just behave as a regular percentage option
|
||||
|
||||
## Using snapped percentage options in your pattern code
|
||||
|
||||
This is all well and good, but how do you use this?
|
||||
|
||||
Well, just like you can get the `options` object from our shorthand call,
|
||||
you can now get the `absoluteOptions` object that holds absolute values
|
||||
for those options with snaps configured.
|
||||
|
||||
In our paco example, what used to be:
|
||||
|
||||
```js
|
||||
store.set('ankleElastic', measurements.waistToFloor * options.ankleElastic)
|
||||
```
|
||||
|
||||
is now:
|
||||
|
||||
```js
|
||||
store.set('ankleElastic', absoluteOptions.ankleElastic)
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
There's really no added value in setting this in the store as `absoluteOptions`
|
||||
is available everywhere, but we've changed as little as possible in the example
|
||||
to clarify the difference.
|
||||
|
||||
</Note>
|
||||
|
||||
[toabs]: /reference/api/config/options/pct/toabs
|
||||
|
||||
[pct]: /reference/api/config/options/pct
|
||||
|
||||
[list]: /reference/api/config/options/list
|
||||
|
||||
[hide]: /reference/api/config/options#optionally-hide-options-by-configuring-a-hide-method
|
Binary file not shown.
Before Width: | Height: | Size: 54 KiB |
|
@ -1,86 +0,0 @@
|
|||
---
|
||||
title: Reporting a percentage option value in millimeter
|
||||
---
|
||||
|
||||
Percentage options are great for parametric desing, but not always
|
||||
very intuitive for the user. For example: Setting the `chestEase`
|
||||
option to `9%` is not very meaningful unless you happen to know
|
||||
what that percentage is based on.
|
||||
|
||||
To address this common grievance, FreeSewing allows you to add a
|
||||
`toAbs` method that should return the value of the option in
|
||||
millimeter.
|
||||
|
||||
## Structure
|
||||
|
||||
The `toAbs` property should hold a function with the following
|
||||
signature:
|
||||
|
||||
```js
|
||||
function toAbs(percentage, settings) {
|
||||
// return value in millimeter here
|
||||
}
|
||||
```
|
||||
|
||||
The first parameter is the percentage value provided by the user (for example
|
||||
`0.5` for `50%`).
|
||||
The second parameter is the pattern's run-time configuration
|
||||
or [settings](/reference/api/settings) which holds -- among other things -- the
|
||||
measurements provided by the user.
|
||||
|
||||
## Example
|
||||
|
||||
In our example above, let's say that the `chestEase` option is
|
||||
a simple percentage of the `chest` measurement. Our option
|
||||
configuration could like like this:
|
||||
|
||||
```js
|
||||
chestEase: {
|
||||
pct: 8,
|
||||
min: 0,
|
||||
max: 20,
|
||||
toAbs: function(value, settings) {
|
||||
return settings.measurements.chest * value
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
With object destructuring and fat-arrow notation,
|
||||
you can write it a bit terser like this:
|
||||
|
||||
```js
|
||||
toAbs: (val, { measurements }) => measurements.chest * val
|
||||
```
|
||||
|
||||
## Using pctBasedOn for simple measurement fractions
|
||||
|
||||
Many percentage options represent a simple fraction of a measurement
|
||||
(chest circumference in the example above).
|
||||
|
||||
As this scenario is so common, `@freesewing/core` exports a `pctBasedOn` method
|
||||
that will do the work for you:
|
||||
|
||||
```js
|
||||
// First import the method
|
||||
import { pctBasedOn } from '@freesewing/core'
|
||||
|
||||
const config = {
|
||||
// ...
|
||||
options: {
|
||||
chestEase: {
|
||||
pct: 8,
|
||||
min: 0,
|
||||
max: 20,
|
||||
// Pass the measurement name as parameter
|
||||
// and spread the return value into your option
|
||||
...pctBasedOn('chest')
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This will not only add an `toAbs()` method to your option -- one that will return
|
||||
the value in millimeter of whatever percentage the option is set to -- it will
|
||||
also add a `fromAbs()` method that does the inverse: return the percentage of
|
||||
any millimeter value passed into it. See [Setting a value in millimeter as a
|
||||
percentage option](/api/config/options/pct/fromabs) for details.
|
|
@ -1,30 +0,0 @@
|
|||
---
|
||||
title: parts
|
||||
---
|
||||
|
||||
The `parts` key in the pattern configuration file holds a list of
|
||||
names of pattern parts.
|
||||
|
||||
<Tip>
|
||||
|
||||
###### This does not need to be an exhaustive list of all parts in your pattern.
|
||||
|
||||
This list of parts is needed for the `draft()` method to figure out what
|
||||
parts need to be drafted.
|
||||
So if parts are included in the `dependencies`, `inject`, or `hide` configuration,
|
||||
there's no need to include them here, as we already know of their existence.
|
||||
|
||||
</Tip>
|
||||
|
||||
## Structure
|
||||
|
||||
An array of strings where the strings are part name.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
parts: [
|
||||
"front",
|
||||
"back"
|
||||
]
|
||||
```
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
title: code
|
||||
---
|
||||
|
||||
```js
|
||||
code: "Joost De Cock",
|
||||
```
|
||||
|
||||
The name of the developer.
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: department
|
||||
---
|
||||
|
||||
```js
|
||||
department: "menswear",
|
||||
```
|
||||
|
||||
One of the following:
|
||||
|
||||
- menswear
|
||||
- womenswear
|
||||
- unisex
|
||||
- accessories
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
title: design
|
||||
---
|
||||
|
||||
```js
|
||||
design: "Joost De Cock",
|
||||
```
|
||||
|
||||
The name of the designer.
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
title: difficulty
|
||||
---
|
||||
|
||||
```js
|
||||
difficulty: 3
|
||||
```
|
||||
|
||||
A `1` to `5` difficulty score that indicates how hard it is to make the pattern.
|
|
@ -1,13 +0,0 @@
|
|||
---
|
||||
title: UI configuration
|
||||
---
|
||||
|
||||
Patterns also take these configuration options to facilitate UI integration:
|
||||
|
||||
<ReadMore list />
|
||||
|
||||
<Tip>
|
||||
|
||||
UI = User Interface. Like a website or mobile app
|
||||
|
||||
</Tip>
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
title: The advanced option group
|
||||
---
|
||||
|
||||
Naming an option group `advanced` will hide it by default from the user
|
||||
unless they enable _expert mode_.
|
||||
|
||||
```js
|
||||
optionGroups: {
|
||||
fit: ["chestEase", "hipsEase", "stretchFactor"],
|
||||
style: ["armholeDrop", "backlineBend"],
|
||||
advanced: [ "plutoniumCount" ]
|
||||
}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
The `advanced` option group can also have nested groups
|
||||
|
||||
</Tip>
|
|
@ -1,28 +0,0 @@
|
|||
---
|
||||
title: optionGroups
|
||||
---
|
||||
|
||||
Organises your pattern options in groups.
|
||||
It expects an object where the key is the group title, and the value an array of options:
|
||||
|
||||
```js
|
||||
optionGroups: {
|
||||
fit: ["chestEase", "hipsEase", "stretchFactor"],
|
||||
style: [
|
||||
"armholeDrop",
|
||||
"backlineBend",
|
||||
"necklineBend",
|
||||
"necklineDrop",
|
||||
"shoulderStrapWidth",
|
||||
"shoulderStrapPlacement",
|
||||
"lengthBonus"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
Options that are not included in the `optionGroup` configuration won't be
|
||||
exposed in the frontend and thus will be unavailable to the user.
|
||||
|
||||
</Note>
|
|
@ -1,26 +0,0 @@
|
|||
---
|
||||
title: Nested option groups
|
||||
---
|
||||
|
||||
You can create sub-groups within an option group:
|
||||
|
||||
```js
|
||||
optionGroups: {
|
||||
style: [
|
||||
'hemStyle',
|
||||
'hemCurve',
|
||||
{
|
||||
closure: [
|
||||
'extraTopButton',
|
||||
'buttons',
|
||||
'buttonFreeLength'
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Only create subgroups one level deep.
|
||||
We do not support groups in groups in groups.
|
||||
</Warning>
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
title: tags
|
||||
---
|
||||
|
||||
```js
|
||||
tags: ["underwear", "top", "basics"],
|
||||
```
|
||||
|
||||
A set of tags to allow filtering of patterns on the website.
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
title: type
|
||||
---
|
||||
|
||||
```js
|
||||
type: "pattern",
|
||||
```
|
||||
|
||||
One of the following:
|
||||
|
||||
- pattern
|
||||
- block
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
title: version
|
||||
---
|
||||
|
||||
The `version` key in the pattern configuration holds the version
|
||||
of the pattern. For a pattern that is published as an NPM package
|
||||
this is typically the same version as set in the `package.json` file.
|
||||
|
||||
## Structure
|
||||
|
||||
A string that holds a valid semantic version number.
|
||||
|
||||
## Example
|
||||
|
||||
version: "0.3.1"
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
title: "@freesewing/core API"
|
||||
title: Core API
|
||||
---
|
||||
|
||||
This is the documentation for FreeSewing's core library, published as `@freesewing/core` on NPM.
|
||||
|
|
|
@ -67,6 +67,13 @@ It just so happens that in most cases, there will be only one settings object in
|
|||
|
||||
</Note>
|
||||
|
||||
## Pattern attributes
|
||||
|
||||
- `Pattern.designConfig`: Holds the design's configuration
|
||||
- `Pattern.patternConfig`: Holds the pattern's configuration
|
||||
- `Pattern.store`: Holds the pattern-wide Store
|
||||
- `Pattern.setStores`: Holds an array of stores, one for each set of settings.
|
||||
|
||||
## Pattern methods
|
||||
|
||||
<ReadMore list />
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
---
|
||||
title: complete
|
||||
---
|
||||
|
||||
The `complete` setting controls the level of details that's included on your pattern.
|
||||
This has different uses, such as generating patterns to be cut out with a laser cutter.
|
||||
|
||||
The default `complete` setting is `true`.
|
||||
Set this to `false` to draft a base outline of the pattern, rather than a fully detailed pattern.
|
||||
|
||||
<Note>
|
||||
Setting this to `false` will force [sa](/reference/api/settings/sa) to be set to `false`.
|
||||
</Note>
|
||||
|
||||
```js
|
||||
import Brian from "@freesewing/brian";
|
||||
|
||||
const pattern = new Brian({
|
||||
complete: false
|
||||
})
|
||||
```
|
|
@ -1,27 +0,0 @@
|
|||
---
|
||||
title: embed
|
||||
---
|
||||
|
||||
The `embed` setting controls the properties of the SVG document.
|
||||
Set it to `true` to make SVG output suitable for embedding in a web page.
|
||||
|
||||
The default for `embed` is `false` which will include the `width` and `height`
|
||||
attributes in the SVG tag, thereby making it suitable for printing.
|
||||
|
||||
When set to `true` the `width` and `height` attributes will not be added
|
||||
which allows you to inject the SVG into an HTML document, where it will
|
||||
responsively scale.
|
||||
|
||||
```js
|
||||
import Brian from "@freesewing/brian";
|
||||
|
||||
const pattern = new Brian({
|
||||
embed: true
|
||||
})
|
||||
```
|
||||
|
||||
<Warning>
|
||||
|
||||
Do **not** use this for SVGs you want to print.
|
||||
|
||||
</Warning>
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: Settings
|
||||
for: developers
|
||||
about: Documents all the settings your pattern can receive, including the pattern options, measurmeents, and design options
|
||||
---
|
||||
|
||||
Settings are what the user passes to your pattern at run-time.
|
||||
|
||||
Don't confuse them with the [pattern configuration](/reference/config/) that is determined by
|
||||
the designer at build-time.
|
||||
|
||||
Below are the supported settings:
|
||||
|
||||
<ReadMore list />
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
title: locale
|
||||
---
|
||||
|
||||
The `locale` setting allows you to specify the language of the pattern.
|
||||
It should contain a 2-letter language code that indicates what language the user wants.
|
||||
The default is `en`.
|
||||
|
||||
This will be used to set the `xml:lang` attribute in the `svg` tag when rendering to SVG,
|
||||
and by [the i18n plugin](/reference/plugins/i18n/) to translate the pattern.
|
||||
|
||||
```js
|
||||
import Brian from "@freesewing/brian";
|
||||
|
||||
const pattern = new Brian({
|
||||
locale: "es"
|
||||
})
|
||||
```
|
|
@ -1,18 +0,0 @@
|
|||
---
|
||||
title: measurements
|
||||
---
|
||||
|
||||
The `measurements` settings should hold and object with the
|
||||
measurements to draft the pattern for.
|
||||
The pattern configuration lists all required measurements.
|
||||
|
||||
```js
|
||||
import Brian from "@freesewing/brian";
|
||||
|
||||
const pattern = new Brian({
|
||||
measurements: {
|
||||
chestCircumference: 1080
|
||||
shoulderSlope: 55
|
||||
}
|
||||
})
|
||||
```
|
|
@ -1,17 +0,0 @@
|
|||
---
|
||||
title: only
|
||||
---
|
||||
|
||||
The `only` setting allows you to specify one or more parts to
|
||||
draft/render, rather than the entire pattern.
|
||||
|
||||
It accepts either a single part name as a string, or an array of
|
||||
one or more part names.
|
||||
|
||||
```js
|
||||
import Brian from "@freesewing/brian";
|
||||
|
||||
const pattern = new Brian({
|
||||
only: ["front", "sleeve"]
|
||||
})
|
||||
```
|
|
@ -1,24 +0,0 @@
|
|||
---
|
||||
title: options
|
||||
---
|
||||
|
||||
The `options` setting allows you to specify values for the pattern-specific
|
||||
options that have been implemented by the pattern designer.
|
||||
|
||||
The available options are listed in the pattern configuration.
|
||||
Refer to the [the options section in the pattern configuration file][1] for
|
||||
all details about using options in FreeSewing.
|
||||
|
||||
[1]: /reference/api/config/options
|
||||
|
||||
```js
|
||||
import Brian from "@freesewing/brian";
|
||||
|
||||
const pattern = new Brian({
|
||||
options: {
|
||||
chestEase: 120
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
<Note>Unlike measurements, options come with defaults.</Note>
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
title: sa
|
||||
---
|
||||
|
||||
The `sa` setting controls the seam allowance. It expects a value in mm
|
||||
or `false` or `0` to disable seam allowance altogether.
|
||||
|
||||
```js
|
||||
import Brian from "@freesewing/brian";
|
||||
|
||||
const pattern = new Brian({
|
||||
sa: 10
|
||||
})
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
This is ignored if [settings.complete](/reference/api/settings/complete) is `false`
|
||||
|
||||
<Comment by="joost">
|
||||
Is it though?
|
||||
I suspect this is not clearly enforced and we should clarify that.
|
||||
</Comment>
|
||||
|
||||
</Note>
|
|
@ -1,17 +0,0 @@
|
|||
---
|
||||
title: units
|
||||
---
|
||||
|
||||
The `units` setting controls the units used on the pattern.
|
||||
It can be either `metric` (the default) or `imperial`.
|
||||
|
||||
Note that this is only used to format the output.
|
||||
Freesewing expects mm as input.
|
||||
|
||||
```js
|
||||
import Brian from "@freesewing/brian";
|
||||
|
||||
const pattern = new Brian({
|
||||
units: "imperial"
|
||||
})
|
||||
```
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: bnotch
|
||||
---
|
||||
|
||||
The `bnotch` snippet is intended for notches at the back, or when you
|
||||
need an alternative to the default `notch`.
|
||||
|
||||
It is provided by [plugin-notches](/reference/plugins/notches/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('bnotch', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_bnotch">An example of the bnotch snippet</Example>
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: button
|
||||
---
|
||||
|
||||
The `button` snippet is used to mark button placement and is
|
||||
provided by [plugin-buttons](/reference/plugins/buttons/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('button', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_button">
|
||||
An example of the button snippet
|
||||
</Example>
|
|
@ -1,26 +0,0 @@
|
|||
---
|
||||
title: buttonhole-end
|
||||
---
|
||||
|
||||
The `buttonhole-end` snippet is used to mark buttonhole placement and is
|
||||
provided by [plugin-buttons](/reference/plugins/buttons/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('buttonhole-end', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_buttonhole_end">
|
||||
An example of the buttonhole-end snippet
|
||||
</Example>
|
||||
|
||||
<Note>
|
||||
|
||||
##### Aligning your buttons and buttonholes
|
||||
|
||||
We provide three buttonhole snippets with a different alignment:
|
||||
|
||||
- [buttonhole](/reference/api/snippets/buttonhole/): Anchor point is the middle of the buttonhole
|
||||
- [buttonhole-start](/reference/api/snippets/buttonhole-start/): Anchor point is the start of the buttonhole
|
||||
- [buttonhole-end](/reference/api/snippets/buttonhole-end/): Anchor point is the end of the buttonhole
|
||||
|
||||
</Note>
|
|
@ -1,26 +0,0 @@
|
|||
---
|
||||
title: buttonhole-start
|
||||
---
|
||||
|
||||
The `buttonhole-start` snippet is used to mark buttonhole placement and is
|
||||
provided by [plugin-buttons](/reference/plugins/buttons/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('buttonhole-start', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_buttonhole_start">
|
||||
An example of the buttonhole-start snippet
|
||||
</Example>
|
||||
|
||||
<Note>
|
||||
|
||||
##### Aligning your buttons and buttonholes
|
||||
|
||||
We provide three buttonhole snippets with a different alignment:
|
||||
|
||||
- [buttonhole](/reference/api/snippets/buttonhole/): Anchor point is the middle of the buttonhole
|
||||
- [buttonhole-start](/reference/api/snippets/buttonhole-start/): Anchor point is the start of the buttonhole
|
||||
- [buttonhole-end](/reference/api/snippets/buttonhole-end/): Anchor point is the end of the buttonhole
|
||||
|
||||
</Note>
|
|
@ -1,26 +0,0 @@
|
|||
---
|
||||
title: buttonhole
|
||||
---
|
||||
|
||||
The `buttonhole` snippet is used to mark buttonhole placement and is
|
||||
provided by [plugin-buttons](/reference/plugins/buttons/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('buttonhole', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_buttonhole">
|
||||
An example of the buttonhole snippet
|
||||
</Example>
|
||||
|
||||
<Note>
|
||||
|
||||
##### Aligning your buttons and buttonholes
|
||||
|
||||
We provide three buttonhole snippets with a different alignment:
|
||||
|
||||
- [buttonhole](/reference/api/snippets/buttonhole/): Anchor point is the middle of the buttonhole
|
||||
- [buttonhole-start](/reference/api/snippets/buttonhole-start/): Anchor point is the start of the buttonhole
|
||||
- [buttonhole-end](/reference/api/snippets/buttonhole-end/): Anchor point is the end of the buttonhole
|
||||
|
||||
</Note>
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
title: Snippets
|
||||
for: developers
|
||||
about: Complete list of all the available snippets
|
||||
---
|
||||
|
||||
Snippets are provided by plugins. Follow the links below for more info on and an example of a specific snippet:
|
||||
|
||||
<ReadMore list />
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: logo
|
||||
---
|
||||
|
||||
The `logo` snippet inserts the FreeSewing logo. It is
|
||||
provided by [plugin-logo](/reference/plugins/logo/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('logo', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_logo">
|
||||
An example of the logo snippet
|
||||
</Example>
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: notch
|
||||
---
|
||||
|
||||
The `notch` snippet is intended for notches and is
|
||||
provided by [plugin-notches](/reference/plugins/notches/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('bnotch', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_notch">
|
||||
An example of the notch snippet
|
||||
</Example>
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
title: snap-socket
|
||||
---
|
||||
|
||||
The `snap-socket` snippet is used to mark the socket part of a snap button.
|
||||
|
||||
It is provided by [plugin-buttons](/reference/plugins/buttons/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('snap-socket', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_snapsocket">
|
||||
An example of the snap-socket snippet
|
||||
</Example>
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
title: snap-stud
|
||||
---
|
||||
|
||||
The `snap-stud` snippet is used to mark the stud part of a snap button.
|
||||
|
||||
It is provided by [plugin-buttons](/reference/plugins/buttons/).
|
||||
|
||||
```js
|
||||
snippets.demo = new Snippet('snap-stud', points.anchor)
|
||||
```
|
||||
|
||||
<Example part="snippets_snapstud">
|
||||
An example of the snap-stud snippet
|
||||
</Example>
|
|
@ -1,5 +1,6 @@
|
|||
---
|
||||
title: attributes
|
||||
title: Svg.attributes
|
||||
---
|
||||
|
||||
An [Attributes](/reference/api/attributes) instance that controls the attributes of the SVG tag.
|
||||
The `Svg.attributes` property holds an [Attributes](/reference/api/attributes)
|
||||
instance to control the attributes of the SVG document.
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
---
|
||||
title: defs
|
||||
title: Svg.defs
|
||||
---
|
||||
|
||||
A string that will be rendered
|
||||
as [the defs section](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs) of
|
||||
the SVG document.
|
||||
The `Svg.defs` property holds a string that will be rendered as [the defs
|
||||
section](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs) of the
|
||||
SVG document.
|
||||
|
||||
The defs attribute is where plugins will add additional snippets.
|
||||
## Signature
|
||||
|
||||
```svg
|
||||
<defs>
|
||||
|
@ -14,9 +14,9 @@ The defs attribute is where plugins will add additional snippets.
|
|||
</defs>
|
||||
```
|
||||
|
||||
<Warning>
|
||||
## Notes
|
||||
|
||||
###### Add, but don't overwrite
|
||||
The defs attribute is where plugins will add additional snippets.
|
||||
|
||||
When adding your own defs, it's important not to
|
||||
overwrite this property, but rather add your own.
|
||||
|
@ -24,13 +24,11 @@ overwrite this property, but rather add your own.
|
|||
In other words, do this:
|
||||
|
||||
```js
|
||||
svg.defs += myDefs;
|
||||
svg.defs += myDefs
|
||||
```
|
||||
|
||||
and don't do this:
|
||||
|
||||
```js
|
||||
svg.defs = myDefs;
|
||||
svg.defs = myDefs
|
||||
```
|
||||
|
||||
</Warning>
|
||||
|
|
|
@ -5,9 +5,10 @@ title: Svg
|
|||
The `Svg` object in FreeSewing's core library represents an SVG document.
|
||||
It is not directly exposed, but it is available as the `svg` attribute
|
||||
of a [Pattern object](/reference/api/pattern/).
|
||||
|
||||
While the methods exposed by this object are only used internally,
|
||||
its attributes are useful for situations where you
|
||||
want to develop a plugin, or use a custom layout:
|
||||
want to develop a plugin, or use a custom layout.
|
||||
|
||||
## Svg properties
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
---
|
||||
title: head
|
||||
---
|
||||
|
||||
A string that combines the `style`, `script`,
|
||||
and `defs` sections and an opening tag for an SVG group.
|
||||
|
||||
```svg
|
||||
<style type="text/css">
|
||||
/* svg.style will be inserted */
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
/* svg.script will be inserted */
|
||||
</scripts>
|
||||
|
||||
<defs>
|
||||
/* svg.defs will be inserted */
|
||||
</defs>
|
||||
|
||||
<!-- Start of group #fs-container -->
|
||||
<g id="fs-container">
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
###### This does not include the opening SVG tag
|
||||
|
||||
Note that while [Pattern.svg.tail](/reference/api/pattern/svg/tail/) closes the SVG tag,
|
||||
[Pattern.svg.head](/reference/api/pattern/head/) does not open it.
|
||||
That's because the `width`, `height` and `viewBox` attributes will
|
||||
depend on the main body of the SVG document.
|
||||
|
||||
</Note>
|
|
@ -1,9 +1,11 @@
|
|||
---
|
||||
title: layout
|
||||
title: Svg.layout
|
||||
---
|
||||
|
||||
An object that holds rendered SVG for all parts, and a list of their transforms.
|
||||
It is structured as follows:
|
||||
The `Svg.layout` property holds an object that holds rendered SVG for all
|
||||
parts, and a list of their transforms.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
{
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
---
|
||||
title: pattern
|
||||
title: Svg.pattern
|
||||
---
|
||||
|
||||
A reference to [the Pattern object](/reference/api/pattern/).
|
||||
The `Svg.pattern` property holds a reference to [the Pattern
|
||||
object](/reference/api/pattern/) itself.
|
||||
|
||||
This allows hooks that only receive the SVG object (such as the preRender and postRender hooks)
|
||||
to still access the pattern object.
|
||||
## Notes
|
||||
|
||||
This allows hooks that only receive the SVG object (such as the preRender and
|
||||
postRender hooks) to still access the pattern object.
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
title: prefix
|
||||
---
|
||||
|
||||
A string that will be rendered before the opening SVG tag.
|
||||
|
||||
Its default value is:
|
||||
|
||||
```svg
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
```
|
||||
|
||||
<Note>This only applies when rendering to SVG, not what
|
||||
rendering a React component</Note>
|
|
@ -1,34 +0,0 @@
|
|||
---
|
||||
title: script
|
||||
---
|
||||
|
||||
A string that will be rendered as the script section of the SVG document.
|
||||
|
||||
We don't use this ourselves, but it's there if you need it.
|
||||
|
||||
```svg
|
||||
<script type="text/javascript">
|
||||
/* svg.script will be inserted */
|
||||
</scripts>
|
||||
```
|
||||
|
||||
<Warning>
|
||||
|
||||
###### Add, but don't overwrite
|
||||
|
||||
When adding your own script, it's important not to
|
||||
overwrite this property, but rather add your own.
|
||||
|
||||
In other words, do this:
|
||||
|
||||
```js
|
||||
svg.script += myScript;
|
||||
```
|
||||
|
||||
and don't do this:
|
||||
|
||||
```js
|
||||
svg.script = myScript;
|
||||
```
|
||||
|
||||
</Warning>
|
|
@ -1,10 +1,11 @@
|
|||
---
|
||||
title: style
|
||||
title: Svg.style
|
||||
---
|
||||
|
||||
A string that will be rendered as the style section of the SVG document.
|
||||
The `Svg.style` property holds a string that will be rendered as the style
|
||||
section of the SVG document.
|
||||
|
||||
The style attribute is where plugins will add additional snippets.
|
||||
## Signature
|
||||
|
||||
```svg
|
||||
<style type="text/css">
|
||||
|
@ -12,9 +13,9 @@ The style attribute is where plugins will add additional snippets.
|
|||
</style>
|
||||
```
|
||||
|
||||
<Warning>
|
||||
## Notes
|
||||
|
||||
###### Add, but don't overwrite
|
||||
The style property is where plugins will add additional styling.
|
||||
|
||||
When adding your own styles, it's important not to
|
||||
overwrite this property, but rather add your own.
|
||||
|
@ -22,13 +23,11 @@ overwrite this property, but rather add your own.
|
|||
In other words, do this:
|
||||
|
||||
```js
|
||||
svg.style += myStyles;
|
||||
svg.style += myStyles
|
||||
```
|
||||
|
||||
and don't do this:
|
||||
|
||||
```js
|
||||
svg.style = myStyles;
|
||||
svg.style = myStyles
|
||||
```
|
||||
|
||||
</Warning>
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
title: tail
|
||||
---
|
||||
|
||||
A string that closes both the group opened by [Pattern.svg.head](/reference/api/pattern/svg/head/) and the SVG tag.
|
||||
|
||||
```svg
|
||||
</g>
|
||||
<!-- end of group #fs-container -->
|
||||
</svg>
|
||||
```
|
|
@ -1,20 +1,23 @@
|
|||
---
|
||||
title: beamIntersectsCircle()
|
||||
title: utils.beamIntersectsCircle()
|
||||
---
|
||||
|
||||
The `utils.beamIntersectsCircle()` function finds the intersection between an
|
||||
endless line through points `point1` and `point2` and a circle with its center
|
||||
at point `center` and a radius of `radius` mm.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array | false utils.beamIntersectsCircle(
|
||||
Point center,
|
||||
float radius,
|
||||
Point point1,
|
||||
Point point1,
|
||||
string sort = 'x'
|
||||
string sort=x
|
||||
)
|
||||
```
|
||||
|
||||
Finds the intersection between an endless line through points `point1` and `point2`
|
||||
and a circle with its center at point `center` and a radius of `radius` mm.
|
||||
|
||||
The 5th and last parameter controls the _sorting_ of the found intersections.
|
||||
This will (almost) always return 2 intersections, and you can choose how
|
||||
they are ordered in the returned array:
|
||||
|
@ -24,59 +27,54 @@ Set sort to:
|
|||
- `x` : The point with the lowest X-coordinate will go first (left to right)
|
||||
- `y` : The point with the lowest Y-coordinate will go first (top to bottom)
|
||||
|
||||
<Example part="utils_beamintersectscircle">
|
||||
A Utils.beamIntersectsCircle() example
|
||||
## Example
|
||||
|
||||
<Example caption="A utils.beamIntersectsCircle() example">
|
||||
```js
|
||||
({ Point, points, Path, paths, Snippet, snippets, utils, part }) => {
|
||||
|
||||
points.A = new Point(45, 45)
|
||||
.addCircle(35, "Fabric")
|
||||
points.B = new Point(5, 50)
|
||||
points.C = new Point(25, 30)
|
||||
points.D = new Point(5, 65)
|
||||
points.E = new Point(65, 5)
|
||||
points.F = new Point(15, 75)
|
||||
points.G = new Point(75, 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 part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
|
||||
points.A = new Point(45, 45)
|
||||
.attr("data-circle", 35)
|
||||
.attr("data-circle-class", "fabric");
|
||||
points.B = new Point(5, 50);
|
||||
points.C = new Point(25, 30);
|
||||
points.D = new Point(5, 65);
|
||||
points.E = new Point(65, 5);
|
||||
points.F = new Point(15, 75);
|
||||
points.G = new Point(75, 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]);
|
||||
```
|
||||
|
|
|
@ -1,38 +1,40 @@
|
|||
---
|
||||
title: beamIntersectsX()
|
||||
title: utils.beamIntersectsX()
|
||||
---
|
||||
|
||||
The `utils.beamIntersectsX()` function finds the intersection between an endless
|
||||
line and a given X-value. Returns a [Point](/reference/api/point) object for
|
||||
the intersection, or `false` there is no intersection.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Point | false utils.beamIntersectsX(Point A, Point B, float X)
|
||||
```
|
||||
|
||||
Finds the intersection between an endless line and a given X-value. Returns a [Point](/reference/api/point) object
|
||||
for the intersection, or `false` there is no intersection.
|
||||
|
||||
<Example part="utils_beamintersectsx">
|
||||
A Utils.beamIntersectsX() example
|
||||
</Example>
|
||||
## Example
|
||||
|
||||
<Example caption="A Utils.beamIntersectsX() example">
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
({ Point, points, Path, paths, Snippet, snippets, utils, part }) => {
|
||||
|
||||
points.A = new Point(10, 10);
|
||||
points.B = new Point(90, 30);
|
||||
points.A = new Point(10, 10)
|
||||
points.B = new Point(90, 30)
|
||||
|
||||
paths.AB = new Path().move(points.A).line(points.B);
|
||||
paths.AB = new Path().move(points.A).line(points.B)
|
||||
|
||||
snippets.x = new Snippet("notch", utils.beamIntersectsX(points.A, points.B, 40));
|
||||
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");
|
||||
.addClass("note dashed")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
|
|
@ -1,38 +1,40 @@
|
|||
---
|
||||
title: beamIntersectsY()
|
||||
title: utils.beamIntersectsY()
|
||||
---
|
||||
|
||||
The `utils.beamIntersectsY()` function finds the intersection between an endless
|
||||
line and a given Y-value. Returns a [Point](/reference/api/point) object for
|
||||
the intersection, or `false` there is no intersection.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Point | false utils.beamIntersectsY(Point A, Point B, float Y)
|
||||
```
|
||||
|
||||
Finds the intersection between an endless line and a given Y-value. Returns a [Point](/reference/api/point) object
|
||||
for the intersection, or `false` there is no intersection.
|
||||
## Example
|
||||
|
||||
<Example part="utils_beamintersectsy">
|
||||
A Utils.beamIntersectsY() example
|
||||
<Example caption="A Utils.beamIntersectsY() example">
|
||||
```js
|
||||
({ 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
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
|
||||
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");
|
||||
```
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
---
|
||||
title: beamsIntersect()
|
||||
title: uils.beamsIntersect()
|
||||
---
|
||||
|
||||
The `utils.beamsIntersect()` function finds the intersection between two endless
|
||||
lines (beams). Returns a [Point](/reference/api/point) object for the
|
||||
intersection, or `false` if the lines don't intersect.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Point | false utils.beamsIntersect(
|
||||
Point A,
|
||||
|
@ -11,34 +17,27 @@ Point | false utils.beamsIntersect(
|
|||
)
|
||||
```
|
||||
|
||||
Finds the intersection between two endless lines (beams). Returns a [Point](/reference/api/point) object
|
||||
for the intersection, or `false` if the lines don't intersect.
|
||||
## Example
|
||||
|
||||
<Example part="utils_beamsintersect">
|
||||
A Utils.beamIntersect() example
|
||||
<Example caption="A Utils.beamIntersect() example">
|
||||
```js
|
||||
({ 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
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
|
||||
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)
|
||||
);
|
||||
```
|
||||
|
|
19
markdown/dev/reference/api/utils/capitalize/en.md
Normal file
19
markdown/dev/reference/api/utils/capitalize/en.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
title: utils.capitalize()
|
||||
---
|
||||
|
||||
The `utils.capitalize()` function returns the string you pass it with its first
|
||||
letter turned into uppercase.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
String utils.capitalize(String input)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
capitalize('hello') // returns 'Hello')
|
||||
capitalize('hello there') // returns 'Hello there'
|
||||
```
|
|
@ -1,7 +1,12 @@
|
|||
---
|
||||
title: circlesIntersect()
|
||||
title: utils.circlesIntersect()
|
||||
---
|
||||
|
||||
The `utils.circlesIntersect()` function finds the intersections between two
|
||||
circles described by their center point and radius.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array | false utils.circlesIntersect(
|
||||
Point centerA,
|
||||
|
@ -12,8 +17,6 @@ array | false utils.circlesIntersect(
|
|||
)
|
||||
```
|
||||
|
||||
Finds the intersections between two circles described by their center point and radius.
|
||||
|
||||
The 5th and last parameter controls the _sorting_ of the found intersections.
|
||||
When this returns 2 intersections, you can choose how they are ordered in the returned array:
|
||||
|
||||
|
@ -22,42 +25,42 @@ Set sort to:
|
|||
- `x` : The point with the lowest X-coordinate will go first (left to right)
|
||||
- `y` : The point with the lowest Y-coordinate will go first (top to bottom)
|
||||
|
||||
<Example part="utils_circlesintersect">
|
||||
A Utils.circlesIntersect() example
|
||||
## Example
|
||||
|
||||
<Example caption="A Utils.circlesIntersect() example">
|
||||
```js
|
||||
({ Point, points, Snippet, snippets, utils, part }) => {
|
||||
|
||||
points.A = new Point(10, 10)
|
||||
.addCircle(15, "fabric")
|
||||
points.B = new Point(30, 30)
|
||||
.addCircle(35, "fabric")
|
||||
points.C = new Point(90, 10)
|
||||
.addCircle(15, "various")
|
||||
points.D = new Point(110, 30)
|
||||
.addCircle(35, "various")
|
||||
|
||||
const intersections1 = utils.circlesIntersect(
|
||||
points.A,
|
||||
points.A.attributes.get("data-circle"),
|
||||
points.B,
|
||||
points.B.attributes.get("data-circle")
|
||||
)
|
||||
const 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
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let { Point, points, Snippet, snippets, utils } = part.shorthand();
|
||||
|
||||
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]);
|
||||
```
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
---
|
||||
title: curveIntersectsX()
|
||||
title: utils.curveIntersectsX()
|
||||
---
|
||||
|
||||
The `utils.curveIntersectsX()` function finds the point(s) where a curve
|
||||
intersects a given X-value.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array | Point | false utils.curveIntersectsX(
|
||||
Point start,
|
||||
|
@ -11,61 +16,60 @@ array | Point | false utils.curveIntersectsX(
|
|||
float x)
|
||||
```
|
||||
|
||||
Finds the point(s) where a curve intersects a given X-value.
|
||||
|
||||
This is a low-level variant
|
||||
of [`Path.intersectsX()`](/reference/api/path/intersectsx).
|
||||
Instead of a path, you describe a single curve by passing the four
|
||||
points that describes it.
|
||||
|
||||
This returns `false` if no intersections are found,
|
||||
a [Point](/reference/api/point) object if
|
||||
a single intersection is found, and an array
|
||||
of [Point](/reference/api/point) objects if
|
||||
multiple intersections are found.
|
||||
|
||||
<Example part="utils_curveintersectsx">A Utils.curveIntersectX() example</Example>
|
||||
## Example
|
||||
|
||||
<Example caption="A Utils.curveIntersectX() example">
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
utils,
|
||||
snippets,
|
||||
Snippet
|
||||
} = part.shorthand();
|
||||
({ Point, points, Path, paths, Snippet, snippets, utils, 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);
|
||||
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])
|
||||
.addClass("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)
|
||||
|
||||
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");
|
||||
return part
|
||||
}
|
||||
|
||||
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);
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
This is a low-level (and faster) variant
|
||||
of [`Path.intersectsX()`](/reference/api/path/intersectsx).
|
||||
Instead of a path, you describe a single curve by passing the four
|
||||
points that describes it.
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
---
|
||||
title: curveIntersectsY()
|
||||
title: utils.curveIntersectsY()
|
||||
---
|
||||
|
||||
The `utils.curveIntersectsX()` function finds the point(s) where a curve
|
||||
intersects a given Y-value.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array | Point | false utils.curveIntersectsY(
|
||||
Point start,
|
||||
|
@ -11,61 +16,60 @@ array | Point | false utils.curveIntersectsY(
|
|||
float y)
|
||||
```
|
||||
|
||||
Finds the point(s) where a curve intersects a given Y-value.
|
||||
|
||||
This is a low-level variant
|
||||
of [`Path.intersectsY()`](/reference/api/path/intersectsy).
|
||||
Instead of a path, you describe a single curve by passing the four
|
||||
points that describes it.
|
||||
|
||||
This returns `false` if no intersections are found,
|
||||
a [Point](/reference/api/point/) object if
|
||||
a single intersection is found, and an array
|
||||
of [Point](/reference/api/point/) objects if
|
||||
multiple intersections are found.
|
||||
|
||||
<Example part="utils_curveintersectsy">A Utils.curveIntersectY() example</Example>
|
||||
|
||||
## Example
|
||||
<Example caption="A Utils.curveIntersectY() example">
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
utils,
|
||||
snippets,
|
||||
Snippet
|
||||
} = part.shorthand();
|
||||
({ Point, points, Path, paths, Snippet, snippets, utils, 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);
|
||||
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])
|
||||
.addClass("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)
|
||||
|
||||
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");
|
||||
return part
|
||||
}
|
||||
|
||||
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);
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
This is a low-level (and faster) variant
|
||||
of [`Path.intersectsY()`](/reference/api/path/intersectsy).
|
||||
Instead of a path, you describe a single curve by passing the four
|
||||
points that describes it.
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
---
|
||||
title: curvesIntersect()
|
||||
title: utils.curvesIntersect()
|
||||
---
|
||||
|
||||
The `utils.curvesIntersect()` function finds the intersections between two curves
|
||||
described by 4 points each.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array | false utils.curvesIntersect(
|
||||
Point startA,
|
||||
|
@ -14,49 +19,43 @@ array | false utils.curvesIntersect(
|
|||
Point endB)
|
||||
```
|
||||
|
||||
Finds the intersections between two curves described by 4 points each.
|
||||
|
||||
<Example part="utils_curvesintersect">
|
||||
A Utils.curvesIntersect() example
|
||||
</Example>
|
||||
## Example
|
||||
|
||||
<Example caption="A Utils.curvesIntersect() example">
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
({ Point, points, Path, paths, Snippet, snippets, utils, getId, 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.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 (const p of utils.curvesIntersect(
|
||||
points.A,
|
||||
points.Acp,
|
||||
points.Bcp,
|
||||
points.B,
|
||||
points.C,
|
||||
points.Ccp,
|
||||
points.Dcp,
|
||||
points.D
|
||||
)) {
|
||||
snippets[getId()] = new Snippet("notch", p)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
---
|
||||
title: deg2rad()
|
||||
title: utils.deg2rad()
|
||||
---
|
||||
|
||||
The `utils.deg2read()` function returns the degrees you pass to it as radians.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
float deg2rad(float degrees)
|
||||
```
|
||||
|
||||
Returns the degrees you pass to it as radians.
|
||||
## Notes
|
||||
|
||||
This is useful for when you use methods like `Math.cos()` that expects a corner
|
||||
This is useful for when you use functions like `Math.cos()` that expect a corner
|
||||
in radians, when we typically use degrees.
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
---
|
||||
title: Utils
|
||||
title: utils
|
||||
---
|
||||
|
||||
The `Utils` object provides the following utility methods to facilitate your work:
|
||||
The `utils` object is a plain object that bundles utility functions to
|
||||
facilitate parametric design.
|
||||
|
||||
The following functions are provided by the `utils` object:
|
||||
|
||||
<ReadMore list />
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
---
|
||||
title: lineIntersectsCircle()
|
||||
title: utils.lineIntersectsCircle()
|
||||
---
|
||||
|
||||
The `utils.lineIntersectsCircle()` function finds the intersection between a line
|
||||
segment from point `from` to point `to` and a circle with its center at point
|
||||
`center` and a radius of `radius` mm.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array | false utils.lineIntersectsCircle(
|
||||
Point center,
|
||||
|
@ -12,9 +18,6 @@ array | false utils.lineIntersectsCircle(
|
|||
)
|
||||
```
|
||||
|
||||
Finds the intersection between a line segment from point `from` to point `to`
|
||||
and a circle with its center at point `center` and a radius of `radius` mm.
|
||||
|
||||
The 5th and last parameter controls the _sorting_ of the found intersections.
|
||||
When this returns 2 intersections, you can choose how they are ordered in the returned array:
|
||||
|
||||
|
@ -23,58 +26,53 @@ Set sort to:
|
|||
- `x` : The point with the lowest X-coordinate will go first (left to right)
|
||||
- `y` : The point with the lowest Y-coordinate will go first (top to bottom)
|
||||
|
||||
<Example part="utils_lineintersectscircle">
|
||||
A Utils.lineIntersectsCircle() example
|
||||
## Example
|
||||
|
||||
<Example caption="A Utils.lineIntersectsCircle() example">
|
||||
```js
|
||||
({ Point, points, Path, paths, Snippet, snippets, utils, part }) => {
|
||||
|
||||
points.A = new Point(95, 45)
|
||||
.addCircle(35, "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)
|
||||
|
||||
const intersections1 = utils.lineIntersectsCircle(
|
||||
points.A,
|
||||
points.A.attributes.get("data-circle"),
|
||||
points.B,
|
||||
points.C
|
||||
)
|
||||
const intersections2 = utils.lineIntersectsCircle(
|
||||
points.A,
|
||||
points.A.attributes.get("data-circle"),
|
||||
points.D,
|
||||
points.E,
|
||||
"y"
|
||||
)
|
||||
const 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 part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
|
||||
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]);
|
||||
```
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
---
|
||||
title: lineIntersectsCurve()
|
||||
title: utils.lineIntersectsCurve()
|
||||
---
|
||||
|
||||
The `utils.lineIntersectsCurve()` function finds the intersection between a line
|
||||
segment from point `from` to point `to` and a curve described by points
|
||||
`start`, `cp1`, `cp2, and `end\`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array | false utils.lineIntersectsCurve(
|
||||
Point from,
|
||||
|
@ -13,43 +19,36 @@ array | false utils.lineIntersectsCurve(
|
|||
)
|
||||
```
|
||||
|
||||
Finds the intersection between a line segment from point `from` to point `to`
|
||||
and a curve described by points `start`, `cp1`, `cp2, and `end\`.
|
||||
|
||||
<Example part="utils_lineintersectscurve">
|
||||
A Utils.lineIntersectsCurve() example
|
||||
</Example>
|
||||
## Example
|
||||
|
||||
<Example caption="A Utils.lineIntersectsCurve() example">
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
({ Point, points, Path, paths, Snippet, snippets, getId, 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);
|
||||
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[getId()] = new Snippet("notch", p)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
---
|
||||
title: linesIntersect()
|
||||
title: utils.linesIntersect()
|
||||
---
|
||||
|
||||
The `utils.linesInersect()` function finds the intersection between two line
|
||||
segments. Returns a [Point](../point) object for the intersection, or `false`
|
||||
if the lines don't intersect.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Point | false utils.linesIntersect(
|
||||
Point A,
|
||||
|
@ -11,34 +17,27 @@ Point | false utils.linesIntersect(
|
|||
)
|
||||
```
|
||||
|
||||
Finds the intersection between two line segments. Returns a [Point](../point) object
|
||||
for the intersection, or `false` if the lines don't intersect.
|
||||
## Example
|
||||
|
||||
<Example part="utils_linesintersect">
|
||||
A Utils.linesIntersect() example
|
||||
<Example caption="A Utils.linesIntersect() example">
|
||||
```js
|
||||
({ 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
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
|
||||
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)
|
||||
);
|
||||
```
|
||||
|
|
35
markdown/dev/reference/api/utils/pctbasedon/en.md
Normal file
35
markdown/dev/reference/api/utils/pctbasedon/en.md
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
title: utils.pctBasedOn()
|
||||
---
|
||||
|
||||
The `utils.pctBasedOn()` function is a helper function to be used when
|
||||
configuring [snapped percentage
|
||||
options](/reference/api/part/config/options/pct/snap).
|
||||
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
object utils.pctBasedOn(String measurement)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const options = {
|
||||
example: {
|
||||
pct: 12,
|
||||
min: 5,
|
||||
max: 18,
|
||||
snap: 3,
|
||||
...pctBasedOn('chest')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
This will return an object with `toAbs` and `fromAbs` properties that calculate
|
||||
the option's absolute and relative values based on a measurment. Refer to
|
||||
[snapped percentage options](/reference/api/part/config/options/pct/snap) for
|
||||
more details.
|
|
@ -1,7 +1,13 @@
|
|||
---
|
||||
title: pointOnBeam()
|
||||
title: utils.pointOnBeam()
|
||||
---
|
||||
|
||||
The `utils.pointOnBeam()` function returns `true` if the point `check` lies on
|
||||
the endless line that goes through `point1` and `point2`.
|
||||
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
bool utils.pointOnBeam(
|
||||
Point point1,
|
||||
|
@ -11,73 +17,64 @@ bool utils.pointOnBeam(
|
|||
)
|
||||
```
|
||||
|
||||
Returns `true` if the point `check` lies on the endless line that goes through `point1` and `point2`.
|
||||
The fourth parameter controls the precision. Lower numbers make the check less precise.
|
||||
|
||||
<Note>
|
||||
## Example
|
||||
|
||||
###### Tweak precision only when needed
|
||||
<Example caption="A Utils.pointOnBeam() example">
|
||||
```js
|
||||
({ Point, points, Path, paths, Snippet, snippets, getId, utils, part }) => {
|
||||
|
||||
Typically, you don't need to worry about precision. But occasionally, you may get
|
||||
unexpected results because of floating point errors, rounding errors, or
|
||||
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)
|
||||
|
||||
const 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[getId()] = new Snippet(snippet, point)
|
||||
if (utils.pointOnBeam(points.from2, points.to2, point, 0.01)) {
|
||||
snippet = "notch"
|
||||
} else snippet = "bnotch"
|
||||
snippets[getId()] = new Snippet(snippet, point)
|
||||
}
|
||||
paths.line1 = new Path()
|
||||
.move(points.from1)
|
||||
.line(points.to1)
|
||||
.addClass("fabric stroke-lg")
|
||||
paths.lne1 = new Path()
|
||||
.move(points.to1)
|
||||
.line(points.b1)
|
||||
.addClass("fabric dashed")
|
||||
paths.line2 = new Path()
|
||||
.move(points.from2)
|
||||
.line(points.to2)
|
||||
.addClass("fabric stroke-lg")
|
||||
paths.lne2 = new Path()
|
||||
.move(points.to2)
|
||||
.line(points.b2)
|
||||
.addClass("fabric dashed")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
Typically, you don't need to worry about precision. But occasionally, you may
|
||||
get unexpected results because of floating point errors, rounding errors, or
|
||||
cubic bezier juggling.
|
||||
|
||||
When that happens, you can lower the precision so you get what you expect.
|
||||
|
||||
</Note>
|
||||
|
||||
<Example part="utils_pointonbeam">
|
||||
A Utils.pointOnBeam() example
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
|
||||
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");
|
||||
```
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
---
|
||||
title: pointOnCurve()
|
||||
title: utils.pointOnCurve()
|
||||
---
|
||||
|
||||
The `utils.pointOnCurve()` function returns `true` if the point `check` lies on a
|
||||
curve described by points `start`, `cp1`, `cp2`, and `end`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
bool utils.pointOnCurve(
|
||||
Point start,
|
||||
|
@ -12,57 +17,49 @@ bool utils.pointOnCurve(
|
|||
)
|
||||
```
|
||||
|
||||
Returns `true` if the point `check` lies on a curve described by points `start`, `cp1`, `cp2`, and `end`.
|
||||
## Example
|
||||
|
||||
<Note>
|
||||
<Example caption="A Utils.pointOnCurve() example">
|
||||
```js
|
||||
({ Point, points, Path, paths, Snippet, snippets, getId, utils, part }) => {
|
||||
|
||||
Keep in mind that calculations with Bezier curves are often aproximations.
|
||||
points.start = new Point(10, 10)
|
||||
points.cp1 = new Point(90, 10)
|
||||
points.cp2 = new Point(10, 60)
|
||||
points.end = new Point(90, 60)
|
||||
|
||||
const 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[getId()] = new Snippet(snippet, point)
|
||||
}
|
||||
paths.curve = new Path()
|
||||
.move(points.start)
|
||||
.curve(points.cp1, points.cp2, points.end)
|
||||
.addClass("fabric stroke-lg")
|
||||
|
||||
</Note>
|
||||
|
||||
<Example part="utils_pointoncurve">
|
||||
A Utils.pointOnCurve() example
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
|
||||
points.start = new Point(10, 10);
|
||||
points.cp1 = new Point(90, 10);
|
||||
points.cp2 = new Point(10, 60);
|
||||
points.end = new Point(90, 60);
|
||||
## Notes
|
||||
|
||||
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");
|
||||
```
|
||||
Keep in mind that calculations with Bezier curves are often aproximations.
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
---
|
||||
title: pointOnLine()
|
||||
title: utils.pointOnLine()
|
||||
---
|
||||
|
||||
The `utils.pointOnLine()` function returns `true` if the point `check` lies on a
|
||||
line segment from point `from` to point `to`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
bool utils.pointOnLine(
|
||||
Point from,
|
||||
|
@ -11,62 +16,57 @@ bool utils.pointOnLine(
|
|||
)
|
||||
```
|
||||
|
||||
Returns `true` if the point `check` lies on a line segment from point `from` to point `to`.
|
||||
The fourth parameter controls the precision.
|
||||
See [pointOnBeam](/reference/api/utils/pointonbeam).
|
||||
|
||||
The fourth parameter controls the precision. See [pointOnBeam](/reference/api/utils/pointonbeam).
|
||||
## Example
|
||||
|
||||
<Example part="utils_pointonline">
|
||||
A Utils.pointOnLine() example
|
||||
<Example caption="A Utils.pointOnLine() example">
|
||||
```js
|
||||
({ Point, points, Path, paths, Snippet, snippets, getId, 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)
|
||||
|
||||
const 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[getId()] = new Snippet(snippet, point)
|
||||
if (utils.pointOnLine(points.from2, points.to2, point, 0.01)) {
|
||||
snippet = "notch"
|
||||
} else snippet = "bnotch"
|
||||
snippets[getId()] = new Snippet(snippet, point)
|
||||
}
|
||||
paths.line1 = new Path()
|
||||
.move(points.from1)
|
||||
.line(points.to1)
|
||||
.addClass("fabric stroke-lg")
|
||||
paths.lne1 = new Path()
|
||||
.move(points.to1)
|
||||
.line(points.b1)
|
||||
.addClass("fabric dashed")
|
||||
paths.line2 = new Path()
|
||||
.move(points.from2)
|
||||
.line(points.to2)
|
||||
.addClass("fabric stroke-lg")
|
||||
paths.lne2 = new Path()
|
||||
.move(points.to2)
|
||||
.line(points.b2)
|
||||
.addClass("fabric dashed")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
```js
|
||||
let {
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
Snippet,
|
||||
snippets,
|
||||
utils
|
||||
} = part.shorthand();
|
||||
|
||||
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");
|
||||
```
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
---
|
||||
title: rad2deg()
|
||||
title: utils.rad2deg()
|
||||
---
|
||||
|
||||
The `utils.rad2dag()` function returns the radians you pass to it as degrees.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
float rad2deg(float radians)
|
||||
```
|
||||
|
||||
Returns the radians you pass to it as degrees.
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
---
|
||||
title: round()
|
||||
title: utils.round()
|
||||
---
|
||||
|
||||
The `utils.round()` function rounds a value to two decimals.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
float utils.round(float value)
|
||||
```
|
||||
|
||||
Rounds a value to two decimals. For example:
|
||||
## Example
|
||||
|
||||
- 0.1234 becomes 0.12
|
||||
- 5.6789 becomes 5.68
|
||||
```js
|
||||
utils.round(0.1234) // 0.12
|
||||
utils.round(5.6789) // 5.68
|
||||
```
|
||||
|
|
81
markdown/dev/reference/api/utils/splitcurve/en.md
Normal file
81
markdown/dev/reference/api/utils/splitcurve/en.md
Normal file
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
title: utils.splitCurve()
|
||||
---
|
||||
|
||||
The `utils.splitCurve()` function splits a curve defined by 4 points `start`,
|
||||
`cp1`, `cp2`, and `end` on the point `split` and returns an array holding both
|
||||
halves.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array utils.splitCurve(
|
||||
Point start,
|
||||
Point cp1,
|
||||
Point cp2,
|
||||
Point end,
|
||||
Point check,
|
||||
)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="A Utils.splitCurve() example">
|
||||
```js
|
||||
({ Point, points, Path, paths, utils, part }) => {
|
||||
|
||||
points.start = new Point(10, 10)
|
||||
points.cp1 = new Point(100, 80)
|
||||
points.cp2 = new Point(100, 0)
|
||||
points.end = new Point(10, 50)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.start)
|
||||
.curve(points.cp1, points.cp2, points.end)
|
||||
.addClass('dotted stroke-xs')
|
||||
|
||||
points.split = paths.example.shiftFractionAlong(0.4)
|
||||
const halves = utils.splitCurve(
|
||||
points.start,
|
||||
points.cp1,
|
||||
points.cp2,
|
||||
points.end,
|
||||
points.split
|
||||
)
|
||||
for (let i=0; i<2; i++) {
|
||||
const { start, cp1, cp2, end } = halves[i]
|
||||
console.log({start, cp1, cp2,end})
|
||||
paths[`segment${i}`] = new Path()
|
||||
.move(start)
|
||||
.curve(cp1, cp2, end)
|
||||
.addClass('stroke-xl')
|
||||
.attr('style', 'stroke-opacity: 0.5;')
|
||||
}
|
||||
paths.segment0.addClass('note')
|
||||
paths.segment1.addClass('lining')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The returned object has this signature:
|
||||
|
||||
```js
|
||||
[
|
||||
{
|
||||
start: Point,
|
||||
cp1: Point,
|
||||
cp2: Point,
|
||||
end: Point,
|
||||
},
|
||||
{
|
||||
start: Point,
|
||||
cp1: Point,
|
||||
cp2: Point,
|
||||
end: Point,
|
||||
},
|
||||
]
|
||||
|
|
@ -1,18 +1,25 @@
|
|||
---
|
||||
title: stretchToScale()
|
||||
title: utils.stretchToScale()
|
||||
---
|
||||
|
||||
The `utils.stretchToScale()` function calculates the scale for a given amount of
|
||||
stretch.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
float utils.stretchToScale(float stretch)
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
The way people measure stretch intuitively is different from the way we handle stretch in code.
|
||||
|
||||
When people say _25% stretch_ they mean that 10cm fabric gets stretched to 12.5cm fabric.
|
||||
In code and on our patterns, that means we need to scale things by 80%.
|
||||
|
||||
This method does that by returning:
|
||||
This function does that by returning:
|
||||
|
||||
```js
|
||||
1 / (1 + parseFloat(stretch));
|
||||
1 / (1 + parseFloat(stretch))
|
||||
```
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
---
|
||||
title: units()
|
||||
title: utils.units()
|
||||
---
|
||||
|
||||
The `utils.units()` function converts the units `value` you pass it into a
|
||||
formatted string for the `format` you pass it.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
string utils.units(float value, string format = 'metric')
|
||||
```
|
||||
|
||||
Converts the units `value` you pass it into a formatted string for the `format` you pass it.
|
||||
|
||||
Format must be either `imperial` or `metric` (the default).
|
||||
|
||||
<Tip>
|
||||
## Notes
|
||||
|
||||
The [Part.shorthand](/reference/api/part/shorthand/) call provides a context-aware
|
||||
`unit()` method that will call this method and pass it the units requested by the user.
|
||||
|
||||
</Tip>
|
||||
A [part's `draft()` function](/reference/api/part/draft) receives a context-aware
|
||||
`unit()` function that will call this function and pass it the units requested by the user.
|
||||
|
|
|
@ -6,13 +6,3 @@ order: zdd
|
|||
You can find a list of all FreeSewing reference documentation below:
|
||||
|
||||
<ReadMore recurse />
|
||||
|
||||
<Related>
|
||||
|
||||
##### What makes a guide a guide?
|
||||
|
||||
Reference materials hold technical descriptions of the underlying technology and how to make use of it.
|
||||
|
||||
For more details, refer to [How we structure our documentation](/guides/docs).
|
||||
|
||||
</Related>
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
---
|
||||
title: Hooks API
|
||||
for: developers
|
||||
about: Documents the available lifecycle hooks in Core and how to use them
|
||||
title: Lifecycle hooks
|
||||
---
|
||||
|
||||
A **hook** is a lifecycle event.
|
||||
FreeSewing has **lifecycle hooks** that allow you extend its functionality by
|
||||
hooking into a lifecycle event.
|
||||
|
||||
You can register a method for a hook. When the hook is triggered, your method will be
|
||||
called. It will receive two parameters:
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue