chore: Port FreeSewing.dev to docusaurus
The replaces the NextJS site powering FreeSewing.dev with a Docusaurus setup. It's part of my efforts to simplify FreeSewing's setup so we can focus on our core value proposition.
This commit is contained in:
parent
497633d1d3
commit
ab3204f9f1
692 changed files with 11037 additions and 20674 deletions
25
sites/dev/docs/reference/api/attributes/add/readme.mdx
Normal file
25
sites/dev/docs/reference/api/attributes/add/readme.mdx
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
title: Attributes.add()
|
||||
---
|
||||
|
||||
The `Attributes.add()` method adds `value` to the attribute identified by
|
||||
`key`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Attributes attributes.add(string key, string value)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'classA')
|
||||
.add('class', 'classB')
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
Adding multiple values to the same key will result in them being joined together
|
||||
(with a space) when rendering.
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
title: Attributes.asPropsIfPrefixIs()
|
||||
---
|
||||
|
||||
The `Attributes.asPropsIfPrefixIs()` method will return attribute values as a
|
||||
props object (a plain JavaScript object) but only for those keys who start with
|
||||
`prefix`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Object attributes.asPropsIfPrefixIs(string prefix)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'various')
|
||||
.add('stroke', 'red')
|
||||
.add('stroke-width', 2)
|
||||
|
||||
const props = attr.asPropsIfPrefixIs('stroke')
|
||||
/* Props holds:
|
||||
{
|
||||
stroke: 'red',
|
||||
stroke-width: 2
|
||||
}
|
||||
*/
|
||||
```
|
|
@ -0,0 +1,87 @@
|
|||
---
|
||||
title: Attributes.asRenderProps()
|
||||
---
|
||||
|
||||
The `Attributes.asRenderProps()` method will return the data stored in the
|
||||
attributes as a serializable JavaScript object. This method is typically
|
||||
note invoked directly but rather called under the hood as a result of
|
||||
calling [`Pattern.getRenderProps()`](/reference/api/pattern/getrenderprops).
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Object attributes.asRenderProps()
|
||||
```
|
||||
|
||||
## Returned object properties
|
||||
|
||||
This returns JavaScript object has the following properties:
|
||||
|
||||
| Name | Description |
|
||||
| ----:| ----------- |
|
||||
| `list`| A plain object representation of all attributes |
|
||||
| `forSvg`| All attributes rendered as a string for inclusion in an SVG (or HTML) tag |
|
||||
| `forCss`| All attributes rendered as a string for inclusion in CSS |
|
||||
| `circle`| An array of circles radii to render (set as the `data-circle` attribute) |
|
||||
| `circleProps`| A plain object representation of all circle-specific attributes (set as the `data-circle-*` attribute) |
|
||||
| `text`| An array of texts to render (set as the `data-text` attribute) |
|
||||
| `textProps`| A plain object representation of all text-specific attributes (set as the `data-text-*` attribute) |
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'various')
|
||||
.add('stroke', 'red')
|
||||
.add('stroke-width', 2)
|
||||
.add('data-circle', 20)
|
||||
.add('data-circle-class', 'lining')
|
||||
.add('data-text', 'test')
|
||||
.add('data-text-dx', 3)
|
||||
|
||||
const json = JSON.stringify(
|
||||
attr.asRenderProps(), null ,2
|
||||
)
|
||||
|
||||
/* json holds:
|
||||
{
|
||||
"list": {
|
||||
"class": [
|
||||
"various"
|
||||
],
|
||||
"stroke": [
|
||||
"red"
|
||||
],
|
||||
"stroke-width": [
|
||||
2
|
||||
],
|
||||
"data-circle": [
|
||||
20
|
||||
],
|
||||
"data-circle-class": [
|
||||
"lining"
|
||||
],
|
||||
"data-text": [
|
||||
"test"
|
||||
],
|
||||
"data-text-dx": [
|
||||
3
|
||||
]
|
||||
},
|
||||
"forSvg": " class=\"various\" stroke=\"red\" stroke-width=\"2\" data-circle=\"20\" data-circle-class=\"lining\" data-text=\"test\" data-text-dx=\"3\"",
|
||||
"forCss": " class:various; stroke:red; stroke-width:2; data-circle:20; data-circle-class:lining; data-text:test; data-text-dx:3;",
|
||||
"circle": [
|
||||
20
|
||||
],
|
||||
"circleProps": {
|
||||
"className": "lining"
|
||||
},
|
||||
"text": [
|
||||
"test"
|
||||
],
|
||||
"textProps": {
|
||||
"dx": "3"
|
||||
}
|
||||
}
|
||||
*/
|
||||
```
|
23
sites/dev/docs/reference/api/attributes/clone/readme.mdx
Normal file
23
sites/dev/docs/reference/api/attributes/clone/readme.mdx
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
title: Attributes.clone()
|
||||
---
|
||||
|
||||
The `Attributes.clone()` method returns a new Attributes object that is a deep
|
||||
copy of this one.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Attributes attributes.clone()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'classA')
|
||||
.add('class', 'classB')
|
||||
|
||||
const cloned = attr.clone()
|
||||
```
|
||||
|
25
sites/dev/docs/reference/api/attributes/get/readme.mdx
Normal file
25
sites/dev/docs/reference/api/attributes/get/readme.mdx
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
title: Attributes.get()
|
||||
---
|
||||
|
||||
The `Attributes.get()` method will return the value of attribute stored under
|
||||
`key`, or `false` if it's not set.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
string attributes.get(string key)
|
||||
```
|
||||
|
||||
If key has multiple values, they will be joined together in a string, separated by spaces.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'classA')
|
||||
.add('class', 'classB')
|
||||
|
||||
const class = attr.get('class')
|
||||
// class now holds: "classA classB"
|
||||
```
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
title: Attributes.getAsArray()
|
||||
---
|
||||
|
||||
The `Attributes.getAsArray()` method will return an array with the value of
|
||||
attribute stored under `key`, or `false` if it's not set.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array attributes.getAsArray(string key)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'classA')
|
||||
.add('class', 'classB')
|
||||
|
||||
const class = attr.getAsArray('class')
|
||||
// class now holds: [ "classA", "classB" ]
|
||||
```
|
35
sites/dev/docs/reference/api/attributes/readme.mdx
Normal file
35
sites/dev/docs/reference/api/attributes/readme.mdx
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
title: Attributes
|
||||
---
|
||||
|
||||
An Attributes object holds attributes for a variety of other objects.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Attributes new Attributes()
|
||||
```
|
||||
|
||||
The Attributes constructor takes no arguments.
|
||||
|
||||
## Properties
|
||||
|
||||
An Attributes object comes with the following property:
|
||||
|
||||
- `list` : Holds the internal object in which attributes are stored
|
||||
|
||||
## Methods
|
||||
An Attributes object exposes the following methods:
|
||||
|
||||
<ReadMore />
|
||||
|
||||
## Notes
|
||||
|
||||
Attributes are attached to [`Point`](/reference/api/point),
|
||||
[`Path`](/reference/api/path), and [`Snippet`](/reference/api/snippet) objects,
|
||||
as well as the internal [`Svg`](/reference/api/svg) object.
|
||||
|
||||
All of these have an instantiated Attributes object in their `attributes`
|
||||
property, as well as a number of (chainable) helper methods to manipulate the
|
||||
attributes. You will typically use these higher-level method and thus are
|
||||
unlikely to interact with an Attributes object directly.
|
23
sites/dev/docs/reference/api/attributes/remove/readme.mdx
Normal file
23
sites/dev/docs/reference/api/attributes/remove/readme.mdx
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
title: Attributes.remove()
|
||||
---
|
||||
|
||||
The `Attributes.remove()` method removes the attribute values under key and
|
||||
returns the Attributes object.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Attributes attributes.remove(string key)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'classA')
|
||||
.add('class', 'classB')
|
||||
.remove('class')
|
||||
|
||||
// attr holds no data
|
||||
```
|
23
sites/dev/docs/reference/api/attributes/render/readme.mdx
Normal file
23
sites/dev/docs/reference/api/attributes/render/readme.mdx
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
title: Attributes.render()
|
||||
---
|
||||
|
||||
The `Attributes.render()` method will render attributes as a string suitable
|
||||
for inclusion in an SVG tag.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
string attributes.render()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.set('id', 'example')
|
||||
.add('class', 'classA')
|
||||
.add('class', 'classb')
|
||||
|
||||
const paragraph = `<p ${attr.render()}>Hello</p>`
|
||||
```
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: Attributes.renderAsCss()
|
||||
---
|
||||
|
||||
The `Attributes.renderAsCss()` method will render attributes as a string
|
||||
suitable for inclusion in a CSS definition.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
string attributes.renderAsCss()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('stroke', 'red')
|
||||
.add('stroke-width', 2)
|
||||
.add('stroke-dasharray', '3 1')
|
||||
|
||||
const css = `
|
||||
path {
|
||||
${attr.renderAsCss()}
|
||||
}
|
||||
`
|
||||
```
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
title: Attributes.renderIfPrefixIs()
|
||||
---
|
||||
|
||||
The `Attributes.renderIfPrefixIs()` method will render attributes as a string
|
||||
suitable for inclusion in an SVG tag, but only those attribute keys who start
|
||||
with `prefix`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
string attributes.renderIfPrefixIs(string prefix)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'various')
|
||||
.add('stroke', 'red')
|
||||
.add('stroke-width', 2)
|
||||
|
||||
const line = `<path ${attr.renderIfPrefixIs('stroke')} d="M 0,0 L 100.0" />`
|
||||
```
|
29
sites/dev/docs/reference/api/attributes/set/readme.mdx
Normal file
29
sites/dev/docs/reference/api/attributes/set/readme.mdx
Normal file
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
title: Attributes.set()
|
||||
---
|
||||
|
||||
The `Attributes.set()` method sets the attribute identified by `key` to value
|
||||
`value`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Attributes attributes.set(string key, string value)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.add('class', 'classA')
|
||||
.add('class', 'classB')
|
||||
|
||||
const class = attr.get('class')
|
||||
// class now holds: "classA classB"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
This will overwrite any value that's currently set on the attribute identified
|
||||
by `key`.
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: Attributes.setIfUnset()
|
||||
---
|
||||
|
||||
The `Attributes.setIfUnset()` method sets the attribute identified by `key` to
|
||||
value `value` but only if it's currently unset (`undefined`).
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Attributes attributes.setIfUnset(string key, string value)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const attr = new Attributes()
|
||||
.setIfUnset('class', 'classA')
|
||||
.setIfUnset('class', 'classB')
|
||||
|
||||
const class = attr.get('class')
|
||||
// class now holds: "classA"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
This will never overwrite any value and thus is a safe way to set attributes
|
44
sites/dev/docs/reference/api/defs/asrenderprops/readme.mdx
Normal file
44
sites/dev/docs/reference/api/defs/asrenderprops/readme.mdx
Normal file
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
title: Defs.asRenderProps()
|
||||
---
|
||||
|
||||
Returns the Defs as render props, suitable for front-end rendering.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Object defs.asRenderProps()
|
||||
```
|
||||
|
||||
The object returned by this method will have a `list` property that
|
||||
holds all the defs, as well as a `asSvg` property that holds the result
|
||||
of [Defs.render()](/reference/api/defs/render):
|
||||
|
||||
```js
|
||||
{
|
||||
list: {
|
||||
button: `<g id="button" transform="scale(1)">
|
||||
<circle cx="0" cy="0" r="3.4" class="mark"></circle>
|
||||
<circle cx="-1" cy="-1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="1" cy="-1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="1" cy="1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="-1" cy="1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
</g>`,
|
||||
buttonhole: `<g id="buttonhole" transform="scale(1)">
|
||||
<path class="mark" d="M -1,-5 L 1,-5 L 1,5 L -1,5 z"></path>
|
||||
</g>`,
|
||||
},
|
||||
forSvg: `
|
||||
<g id="button" transform="scale(1)">
|
||||
<circle cx="0" cy="0" r="3.4" class="mark"></circle>
|
||||
<circle cx="-1" cy="-1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="1" cy="-1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="1" cy="1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="-1" cy="1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
</g>
|
||||
<g id="buttonhole" transform="scale(1)">
|
||||
<path class="mark" d="M -1,-5 L 1,-5 L 1,5 L -1,5 z"></path>
|
||||
</g>
|
||||
`
|
||||
}
|
||||
```
|
11
sites/dev/docs/reference/api/defs/clone/readme.mdx
Normal file
11
sites/dev/docs/reference/api/defs/clone/readme.mdx
Normal file
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: Defs.clone()
|
||||
---
|
||||
|
||||
Returns a Defs object that is a deep copy of this one.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Defs defs.clone()
|
||||
```
|
12
sites/dev/docs/reference/api/defs/get/readme.mdx
Normal file
12
sites/dev/docs/reference/api/defs/get/readme.mdx
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: Defs.get()
|
||||
---
|
||||
|
||||
Returns the value of a defs entry stored under _name_.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
String defs.get(string name)
|
||||
```
|
||||
|
22
sites/dev/docs/reference/api/defs/readme.mdx
Normal file
22
sites/dev/docs/reference/api/defs/readme.mdx
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
title: Defs
|
||||
---
|
||||
|
||||
The `Defs` object in FreeSewing's core library represents an SVG document's
|
||||
[`defs` element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs).
|
||||
It is not directly exposed, but it is available as the `defs` attribute
|
||||
of an [Svg object](/reference/api/svg/defs).
|
||||
|
||||
While the properties and methods exposed by this object are typically only used internally,
|
||||
they are documented here to facilitate development of plugins.
|
||||
|
||||
## Properties
|
||||
|
||||
A Defs object comes with the following property:
|
||||
|
||||
- `list` : Holds the internal object in which entries of the `defs` element are stored
|
||||
|
||||
## Defs methods
|
||||
|
||||
<ReadMore />
|
||||
|
15
sites/dev/docs/reference/api/defs/remove/readme.mdx
Normal file
15
sites/dev/docs/reference/api/defs/remove/readme.mdx
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
title: Defs.remove()
|
||||
---
|
||||
|
||||
Removes the defs entry stored under _name_.
|
||||
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Defs defs.remove(string name)
|
||||
```
|
||||
|
||||
This object is chainable as it returns the `Defs` object.
|
||||
|
27
sites/dev/docs/reference/api/defs/render/readme.mdx
Normal file
27
sites/dev/docs/reference/api/defs/render/readme.mdx
Normal file
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
title: Defs.render()
|
||||
---
|
||||
|
||||
Renders the added Defs as a string suitable for inclusion in an SVG document `defs` element.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
String defs.render()
|
||||
```
|
||||
|
||||
This function is called by [svg.render()](/reference/api/svg/render) internally.
|
||||
Its output will look something like this:
|
||||
|
||||
```()
|
||||
<g id="button" transform="scale(1)">
|
||||
<circle cx="0" cy="0" r="3.4" class="mark"></circle>
|
||||
<circle cx="-1" cy="-1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="1" cy="-1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="1" cy="1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
<circle cx="-1" cy="1" r="0.5" class="no-stroke fill-mark"></circle>
|
||||
</g>
|
||||
<g id="buttonhole" transform="scale(1)">
|
||||
<path class="mark" d="M -1,-5 L 1,-5 L 1,5 L -1,5 z"></path>
|
||||
</g>
|
||||
```
|
17
sites/dev/docs/reference/api/defs/set/readme.mdx
Normal file
17
sites/dev/docs/reference/api/defs/set/readme.mdx
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
title: Defs.set()
|
||||
---
|
||||
|
||||
Sets the defs entry stored under _name_ to _value_.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Defs defs.set(
|
||||
String name,
|
||||
String value
|
||||
)
|
||||
```
|
||||
|
||||
This object is chainable as it returns the `Defs` object.
|
||||
|
17
sites/dev/docs/reference/api/defs/setifunset/readme.mdx
Normal file
17
sites/dev/docs/reference/api/defs/setifunset/readme.mdx
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
title: Defs.setIfUnset()
|
||||
---
|
||||
|
||||
Sets the defs entry stored under _name_ to _value_, but only if it
|
||||
is not currently set to any value (if it is undefined).
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Defs defs.setIfUnset(
|
||||
String name,
|
||||
String value
|
||||
)
|
||||
```
|
||||
|
||||
This object is chainable as it returns the `Defs` object.
|
77
sites/dev/docs/reference/api/design/readme.mdx
Normal file
77
sites/dev/docs/reference/api/design/readme.mdx
Normal file
|
@ -0,0 +1,77 @@
|
|||
---
|
||||
title: Design
|
||||
---
|
||||
|
||||
The `Design` named export in FreeSewing's core library is a constructor that
|
||||
creates new pattern designs.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Pattern Design({
|
||||
array parts,
|
||||
object data
|
||||
})
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const Sorcha = new Design({
|
||||
// design configuration here
|
||||
})
|
||||
```
|
||||
|
||||
This constructor creates a new pattern design.
|
||||
It takes a single argument, an object holding the design's configuration.
|
||||
|
||||
## Design configuration
|
||||
|
||||
Since a design's configuration is managed at the part level,
|
||||
the Design configuration object only requires a `parts` property that should
|
||||
hold an array of parts to include in the Design.
|
||||
|
||||
```js
|
||||
const Sorcha = new Design({
|
||||
parts: [ front, back, sleeve ],
|
||||
})
|
||||
```
|
||||
|
||||
:::tipA Design in FreeSewing is little more than a container for various Parts:::
|
||||
|
||||
Optionally, you can also pass it a `data` attribute
|
||||
to hold any custom data you'd like to add to your Design.
|
||||
|
||||
Any `data` you add to the Design constructor will be added
|
||||
to [the Store](/reference/api/store).
|
||||
|
||||
```js
|
||||
const Sorcha = new Design({
|
||||
parts: [ front, back, sleeve ],
|
||||
data: {
|
||||
version: 3,
|
||||
price: 12,
|
||||
currency: 'euro'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
The Design constructor is a _super-constructor_.
|
||||
It will return a constructor method that will a pattern based on your design.
|
||||
|
||||
## Properties
|
||||
|
||||
In addition to the returned constructor method, an instantiated Design object
|
||||
also provides the following properties:
|
||||
|
||||
### Design.designConfig
|
||||
|
||||
This holds the design configuration as passed to the Design constructor.
|
||||
|
||||
### Design.patternConfig
|
||||
|
||||
Holds the resolved pattern configuration based on the configuration passed to the Design constructor.
|
||||
|
31
sites/dev/docs/reference/api/part/asrenderprops/readme.mdx
Normal file
31
sites/dev/docs/reference/api/part/asrenderprops/readme.mdx
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
title: Part.asRenderProps()
|
||||
---
|
||||
|
||||
|
||||
The `Part.asRenderProps()` method will return the data stored in the
|
||||
part as a serializable JavaScript object. This method is typically
|
||||
not invoked directly but rather called under the hood as a result of
|
||||
calling [`Pattern.getRenderProps()`](/reference/api/pattern/getrenderprops).
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Object part.asRenderProps()
|
||||
```
|
||||
|
||||
## Returned object properties
|
||||
|
||||
This returns JavaScript object has the following properties:
|
||||
|
||||
| Name | Description |
|
||||
| ----:| ----------- |
|
||||
| `paths` | The part's paths as [Path.asRenderProps()](/reference/api/path/asrenderprops) |
|
||||
| `points` | The part's points as [Point.asRenderProps()](/reference/api/point/asrenderprops) |
|
||||
| `snippet` | The part's snippets as [Snippet.asRenderProps()](/reference/api/snippet/asrenderprops) |
|
||||
| `attributes` | The result of [Part.attributes.asRenderProps()](/reference/api/attributes/asrenderprops) |
|
||||
| `height` | A number indicating the part height in `mm` |
|
||||
| `width` | A number indicating the part width in `mm` |
|
||||
| `topLeft` | The [Point](/reference/api/point) at the top left of the part, or rather its [`Point.asRenderProps()`](/reference/api/point/asrenderprops) result |
|
||||
| `bottomRight` | The [Point](/reference/api/point) at the bottom right of the part, or rather its [`Point.asRenderProps()`](/reference/api/point/asrenderprops) result |
|
||||
|
57
sites/dev/docs/reference/api/part/attr/readme.mdx
Normal file
57
sites/dev/docs/reference/api/part/attr/readme.mdx
Normal file
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
title: Part.attr()
|
||||
---
|
||||
|
||||
This `Part.attr()` method can be used to add attributes to the Part object.
|
||||
It calls `this.attributes.add()` under the hood, and returns the Part object.
|
||||
|
||||
If the third parameter is set to `true` it will call `this.attributes.set()`
|
||||
instead, thereby overwriting the value of the attribute.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
|
||||
Part Part.attr(
|
||||
string name,
|
||||
mixed value,
|
||||
bool overwrite = false
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
This method is chainable as it returns the `Part` object
|
||||
|
||||
:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption=" Example of the Part.attr() method">
|
||||
|
||||
```js
|
||||
|
||||
({ part, points, Point, Path, paths }) => {
|
||||
|
||||
points.A = new Point(0,0)
|
||||
points.B = new Point(0,40)
|
||||
points.C = new Point(100,40)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.B)
|
||||
.line(points.C)
|
||||
.line(points.A)
|
||||
.line(points.B)
|
||||
.close()
|
||||
.addText('I have been flipped!', 'left')
|
||||
|
||||
part.attr('transform', 'scale(1,-1) translate(0,-40)')
|
||||
|
||||
return part
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
</Example>
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
---
|
||||
title: Part dependencies
|
||||
---
|
||||
|
||||
Dependencies in a part's configuration object are controlled by the `from` and `after` properties.
|
||||
|
||||
:::note
|
||||
|
||||
In both cases, you should specify the actual configuration object of the dependency part,
|
||||
not merely a string with its name.
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Dependencies configured on parts do not need to be included in the `parts` property
|
||||
passed to [the Design constructor](/reference/api/design). FreeSewing core will
|
||||
recursively resolve all dependencies and add them to the design for you.
|
||||
|
||||
:::
|
||||
|
||||
## after
|
||||
|
||||
The `after` property holds an array of parts that should be drafted before the current part:
|
||||
|
||||
```js
|
||||
import { exampleBack } from './back.mjs'
|
||||
import { exampleFront } from './front.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'example.sleeve',
|
||||
after: [ exampleBack, exampleFront ],
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
The effect of the `after` property is that drafting of this part will be deferred until all the parts listed
|
||||
in the `after` property are drafted.
|
||||
|
||||
:::tip
|
||||
|
||||
If you only have one part for the `after` property, you do not have to specify an array:
|
||||
|
||||
```js
|
||||
import { exampleBack } from './back.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
after: exampleBack,
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## from
|
||||
|
||||
The `from` property holds a part that should be used as the base for the current part.
|
||||
In other words, the current part will _extend_ the part listed in `front` and inherit all its content.
|
||||
|
||||
```js
|
||||
import { exampleBack } from './back.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
from: exampleBack,
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
:::warning
|
||||
|
||||
Unlike `after`, `from` only ever takes one part since you can only extend one part.
|
||||
|
||||
:::
|
||||
|
265
sites/dev/docs/reference/api/part/config/hide/readme.mdx
Normal file
265
sites/dev/docs/reference/api/part/config/hide/readme.mdx
Normal file
|
@ -0,0 +1,265 @@
|
|||
---
|
||||
title: Hiding parts
|
||||
---
|
||||
|
||||
The `hide` option of a part's configuration controls how to hide it and/or its dependencies.
|
||||
|
||||
:::tipA hidden part will not be included in the output when it's rendered:::
|
||||
:::tipThe `hide` configuration from parts that you include in your design will always override configuration from inherited parts.:::
|
||||
|
||||
## Settings
|
||||
|
||||
### hide.after
|
||||
|
||||
To hide the explicitly included `after` parts, set `hide.after` to a truthy value
|
||||
|
||||
```js
|
||||
import exampleBase from './base.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
after: [exampleBase],
|
||||
// hide `exampleBase`
|
||||
hide: {after: true},
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### hide.always
|
||||
|
||||
To hide a specific part that would otherwise not be hidden by other configuration, add its name to the `hide.always` array
|
||||
|
||||
```js
|
||||
import { exampleBase } from './base.mjs'
|
||||
import { exampleBack } from './back.mjs'
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
after: [exampleBase, exampleBack],
|
||||
// hide `exampleBack`
|
||||
hide: {always: ['example.back']},
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
### hide.from
|
||||
|
||||
To hide the explicitly included `from` part, set `hide.from` to a truthy value.
|
||||
|
||||
```js
|
||||
import exampleBase from './base.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'other.base',
|
||||
from: exampleBase,
|
||||
// hide exampleBase
|
||||
hide: {from: true},
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
### hide.inherited
|
||||
|
||||
To hide parts that you have not explicitly included in this part that may be pulled in by the explicitly included `from` and `after` parts, set `hide.inherited` to a truthy value.
|
||||
|
||||
:::noteThis setting will hide any part included as `from` or `after` by your explicitly included `from` part or its dependency chain. It will also hide any part included as `from` by your explicitly included `after` part or its dependency chain. It will not hide the `after` parts of `after` parts:::
|
||||
|
||||
```js
|
||||
// the "after" chain
|
||||
const mainFrontParent = {
|
||||
name: 'other.mainFront',
|
||||
draft: ({part}) => part
|
||||
}
|
||||
const mainFrontBase = {
|
||||
name: 'example.mainFrontBase',
|
||||
draft: ({part}) => part
|
||||
}
|
||||
const mainFront = {
|
||||
name: 'example.mainFront',
|
||||
after: mainFrontBase,
|
||||
from: mainFrontParent,
|
||||
draft: ({part}) => part
|
||||
}
|
||||
|
||||
// the "from" chain
|
||||
const grandParentBase = {
|
||||
name: 'other.grandParentBase',
|
||||
draft: ({part}) => part
|
||||
}
|
||||
const grandParent = {
|
||||
name: 'other.grandParent',
|
||||
after: grandParentBase
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
const parent = {
|
||||
name: 'other.parent',
|
||||
from: grandParent
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
|
||||
|
||||
const mainBack = {
|
||||
name: 'example.mainBack',
|
||||
from: parent,
|
||||
after: mainFront,
|
||||
// hide grandParentBase, grandParent, mainFrontParent
|
||||
// don't hide parent, mainFront, or mainFrontBase
|
||||
hide: { inherited: true },
|
||||
draft: ({part}) => part
|
||||
}
|
||||
|
||||
```
|
||||
:::tip
|
||||
<details>
|
||||
<summary>Need more clarity?</summary>
|
||||
|
||||
In the above example, the dependency tree for the part `example.mainBack` resolves to the following, with `from` dependencies in **bold** and `after` dependencies *italicized*.
|
||||
|
||||
|
||||
| Part | Dependency Type | Hidden |
|
||||
| :---------- | :---------- | :-----|
|
||||
| example.mainBack | root | false |
|
||||
| - **other.parent** | from | false |
|
||||
| - - **other.grandParent** | inherited from | true |
|
||||
| - - - *other.grandParentBase* | inherited after | true |
|
||||
| - *example.mainFront* | after | false |
|
||||
| - - *example.mainFrontBase* | after | false |
|
||||
| - - **other.mainFront** | inherited from | true |
|
||||
|
||||
Dependencies are considered inherited if they have two or more dashes (-) next to them, and are either **bold** themselves, or underneath a **bold** part.
|
||||
</details>
|
||||
:::
|
||||
|
||||
### hide.never
|
||||
|
||||
To __not__ hide a specific part that would otherwise be hidden by other configuration, add its name to the `hide.never` array
|
||||
|
||||
```js
|
||||
import { exampleBase } from './base.mjs'
|
||||
import { exampleBack } from './back.mjs'
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
after: [exampleBase, exampleBack],
|
||||
hide: {
|
||||
// hide exampleBase and exampleBack
|
||||
after: true,
|
||||
// override hiding exampleBack so that it is shown
|
||||
never: ['example.back']
|
||||
},
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
### hide.self
|
||||
|
||||
To hide the current part, set `hide.self` to a truthy value:
|
||||
|
||||
```js
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
// hide `example.front`
|
||||
hide: {self: true},
|
||||
draft: (({ part }) => part)
|
||||
}
|
||||
```
|
||||
|
||||
## Presets
|
||||
We provide two presets for common hiding configurations. For convenience, you can pass a preset to the `hide` configuration as a string like `hide: <preset name>`, or you can use `import { hidePresets } from '@freesewing.core` and pass `hide: hidePresets.<preset name>`
|
||||
|
||||
:::tip If you don't like to remember strings and you're working in development a environment that has code completion, importing the presets from `@freesewing/core` will help you be sure you're definitely using an available preset :::
|
||||
|
||||
### HIDE_ALL
|
||||
For a shortcut to setting all `boolean` hiding options ([`after`](#hideafter), [`from`](#hidefrom), [`inherited`](#hideinherited), and [`self`](#hideself)) to true, use `HIDE_ALL`
|
||||
:::note
|
||||
This is equivalent to using
|
||||
|
||||
```js
|
||||
{
|
||||
self: true,
|
||||
after: true,
|
||||
from: true,
|
||||
inherited: true
|
||||
}
|
||||
```
|
||||
:::
|
||||
|
||||
To use it as an imported preset:
|
||||
```js
|
||||
import { hidePresets } from '@freesewing/core'
|
||||
import { exampleBase } from './base.mjs'
|
||||
import { exampleBack } from './back.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
from: exampleBase
|
||||
after: [exampleBack],
|
||||
// hide `example.front`, `exmpleBase`, and `exampleBack`
|
||||
// as well as any inherited parts
|
||||
hide: hidePresets.HIDE_ALL,
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
To use it as a string
|
||||
```js
|
||||
import { exampleBase } from './base.mjs'
|
||||
import { exampleBack } from './back.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
from: exampleBase,
|
||||
after: [exampleBack],
|
||||
// hide `example.front`, `exmpleBase`, and `exampleBack`
|
||||
// as well as any inherited parts
|
||||
hide: 'HIDE_ALL',
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
### HIDE_TREE
|
||||
For a shortcut to setting [`from: true`](#hidefrom) and [`inherited: true`](#hideinherited), use `HIDE_TREE`
|
||||
|
||||
:::note
|
||||
This is equivalent to using
|
||||
|
||||
```js
|
||||
{
|
||||
from: true,
|
||||
inherited: true
|
||||
}
|
||||
````
|
||||
:::
|
||||
:::note RELATED
|
||||
See [`hide.inherited`](#hideinherited) for a full explanation of how that option works
|
||||
:::
|
||||
|
||||
To use it as an imported preset:
|
||||
```js
|
||||
import { hidePresets } from '@freesewing/core'
|
||||
import { exampleBase } from './base.mjs'
|
||||
import { exampleBack } from './back.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
from: exampleBase,
|
||||
// hide `exmpleBase`, and all inherited parts
|
||||
hide: hidePresets.HIDE_TREE,
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
To use it as a string
|
||||
```js
|
||||
import { exampleBase } from './base.mjs'
|
||||
import { exampleBack } from './back.mjs'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
from: exampleBase,
|
||||
// hide `exmpleBase`, and all inherited parts
|
||||
hide: 'HIDE_TREE',
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
title: Part measurements
|
||||
---
|
||||
|
||||
The `measurements` and `optionalMeasurements` properties on the
|
||||
part configuration object list the part's required and optional
|
||||
measurements respectively.
|
||||
|
||||
:::tipYou should only include what's required by the part itself, not its dependencies:::
|
||||
|
||||
## measurements
|
||||
|
||||
The `measurements` property should hold the names of the measurements
|
||||
that are required to draft the current part.
|
||||
|
||||
```js
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
measurements: [ 'head', 'chest' ],
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
## optionalMeasurements
|
||||
|
||||
The `optionalMeasurements` property should hold the names of the measurements
|
||||
that are optional to draft the current part.
|
||||
|
||||
```js
|
||||
import { pluginBust } from '@freesewing/plugin-bust'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
plugins: [ pluginBust ],
|
||||
measurements: [ 'head', 'chest' ],
|
||||
optionalMeasurements: [ 'highBust' ],
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
24
sites/dev/docs/reference/api/part/config/name/readme.mdx
Normal file
24
sites/dev/docs/reference/api/part/config/name/readme.mdx
Normal file
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
title: Naming parts
|
||||
---
|
||||
|
||||
The `name` property is -- together with [the `draft()`
|
||||
method](/reference/api/part/draft) -- the
|
||||
only mandatory property in a part's configuration object.
|
||||
|
||||
It should hold a string and be unique in the design:
|
||||
|
||||
```js
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
We recommend to use a `design.part` format when naming your part.
|
||||
This avoids naming clashes when people re-use your parts in other designs.
|
||||
|
||||
:::
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: Boolean options
|
||||
---
|
||||
|
||||
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
|
||||
|
||||
:::tip
|
||||
|
||||
Like all options that are configured through an object, you can
|
||||
add more properties to the options' object to implement functionality on
|
||||
top of what's provided by the core library.
|
||||
|
||||
Refer to [extending options](/reference/api/part/config/options/extend) for
|
||||
more details.
|
||||
|
||||
:::
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
options: {
|
||||
withLining: {
|
||||
bool: true
|
||||
}
|
||||
},
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
title: Constant options
|
||||
---
|
||||
|
||||
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
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
options: {
|
||||
collarFactor: 4.8,
|
||||
fitCollar: false,
|
||||
},
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
:::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 use your
|
||||
part as a dependency can override 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.
|
||||
|
||||
:::
|
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: Counter options
|
||||
---
|
||||
|
||||
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 minimum integer value that's allowed
|
||||
- `max` : The maximum integer value that's allowed
|
||||
|
||||
:::tip
|
||||
|
||||
Like all options that are configured through an object, you can
|
||||
add more properties to the options' object to implement functionality on
|
||||
top of what's provided by the core library.
|
||||
|
||||
Refer to [extending options](/reference/api/part/config/options/extend) for
|
||||
more details.
|
||||
|
||||
:::
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
butttons: {
|
||||
count: 7,
|
||||
min: 4,
|
||||
max: 12
|
||||
}
|
||||
}
|
||||
```
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
title: Degree options
|
||||
---
|
||||
|
||||
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 minimum that's allowed
|
||||
- `max` : The maximum that's allowed
|
||||
|
||||
:::tip
|
||||
|
||||
Like all options that are configured through an object, you can
|
||||
add more properties to the options' object to implement functionality on
|
||||
top of what's provided by the core library.
|
||||
|
||||
Refer to [extending options](/reference/api/part/config/options/extend) for
|
||||
more details.
|
||||
|
||||
:::
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
collarAngle: {
|
||||
deg: 85,
|
||||
min: 60,
|
||||
max: 130,
|
||||
}
|
||||
}
|
||||
```
|
|
@ -0,0 +1,122 @@
|
|||
---
|
||||
title: Extending options
|
||||
---
|
||||
|
||||
Additional, optional information can be added to options to extend
|
||||
their use outside of core functionality.
|
||||
This can be useful when using FreeSewing through a frontend UI.
|
||||
The extended information can be used by the frontend to affect
|
||||
how options are presented.
|
||||
|
||||
|
||||
## Add menu structure
|
||||
|
||||
Because FreeSewing designs have been written with the expectation that
|
||||
they will be used primarily through the freesewing.org website,
|
||||
their options have been extended with menu information.
|
||||
|
||||
```js
|
||||
options: {
|
||||
// Fit
|
||||
waistEase: { pct: 2, min: 0, max: 10, menu: 'fit', order: '100' },
|
||||
seatEase: { pct: 5, min: 0, max: 15, menu: 'fit', order: '200' },
|
||||
// Style
|
||||
waistHeight: { pct: 5, min: 0, max: 100, menu: 'style', order: '400' },
|
||||
lengthBonus: { pct: 0, min: -15, max: 10, menu: 'style', order: '300' },
|
||||
elasticatedCuff: { bool: true, menu: 'style' },
|
||||
buttons = { count: 7, min: 4, max: 12, menu: 'style.closure', order: '800' }
|
||||
extraTopButton = { bool: true, menu: 'style.closure', order: '850' }
|
||||
}
|
||||
```
|
||||
|
||||
In the above example, the added `menu` attributes provide the
|
||||
freesewing.org website UI with information about the options
|
||||
should appear in menus.
|
||||
- The `waistEase` and `seatEase` options should appear in the `fit`
|
||||
menu while the other options go in the `style` menu.
|
||||
- Additionally, the `buttons` and `extraTopButton` options should
|
||||
appear in a `closure` submenu under the `style` menu.
|
||||
|
||||
The optional 'order' attributes provide the UI with information about
|
||||
the order in which options and menus should appear.
|
||||
- Within the `fit` menu, `waistEase` should come before `seatEase`.
|
||||
- Within the `style` menu, options should be in the order
|
||||
`lengthBonus`, `waistHeight`, `buttons`, `extraTopButton`, and
|
||||
`elasticatedCuff`.
|
||||
- The `elasticatedCuff` option does not have an `order` attribute,
|
||||
so it should appear after the options that do.
|
||||
- Because the `fit` menu has an option with an `order` value that comes
|
||||
before any of the `order` values for options in the `style` menu,
|
||||
the `fit` menu should appear before the `style` menu.
|
||||
|
||||
:::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
|
||||
|
||||
freesewing.org UI behavior:
|
||||
- Ordering is performed using an alphabetic, not numeric, sort.
|
||||
For example, `order` value "99" will be placed _after_ "100" because
|
||||
"1" comes before "9" alphabetically.
|
||||
However, "099" will be placed before "100", so using leading zeros
|
||||
can be helpful when using numbers as `order` values.
|
||||
- After they have been ordered using `order` attribute, if present,
|
||||
design options and menus are arranged in alphabetical order by
|
||||
their names.
|
||||
- However, the `advanced` menu, if present, is always ordered to
|
||||
be the last menu, appearing after all the other menus.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
## Suppress translation
|
||||
|
||||
When using `list` options, we usually we want the different options
|
||||
in the list 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.
|
||||
|
||||
:::
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
title: List options
|
||||
---
|
||||
|
||||
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
|
||||
|
||||
:::tip
|
||||
|
||||
Like all options that are configured through an object, you can
|
||||
add more properties to the options' object to implement functionality on
|
||||
top of what's provided by the core library.
|
||||
|
||||
Refer to [extending options](/reference/api/part/config/options/extend) for
|
||||
more details.
|
||||
|
||||
:::
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
cuffStyle: {
|
||||
dflt: "angledBarrelCuff",
|
||||
list: [
|
||||
"roundedBarrelCuff",
|
||||
"angledBarrelCuff",
|
||||
"straightBarrelCuff",
|
||||
"roundedFrenchCuff",
|
||||
"angledFrenchCuff",
|
||||
"straightFrenchCuff"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: Millimeter options
|
||||
---
|
||||
|
||||
:::warning
|
||||
|
||||
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 millimeters
|
||||
- `min` : The minimum that's allowed
|
||||
- `max` : The maximum that's allowed
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
options: {
|
||||
elasticWidth: {
|
||||
mm: 35,
|
||||
min: 5,
|
||||
max: 80
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::note 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.
|
||||
|
||||
:::
|
||||
|
||||
[1]: /reference/api/part/config/options/pct
|
|
@ -0,0 +1,94 @@
|
|||
---
|
||||
title: Setting a value in millimeter as a percentage option
|
||||
---
|
||||
|
||||
Percentage options are great for parametric design, 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 a percentage value. It is up to the
|
||||
frontend designer to then either set this value, or suggest it to
|
||||
the user.
|
||||
|
||||
:::
|
||||
|
||||
## Structure
|
||||
|
||||
The `fromAbs` property should hold a function with the following
|
||||
signature:
|
||||
|
||||
```js
|
||||
function fromAbs(millimeter, settings) {
|
||||
// return a percentage here (0.5 is 50%)
|
||||
}
|
||||
```
|
||||
|
||||
The first parameter is the desired value in millimeter (for example
|
||||
`130` for `13 cm`).
|
||||
The second parameter is the pattern's [settings](/reference/settings) object
|
||||
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'
|
||||
|
||||
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/part/config/options/pct/toabs) for details.
|
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
title: Percentage options
|
||||
---
|
||||
|
||||
Percentage options are the bread and butter of freesewing.
|
||||
Almost all your options will most likely be percentage options as
|
||||
they ensure that your part 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
|
||||
|
||||
:::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 part.
|
||||
|
||||
###### 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.
|
||||
|
||||
:::
|
||||
|
||||
:::tip
|
||||
|
||||
Like all options that are configured through an object, you can
|
||||
add more properties to the options' object to implement functionality on
|
||||
top of what's provided by the core library.
|
||||
|
||||
Refer to [extending options](/reference/api/part/config/options/extend) for
|
||||
more details.
|
||||
|
||||
:::
|
||||
|
||||
## Example
|
||||
|
||||
Below is a simple example:
|
||||
|
||||
```js
|
||||
options: {
|
||||
acrossBackFactor: {
|
||||
pct: 97,
|
||||
min: 93,
|
||||
max: 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced use
|
||||
|
||||
Percentage options have more advanced features that are supported by the core library.
|
||||
You can unlock those features by adding the following properties to your option:
|
||||
|
||||
- `fromAbs`: A method to [determine the percentage based on a value in millimeter][fromabs]
|
||||
- `toAbs`: A method to [return the option value in millimeter][toabs]
|
||||
- `snap`: The configuration to control [snapping of percentage options][snap]
|
||||
|
||||
[fromabs]: /reference/api/part/config/options/pct/fromabs
|
||||
[toabs]: /reference/api/part/config/options/pct/toabs
|
||||
[snap]: /reference/api/part/config/options/pct/snap
|
||||
|
||||
Refer to the relevant documentation for more details:
|
||||
|
||||
<ReadMore />
|
|
@ -0,0 +1,249 @@
|
|||
---
|
||||
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 below)
|
||||
- `toAbs`: a method returning the **millimeter value** of the option ([see `toAbs()`][toabs])
|
||||
|
||||
:::tip
|
||||
##### Values for snapped percentage options are available through `absoluteOptions`
|
||||
|
||||
Your draft method can not only destructure the `options` property to get access to options,
|
||||
it can also destructure the `absoluteOptions` property to get access to the values
|
||||
for those options with snaps configured.
|
||||
|
||||
See [the part `draft()` method](/reference/api/part/draft) for more details.
|
||||
|
||||
:::
|
||||
|
||||
## Snap configuration
|
||||
|
||||
A snapped percentage option requires a `snap` property that will determine
|
||||
what **value in millimeter** 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 `0 mm`, `7 mm`, `14 mm`, `21 mm`, `28 mm`, `35 mm`, `42 mm`, ...).
|
||||
|
||||
```js
|
||||
myOption: {
|
||||
pct:5,
|
||||
min: 0
|
||||
max: 25,
|
||||
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.
|
||||
|
||||
:::
|
||||
|
||||
### 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 mm` and `69.5 mm` -- 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 either a number or an array of numbers
|
||||
|
||||
In this case, the behavior is similar to either when `snap` holds a number or when it holds an array
|
||||
of numbers.
|
||||
|
||||
The difference is that this allows you to supply a different multiple value or list of snap values
|
||||
for users using metric or imperial units.
|
||||
|
||||
In the first example below, the value of [settings.units](/reference/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 mm` and `69.5 mm` for metric
|
||||
and between `12.7 mm` and `88.9 mm` for imperial -- the nearest snap value
|
||||
will be used. If instead it is outside the region of influence, the result of
|
||||
`toAbs()` will be used as-is.
|
||||
|
||||
```js
|
||||
myOption: {
|
||||
pct:5,
|
||||
min: 0
|
||||
max: 35,
|
||||
snap: {
|
||||
metric: [7, 12, 21, 34, 53, 64 ],
|
||||
imperial: [25.4, 50.8, 76.2 ],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this second example, the value of [settings.units](/reference/settings/units) will
|
||||
determine which multiple value gets used.
|
||||
|
||||
If set to `metric`, the absolute value of this option will be set to a multiple of `7`
|
||||
(so one of `0 mm`, `7 mm`, `14 mm`, `21 mm`, `28 mm`, `35 mm`, `42 mm`, ...).
|
||||
If set to `imperial`, the absolute value of this option will be set to a
|
||||
multiple of `25.4` (1 in.)
|
||||
(so one of `0 mm` (0 in.), `25.4 mm` (1 in.), `50.8 mm` (2 in.), `76.2 mm` (3 in.), ...).
|
||||
|
||||
```js
|
||||
myOption: {
|
||||
pct:5,
|
||||
min: 0
|
||||
max: 35,
|
||||
snap: {
|
||||
metric: 7,
|
||||
imperial: 25.4,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(Again, similar to when `snap` is set to a single number, the snap points
|
||||
will be distributed equally across the entire range, and
|
||||
the value will **always** be snapped,)
|
||||
|
||||
:::note
|
||||
|
||||
##### 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.
|
||||
|
||||
:::
|
||||
|
||||
## 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.12 mm` for
|
||||
user A and `27.83 mm` for user B.
|
||||
|
||||
Elastic of that width is not 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 B (with a list option).
|
||||
|
||||
For dolls and giants, the option will revert to the parametric value and
|
||||
behave just like Approach A (with a percentage option).
|
||||
|
||||
## How snapped percentage options work
|
||||
|
||||
Before we wade into the details of how snapped percentage options are handled
|
||||
under the hood, let's first agree on terminology:
|
||||
|
||||
- The **percentage value** is the value passed by the user for the option.
|
||||
Its value always represents a percentage. For example `0.5` for 50%.
|
||||
- The **millimeter value** is the result of feeding the **percentage value** to
|
||||
the `toAbs()` method. Its value always represents millimeters. For example `12 mm`.
|
||||
- The **snap values** are the values provided by the snap configuration.
|
||||
Each of the values always represents millimeters (even for imperial users).
|
||||
|
||||
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
|
||||
|
||||
[toabs]: /reference/api/part/config/options/pct/toabs
|
||||
|
||||
[pct]: /reference/api/part/config/options/pct
|
||||
|
||||
[list]: /reference/api/part/config/options/list
|
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
title: Reporting a percentage option value in millimeter
|
||||
---
|
||||
|
||||
Percentage options are great for parametric design, 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, mergeOptions) {
|
||||
// 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 holds the pattern's [settings](/reference/settings) object
|
||||
which holds -- among other things -- the measurements provided by the user.
|
||||
|
||||
The third parameter should be the return value of
|
||||
[utils.mergeOptions()](/reference/api/utils/mergeoptions), which provides an
|
||||
object with all option values populated. Although this parameter is not
|
||||
required for simple values based on measurements, it is often required when the
|
||||
result depends on several options.
|
||||
|
||||
## 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'
|
||||
|
||||
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](/reference/api/part/config/options/pct/fromabs) for details.
|
75
sites/dev/docs/reference/api/part/config/options/readme.mdx
Normal file
75
sites/dev/docs/reference/api/part/config/options/readme.mdx
Normal file
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
title: Part options
|
||||
---
|
||||
|
||||
The `options` property on the part configuration object
|
||||
list the part's options:
|
||||
|
||||
```js
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
options: {
|
||||
chestEase: { pct: 12, min: 0, max: 25 },
|
||||
},
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
## The use case for 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 measurements.
|
||||
|
||||
This _bespoke_ 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 part's configuration is what makes this
|
||||
possible.
|
||||
|
||||
## Types of options
|
||||
|
||||
These are the types of options supported by the FreeSewing core library:
|
||||
|
||||
1. [**boolean** options][bool] are for yes/no choices
|
||||
2. [**constant** options][const] are used as [feature flags](https://en.wikipedia.org/wiki/Feature_toggle) or to hard-code certain values yet still allow them to be changed when the part is extended
|
||||
3. [**counter** options][count] are for integer values
|
||||
4. [**degree** options][deg] are for degrees
|
||||
5. [**list** options][list] are for a list of possible choices
|
||||
6. [**millimeter** options][mm] are supported but not recommended (see warning below)
|
||||
7. [**percentage** options][pct] are for percentages (and can optionally be [**snapped percentage** options][snapped])
|
||||
|
||||
These options can be [extended][extend] with additional, optional
|
||||
information to help with their use outside of the core.
|
||||
|
||||
:::tip
|
||||
|
||||
In parametric design, percentage options are by far the most common.
|
||||
They also have the most features and flexibility.
|
||||
|
||||
:::
|
||||
|
||||
:::warning
|
||||
|
||||
While our core library supports millimeter (`mm`) options,
|
||||
we do not allow them in designs contributed to FreeSewing.org
|
||||
as they are a _red flag_ for poor parametric design.
|
||||
|
||||
If you believe you need `mm` options, look into [snapped
|
||||
percentage options][snapped] instead.
|
||||
|
||||
:::
|
||||
|
||||
[bool]: /reference/api/part/config/options/bool
|
||||
[const]: /reference/api/part/config/options/const
|
||||
[count]: /reference/api/part/config/options/counter
|
||||
[deg]: /reference/api/part/config/options/deg
|
||||
[list]: /reference/api/part/config/options/list
|
||||
[pct]: /reference/api/part/config/options/pct
|
||||
[snapped]: /reference/api/part/config/options/pct/snap
|
||||
[mm]: /reference/api/part/config/options/mm
|
||||
[extend]: /reference/api/part/config/options/extend
|
68
sites/dev/docs/reference/api/part/config/plugins/readme.mdx
Normal file
68
sites/dev/docs/reference/api/part/config/plugins/readme.mdx
Normal file
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
title: Part plugins
|
||||
---
|
||||
|
||||
The `plugins` property on the part configuration object
|
||||
list the plugins that are used in/required by the part:
|
||||
|
||||
```js
|
||||
import { pluginBundle } from '@freesewing/plugin-bundle'
|
||||
import { pluginBust } from '@freesewing/plugin-bust'
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
plugins: [ pluginBundle, pluginBust ],
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
:::tip
|
||||
|
||||
You should only list the plugins that are required by the part itself,
|
||||
not those required by its dependencies
|
||||
|
||||
:::
|
||||
|
||||
## Passing data to a plugin
|
||||
|
||||
Some plugins require you to pass data to the plugin.
|
||||
For these, pass an `[plugin, data]` array:
|
||||
|
||||
```js
|
||||
import { pluginBundle } from '@freesewing/plugin-bundle'
|
||||
import { myDataPlugin } from 'myDataPlugin'
|
||||
|
||||
const myData = {
|
||||
some: 'data'
|
||||
}
|
||||
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
plugins: [ pluginBundle, [ myDataPlugin, data ] ],
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
## Conditional plugins
|
||||
|
||||
A conditional plugin is loaded only when a condition is met.
|
||||
The plugin and condition should be provided as an `Object`
|
||||
with the following structure:
|
||||
|
||||
```js
|
||||
import myPlugin from './my-plugin.mjs'
|
||||
|
||||
const myConditionalPlugin = {
|
||||
myPlugin,
|
||||
condition,
|
||||
}
|
||||
```
|
||||
|
||||
Where `myPlugin` is the plugin itself, and `condition` is a method
|
||||
that returns `true` if the plugin should be loaded.
|
||||
|
||||
:::note RELATED
|
||||
|
||||
Refer to [the plugin guide](/guides/plugins) to learn
|
||||
about conditional plugins
|
||||
|
||||
:::
|
14
sites/dev/docs/reference/api/part/config/readme.mdx
Normal file
14
sites/dev/docs/reference/api/part/config/readme.mdx
Normal file
|
@ -0,0 +1,14 @@
|
|||
---
|
||||
title: "Parts: Configuration"
|
||||
---
|
||||
|
||||
Apart from [the `draft()` method](/reference/api/part/draft) a part
|
||||
can provide the following configuration properties:
|
||||
|
||||
- [`name`](/reference/api/part/config/name) __is mandatory__ and holds the part's name
|
||||
- [`from` and `after`](/reference/api/part/config/dependencies) list the part's dependencies
|
||||
- [`hide`, `hideDependencies`, or `hideAll`](/reference/api/part/config/hide) hide the part, its dependencies, or both
|
||||
- [`measurements` and `optionalMeasurements`](/reference/api/part/config/measurements) lists the part's required or optional measurements
|
||||
- [`options`](/reference/api/part/config/options) lists the part's options
|
||||
- [`plugins`](/reference/api/part/config/plugins) lists the part's required plugins
|
||||
- [`stack`](/reference/api/part/config/stack) assigns the part to a stack
|
51
sites/dev/docs/reference/api/part/config/stack/readme.mdx
Normal file
51
sites/dev/docs/reference/api/part/config/stack/readme.mdx
Normal file
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
title: Assigning parts to stacks
|
||||
---
|
||||
|
||||
The optional `stack` property assigns the part to a specific
|
||||
[Stack](/reference/api/stack).
|
||||
|
||||
It holds either a string with the stack name or a function which
|
||||
returns the stack name:
|
||||
|
||||
```js
|
||||
const part = {
|
||||
name: 'example.front',
|
||||
stack: 'example.combined',
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
const part = {
|
||||
name: 'example.back',
|
||||
stack: ({options}) => options.stack ? 'example.combined' : 'example.back',
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
If `stack` is present, the part is assigned to the stack with the
|
||||
specified name.
|
||||
If multiple parts are assigned to the same stack, they will overlap
|
||||
in drafting and printing layouts.
|
||||
This is because parts in the stack are drafted within the same stack
|
||||
space.
|
||||
|
||||
Otherwise, if the `stack` property is not present, the default behavior
|
||||
is to use the part's name as its stack name.
|
||||
|
||||
- In a draft with only one set, this will result in each part having its
|
||||
own stack.
|
||||
With a default layout, the part will not overlap other parts because it is
|
||||
the only part drafted within its stack and stacks do not overlap.
|
||||
|
||||
- In a draft with multiple sets, this will result in parts of the same name
|
||||
using the same stack.
|
||||
This is how we achieve the layered look of parts in sample drafts.
|
||||
|
||||
:::note RELATED
|
||||
|
||||
Please see [Stacks](/guides/designs/stacks) in the Design Guide for
|
||||
more information about how stacks can be used.
|
||||
|
||||
:::
|
52
sites/dev/docs/reference/api/part/draft/readme.mdx
Normal file
52
sites/dev/docs/reference/api/part/draft/readme.mdx
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
title: "The part's draft method"
|
||||
---
|
||||
|
||||
Each part **must** have a `draft` property that holds a method that will draft the part.
|
||||
In other words, this method is where the actual work happens. The method's signature
|
||||
is as follows:
|
||||
|
||||
```js
|
||||
function draft(props)
|
||||
```
|
||||
|
||||
The draft method receives a single parameter, an object which you can _destructure_ to
|
||||
access the following properties:
|
||||
|
||||
| Property | Description |
|
||||
| --------:|:----------- |
|
||||
|| **_Content constructors_** |
|
||||
| `Path` | A [Path constructor](/reference/api/path) to create new paths |
|
||||
| `Point` | A [Point constructor](/reference/api/point) to create new points |
|
||||
| `Snippet` | A [Snippet constructor](/reference/api/snippet) to create new snippets |
|
||||
|| **_Content containers_** |
|
||||
| `paths` | Add a Path to your part by adding it to this object |
|
||||
| `points` | Add a Points to your part by adding it to this object |
|
||||
| `snippets` | Add a Snippet to your part by adding it to this object |
|
||||
|| **_Access to settings_** |
|
||||
| `absoluteOptions` | Access to `settings.absoluteOptions` |
|
||||
| `complete` | Access to `settings.complete` |
|
||||
| `measurements` | Access to `settings.measurements` |
|
||||
| `options` | Access to `settings.options` |
|
||||
| `paperless` | Access to `settings.paperless` |
|
||||
| `sa` | Access to `settings.sa` |
|
||||
| `scale` | Access to `settings.scale` |
|
||||
|| **_Access to utilities_** |
|
||||
| `context` | Allows access to the pattern object and other things higher in the tree |
|
||||
| `getId` | See [the getId documentation](/reference/api/part/getid) |
|
||||
| `log` | See [the Store Methods documentation](/reference/store-methods#store-methods-we-maintain) |
|
||||
| `macro` | See [the macros documentation](/reference/macros/) |
|
||||
| `store` | See [the store documentation](/reference/api/store) |
|
||||
| `units` | A version of [`utils.units()`](/reference/api/utils/units) that is preconfigured with the user's chosen units |
|
||||
| `utils` | See [the utils documentation](/reference/api/utils) |
|
||||
| `Bezier` | The [bezier-js](https://pomax.github.io/bezierjs/) library's `Bezier` named export |
|
||||
|| **_Return value_** |
|
||||
| `part` | Your draft method **must** return this |
|
||||
|
||||
:::tip
|
||||
|
||||
Please note that there is no `optionalMeasurements` property.
|
||||
Instead, optional measurements are accessed via the 'measurements'
|
||||
property.
|
||||
|
||||
:::
|
37
sites/dev/docs/reference/api/part/getid/readme.mdx
Normal file
37
sites/dev/docs/reference/api/part/getid/readme.mdx
Normal file
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: Part.getId()
|
||||
---
|
||||
|
||||
The `Part.getId()` method will return an integer the can be used as an
|
||||
for ID Points/Paths/Snippets. This method will ensure the ID is unique by
|
||||
keeping an internal incremental counter of the IDs that have been used.
|
||||
It is typically used when programatically adding points, paths, or snippets.
|
||||
|
||||
:::tip
|
||||
This method can be destructured as `getID`
|
||||
in [a part's draft method](/reference/api/part/draft).
|
||||
:::
|
||||
|
||||
|
||||
## Part.getId() signature
|
||||
|
||||
```js
|
||||
int|string getId(prefix='')
|
||||
```
|
||||
|
||||
This method takes an optional parameter that will be used as a prefix for the ID.
|
||||
|
||||
## Part.getId() example
|
||||
|
||||
```js
|
||||
cont part = {
|
||||
name: 'examples.getid',
|
||||
draft: ({ Point, points, getId, part }) => {
|
||||
for (let i=0;i<10;i++) {
|
||||
points[getId()] = new Point(i*10, i*10)
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
||||
}
|
||||
```
|
28
sites/dev/docs/reference/api/part/hide/readme.mdx
Normal file
28
sites/dev/docs/reference/api/part/hide/readme.mdx
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
title: Part.hide()
|
||||
---
|
||||
|
||||
The `Part.hide()` method will mark the part as hidden.
|
||||
This method returns the `part` object, so it's chainable.
|
||||
|
||||
:::tip
|
||||
This method can be destructured as `hidden`
|
||||
in [a part's draft method](/reference/api/part/draft).
|
||||
:::
|
||||
|
||||
:::note RELATED
|
||||
|
||||
The [unhide](/reference/api/part/unhide) and
|
||||
[setHidden](/reference/api/part/sethidden) methods also control a
|
||||
part's visibility
|
||||
|
||||
:::
|
||||
|
||||
## Part.hide() example
|
||||
|
||||
```js
|
||||
cont part = {
|
||||
name: 'examples.hide',
|
||||
draft: ({ hide, part }) => part.hide()
|
||||
}
|
||||
```
|
73
sites/dev/docs/reference/api/part/readme.mdx
Normal file
73
sites/dev/docs/reference/api/part/readme.mdx
Normal file
|
@ -0,0 +1,73 @@
|
|||
---
|
||||
title: Part
|
||||
---
|
||||
|
||||
A `Part` in FreeSewing holds all data, logic, and configuration of a Design.
|
||||
Parts truly are the building blocks of FreeSewing as they not only provide
|
||||
the configuration, but also a `draft()` method that does the actual work
|
||||
of drafting a parametric design.
|
||||
|
||||
## Properties
|
||||
|
||||
A Part object comes with the following properties:
|
||||
|
||||
- `attributes` : An [Attributes](/reference/api/attributes) instance holding
|
||||
the part's attributes
|
||||
- `hidden` : When this is `true` the part will be hidden (excluding it from the
|
||||
output). See [Part.hide()](/reference/api/part/hide),
|
||||
[Part.unhide()](/reference/api/part/unhide), and
|
||||
[Part.setHidden()](/reference/api/part/sethidden) for various methods that
|
||||
allow setting this in a chainable way.
|
||||
- `name` : The name of the part
|
||||
- `paths` : Holds the paths used in the part
|
||||
- `points` : Holds the points used in the part
|
||||
- `snippets` : Holds the snippets used in the part
|
||||
|
||||
:::note RELATED
|
||||
See [Using Attributes](/howtos/code/attributes)
|
||||
for information about custom Attributes that can be used with Parts.
|
||||
:::
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
const part = {
|
||||
name: 'example.part',
|
||||
from: otherPart,
|
||||
after: [ yetAnotherPart, oneMorePart ],
|
||||
measurements: ['head', 'chest' ],
|
||||
optionalMeasurements: ['neck'],
|
||||
options: {
|
||||
headEase: { pct: 12, min: 5, max: 20 }
|
||||
}
|
||||
hide: false,
|
||||
hideAll: false,
|
||||
hideDependencies: true,
|
||||
plugins: [
|
||||
plugin1,
|
||||
plugin1,
|
||||
[ plugin3, dataForPlugin3 ],
|
||||
],
|
||||
draft: ({ part }) => part
|
||||
}
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
A Part object exposes the following methods:
|
||||
|
||||
- [Part.asRenderProps()](/reference/api/part/asrenderprops)
|
||||
- [Part.attr()](/reference/api/part/attr)
|
||||
- [Part.getId()](/reference/api/part/getid)
|
||||
- [Part.hide()](/reference/api/part/hide)
|
||||
- [Part.setHidden()](/reference/api/part/sethidden)
|
||||
- [Part.shorthand()](/reference/api/part/shorthand)
|
||||
- [Part.unhide()](/reference/api/part/unhide)
|
||||
- [Part.units()](/reference/api/part/units)
|
||||
|
||||
## More information
|
||||
|
||||
Click below to learn more about:
|
||||
|
||||
- [A part's configuration](/reference/api/part/config)
|
||||
- [A part's `draft()` method](/reference/api/part/draft)
|
32
sites/dev/docs/reference/api/part/sethidden/readme.mdx
Normal file
32
sites/dev/docs/reference/api/part/sethidden/readme.mdx
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
title: Part.setHidden()
|
||||
---
|
||||
|
||||
The `Part.setHidden()` method will mark the part either hidden
|
||||
or not, depending on the value you pass it.
|
||||
This method returns the `part` object, so it's chainable
|
||||
|
||||
- Pass a *truthy* value: The part will be hidden
|
||||
- Pass a *falsy* value: The part will be unhidden/revealed
|
||||
|
||||
:::tip
|
||||
This method can be destructured as `setHidden`
|
||||
in [a part's draft method](/reference/api/part/draft).
|
||||
:::
|
||||
|
||||
:::note RELATED
|
||||
|
||||
The [hide](/reference/api/part/hide) and
|
||||
[unhide](/reference/api/part/unhide) also control a
|
||||
part's visibility
|
||||
|
||||
:::
|
||||
|
||||
## Part.setHidden() example
|
||||
|
||||
```js
|
||||
cont part = {
|
||||
name: 'examples.hide',
|
||||
draft: ({ setHidden, part }) => part.setHidden(true)
|
||||
}
|
||||
```
|
8
sites/dev/docs/reference/api/part/shorthand/readme.mdx
Normal file
8
sites/dev/docs/reference/api/part/shorthand/readme.mdx
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
title: Part.shorthand()
|
||||
---
|
||||
|
||||
The `Part.shorthand()` method is what is called under the hood to provide the
|
||||
object you can destructure in [a part's draft method](/reference/api/part/draft).
|
||||
|
||||
You probably do not want to call it directly.
|
28
sites/dev/docs/reference/api/part/unhide/readme.mdx
Normal file
28
sites/dev/docs/reference/api/part/unhide/readme.mdx
Normal file
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
title: Part.unhide()
|
||||
---
|
||||
|
||||
The `Part.unhide()` method will mark the part as not hidden.
|
||||
This method returns the `part` object, so it's chainable.
|
||||
|
||||
:::tip
|
||||
This method can be destructured as `inhide`
|
||||
in [a part's draft method](/reference/api/part/draft).
|
||||
:::
|
||||
|
||||
:::note RELATED
|
||||
|
||||
The [hide](/reference/api/part/hide) and
|
||||
[setHidden](/reference/api/part/sethidden) methods also control a
|
||||
part's visibility
|
||||
|
||||
:::
|
||||
|
||||
## Part.unhide() example
|
||||
|
||||
```js
|
||||
cont part = {
|
||||
name: 'examples.hide',
|
||||
draft: ({ unhide, part }) => part.unhide()
|
||||
}
|
||||
```
|
13
sites/dev/docs/reference/api/part/units/readme.mdx
Normal file
13
sites/dev/docs/reference/api/part/units/readme.mdx
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: Part.units()
|
||||
---
|
||||
|
||||
The `Part.units()` method returns a value formatted according to the
|
||||
units set in settings.
|
||||
|
||||
:::note
|
||||
This method is used internally.
|
||||
You will probably want to the use `units()` method you can destructure
|
||||
in [a part's draft method](/reference/api/part/draft) instead.
|
||||
:::
|
||||
|
48
sites/dev/docs/reference/api/path/_curve/readme.mdx
Normal file
48
sites/dev/docs/reference/api/path/_curve/readme.mdx
Normal file
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
title: "Path._curve()"
|
||||
---
|
||||
|
||||
The `Path._curve()` method draws a cubic Bézier curve
|
||||
from the current position via two control points to a given endpoint.
|
||||
However, the start control point is identical to the current position,
|
||||
so you do not need to provide it.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path._curve(Point cp2, Point to)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.\_curve() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(5, 20)
|
||||
points.cp2 = new Point(60, 50)
|
||||
points.to = new Point(90, 20)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
._curve(points.cp2, points.to)
|
||||
.setText("Path._curve()", "text-sm center fill-note")
|
||||
.attr("data-text-dy", -1)
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
The main purpose of this method is to save your some typing,
|
||||
as the two following calls yield the same result:
|
||||
|
||||
```js
|
||||
path.curve(point1, point1, point2)
|
||||
path._curve(point1, point2)
|
||||
```
|
42
sites/dev/docs/reference/api/path/addclass/readme.mdx
Normal file
42
sites/dev/docs/reference/api/path/addclass/readme.mdx
Normal file
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
title: Path.addClass()
|
||||
---
|
||||
|
||||
The `Path.addClass()` method adds a CSS class to the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.addClass(string className)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.addClass() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(5, 10)
|
||||
points.to = new Point(95, 10)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
.line(points.to)
|
||||
.addClass('note dashed')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The main purpose of this method is to save your some typing,
|
||||
as the two following calls yield the same result:
|
||||
|
||||
```js
|
||||
path.attr('class', 'fabric')
|
||||
path.addClass('fabric')
|
||||
```
|
47
sites/dev/docs/reference/api/path/addtext/readme.mdx
Normal file
47
sites/dev/docs/reference/api/path/addtext/readme.mdx
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
title: Path.addText()
|
||||
---
|
||||
|
||||
The `Path.addText()` method adds text to the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.addText(string text, string className = '')
|
||||
```
|
||||
|
||||
The second argument will optionally be used to set the CSS class for the text.
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.addText() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
points.from = new Point(5, 10)
|
||||
points.to = new Point(95, 10)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
.line(points.to)
|
||||
.addText('FreeSewing rocks')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The main purpose of this method is to save your some typing,
|
||||
as the two following calls yield the same result:
|
||||
|
||||
```js
|
||||
path.attr('data-text', 'Hello')
|
||||
path.addText('Hello')
|
||||
```
|
||||
|
||||
The difference with [Path.setText()](/reference/api/path/addtext) is that this
|
||||
method will add to the existing text whereas `Path.setText()` will overwrite
|
||||
existing text on the path,
|
54
sites/dev/docs/reference/api/path/angleat/readme.mdx
Normal file
54
sites/dev/docs/reference/api/path/angleat/readme.mdx
Normal file
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
title: Path.angleAt()
|
||||
---
|
||||
|
||||
The `Path.angleAt()` method returns the (tangent) angle of a path at a specific point.
|
||||
|
||||
If the given point is a sharp corner, this method prefers returning the angle directly before the corner.
|
||||
|
||||
If the given point does not lie (approximately) on the path, this method returns `false`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
number|false path.angleAt(Point point)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.angleAt() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
points.D = new Point(50, 80)
|
||||
points.DCp1 = new Point(70, 30)
|
||||
|
||||
paths.demo = new Path()
|
||||
.move(points.D)
|
||||
.curve(points.DCp1, points.DCp1, points.C)
|
||||
.curve(points.CCp1, points.BCp2, points.B)
|
||||
.line(points.A)
|
||||
|
||||
points.testPoint = paths.demo.shiftFractionAlong(0.55)
|
||||
snippets.point = new Snippet("notch", points.testPoint)
|
||||
|
||||
let angle = paths.demo.angleAt(points.testPoint)
|
||||
//draw a tangent path
|
||||
paths.tangent = new Path()
|
||||
.move(points.testPoint.shift(angle, -30))
|
||||
.line(points.testPoint.shift(angle, 30))
|
||||
.attr("class", "lining dashed")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
Keep in mind that calculations with Bézier curves are often approximations.
|
17
sites/dev/docs/reference/api/path/aspathstring/readme.mdx
Normal file
17
sites/dev/docs/reference/api/path/aspathstring/readme.mdx
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
title: Path.asPathString()
|
||||
---
|
||||
|
||||
This `Path.asPathString()` returns the path as a string that can be used
|
||||
as the `d` attribute for an SVG `path` element.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
string path.asPathString()
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
This method is mostly aimed at people looking to implement their own rendering
|
||||
methods, or integrate with SVG processing tools.
|
31
sites/dev/docs/reference/api/path/asrenderprops/readme.mdx
Normal file
31
sites/dev/docs/reference/api/path/asrenderprops/readme.mdx
Normal file
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
title: Path.asRenderProps()
|
||||
---
|
||||
|
||||
The `Path.asRenderProps()` method will return the data stored in the
|
||||
path as a serializable JavaScript object. This method is typically
|
||||
not invoked directly but rather called under the hood as a result of
|
||||
calling [`Pattern.getRenderProps()`](/reference/api/pattern/getrenderprops).
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Object path.asRenderProps()
|
||||
```
|
||||
|
||||
## Returned object properties
|
||||
|
||||
This returns JavaScript object has the following properties:
|
||||
|
||||
| Name | Description |
|
||||
| ----:| ----------- |
|
||||
| `attributes` | The result of [Path.attributes.asRenderProps()](/reference/api/attributes/asrenderprops) |
|
||||
| `hidden` | A boolean indicating whether the path is hidden or not |
|
||||
| `name` | The path name |
|
||||
| `ops` | An array of drawing operations |
|
||||
| `height` | A number indicating the path height in `mm` |
|
||||
| `width` | A number indicating the path width in `mm` |
|
||||
| `topLeft` | The [Point](/reference/api/point) at the top left of the part, or rather its [`Point.asRenderProps()`](/reference/api/point/asrenderprops) result |
|
||||
| `bottomRight` | The [Point](/reference/api/point) at the bottom right of the part, or rather its [`Point.asRenderProps()`](/reference/api/point/asrenderprops) result |
|
||||
| `d` | The path's pathstring for rendering as SVG |
|
||||
|
56
sites/dev/docs/reference/api/path/attr/readme.mdx
Normal file
56
sites/dev/docs/reference/api/path/attr/readme.mdx
Normal file
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
title: Path.attr()
|
||||
---
|
||||
|
||||
This `Path.attr()` method can be used to add attributes to the Path object.
|
||||
It calls `this.attributes.add()` under the hood, and returns the Path object.
|
||||
|
||||
If the optional third parameter is set to `true` it will call `this.attributes.set()`
|
||||
instead, thereby overwriting the value of the attribute.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.attr(
|
||||
string name,
|
||||
mixed value,
|
||||
bool overwrite = false
|
||||
)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption=" Example of the Path.attr() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(10, 20)
|
||||
points.cp1 = new Point(20, -10)
|
||||
points.cp2 = new Point(50, 50)
|
||||
points.to = new Point(70, 20)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.from)
|
||||
.curve(points.cp1, points.cp2, points.to)
|
||||
.attr("class", "canvas")
|
||||
.setText("FreeSewing rocks", "text-xs center")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
Methods like
|
||||
[`Path.addClass`](/reference/api/path/addclass),
|
||||
[`Path.setClass`](/reference/api/path/setclass),
|
||||
[`Path.addText`](/reference/api/path/addtext), and
|
||||
[`Path.setText`](/reference/api/path/settext)
|
||||
all call this method under the hood.
|
||||
|
||||
See [Using Attributes](/howtos/code/attributes)
|
||||
for information about custom Attributes that can be used with Paths.
|
25
sites/dev/docs/reference/api/path/bbox/readme.mdx
Normal file
25
sites/dev/docs/reference/api/path/bbox/readme.mdx
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
title: Path.bbox()
|
||||
---
|
||||
|
||||
The `Path.bbox()` method returns an object describing the bounding box of a path.
|
||||
In other words, it gives you a rectangle the Path fits in.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
object path.bbox()
|
||||
```
|
||||
|
||||
It returns an object with a signature like this:
|
||||
|
||||
```js
|
||||
{
|
||||
topLeft: Point,
|
||||
bottomRight: Point
|
||||
}
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
This method is mostly aimed at people looking to implement their own layout solution.
|
52
sites/dev/docs/reference/api/path/circlesegment/readme.mdx
Normal file
52
sites/dev/docs/reference/api/path/circlesegment/readme.mdx
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
title: Path.circleSegment()
|
||||
---
|
||||
|
||||
The `Path.circleSegment()` method draws a circle segment
|
||||
starting from the current endpoint of the path around the given origin with a given angle.
|
||||
|
||||
A positive angle results in a counter-clockwise arc.
|
||||
|
||||
A negative angle results in a clockwise arc.
|
||||
|
||||
:::tip
|
||||
The new endpoint of this path is the same point
|
||||
that
|
||||
```js
|
||||
path.end().rotate(deg, origin)
|
||||
```
|
||||
would return.
|
||||
:::
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.circleSegment(deg, origin)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.circleSegment() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(10, 20)
|
||||
points.origin = new Point(40, 0)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
.circleSegment(90, points.origin)
|
||||
.setText("→ Path.circleSegment() →", "text-sm center fill-note")
|
||||
|
||||
paths.helper = new Path()
|
||||
.move(paths.line.start())
|
||||
.line(points.origin)
|
||||
.line(paths.line.end())
|
||||
.setClass('dotted stroke-sm')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
60
sites/dev/docs/reference/api/path/clean/readme.mdx
Normal file
60
sites/dev/docs/reference/api/path/clean/readme.mdx
Normal file
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
title: Path.clean()
|
||||
---
|
||||
|
||||
The `Path.clean()` method removes spurious drawing operations from a path.
|
||||
|
||||
A _spurious_ drawing operation is one that has no effect, but can still cause
|
||||
problems if left in place. For example, a line from a given point to the same
|
||||
given point will not cause any problems as such, but can trip up things like
|
||||
path offset and other methods. For this reason, such drawing operations can be
|
||||
cleaned up with the `Path.clean()` method.
|
||||
|
||||
As this method is called under the hood to guard against various scenarios
|
||||
where spurious segments could cause an issue, you should have no need to call
|
||||
this method yourself explicitly, but it's there if you need it. path that you
|
||||
pass it.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.clean()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.clean() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, part }) => {
|
||||
|
||||
points.A = new Point(10, 10)
|
||||
points.B = new Point(10, 20)
|
||||
points.C = new Point(10, 30)
|
||||
points.D = new Point(90, 10)
|
||||
points.E = new Point(90, 20)
|
||||
points.F = new Point(90, 30)
|
||||
|
||||
paths.a = new Path()
|
||||
.move(points.A)
|
||||
.line(points.C)
|
||||
.line(points.B)
|
||||
.line(points.B) // spurious op
|
||||
.line(points.E)
|
||||
.line(points.F)
|
||||
.curve_(points.F, points.F) // another spurious op
|
||||
.line(points.D)
|
||||
.addClass('lining')
|
||||
|
||||
paths.b = paths.a
|
||||
.clone()
|
||||
.clean()
|
||||
.addClass('interfacing')
|
||||
|
||||
paths.a.addText(`${paths.a.ops.length} ops in a`, 'center fill-lining')
|
||||
paths.b.addText(`${paths.b.ops.length} ops in b`, 'center fill-note')
|
||||
.attr('data-text-dy', 7)
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
38
sites/dev/docs/reference/api/path/clone/readme.mdx
Normal file
38
sites/dev/docs/reference/api/path/clone/readme.mdx
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
title: Path.clone()
|
||||
---
|
||||
|
||||
The `Path.clone()` method returns a new `Path` object that is a deep copy of this path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.clone()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.clone() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
|
||||
paths.clone = paths.example
|
||||
.clone()
|
||||
.setClass("note lashed stroke-xl")
|
||||
.attr("style", "stroke-opacity: 0.5")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
35
sites/dev/docs/reference/api/path/close/readme.mdx
Normal file
35
sites/dev/docs/reference/api/path/close/readme.mdx
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
title: Path.close()
|
||||
---
|
||||
|
||||
The `Path.close()` method closes a path by drawing a straight line from the current position to the path's start.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.close()
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.close() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(10, 20)
|
||||
points.cp2 = new Point(60, 30)
|
||||
points.to = new Point(90, 20)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
._curve(points.cp2, points.to)
|
||||
.close()
|
||||
.reverse() // To keep text from being upside-down
|
||||
.setText('Path._close()', 'text-sm right fill-note')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
58
sites/dev/docs/reference/api/path/combine/readme.mdx
Normal file
58
sites/dev/docs/reference/api/path/combine/readme.mdx
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
title: Path.combine()
|
||||
---
|
||||
|
||||
The `Path.combine()` method combines this path with one or more other paths
|
||||
into a single Path instance.
|
||||
|
||||
Any gaps in the path (caused by move operations) will be left as-is, rather
|
||||
than joined with a line. If that's not what you want, you should use
|
||||
[`Path.join()`](/reference/api/path/join) instead.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.combine(path other)
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
<Example caption="Example of the Path.combine() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.A1 = new Point(0, 0)
|
||||
points.A2 = new Point(60, 0)
|
||||
points.B1 = new Point(0, 10)
|
||||
points.B2 = new Point(60, 10)
|
||||
points.C1 = new Point(0, 20)
|
||||
points.C2 = new Point(60, 20)
|
||||
|
||||
paths.path1 = new Path()
|
||||
.move(points.A1)
|
||||
.line(points.A2)
|
||||
.setClass("various")
|
||||
|
||||
paths.path2 = new Path()
|
||||
.move(points.B1)
|
||||
.line(points.B2)
|
||||
.setClass("note")
|
||||
|
||||
paths.path3 = new Path()
|
||||
.move(points.C1)
|
||||
.line(points.C2)
|
||||
.setClass("canvas")
|
||||
|
||||
paths.combo = paths.path1
|
||||
.combine(paths.path2, paths.path3)
|
||||
.setClass("lining dotted")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
`Path.combine()` method is _variadic_, so you can pass multiple paths to join
|
35
sites/dev/docs/reference/api/path/curve/readme.mdx
Normal file
35
sites/dev/docs/reference/api/path/curve/readme.mdx
Normal file
|
@ -0,0 +1,35 @@
|
|||
---
|
||||
title: Path.curve()
|
||||
---
|
||||
|
||||
The `Path.curve()` method draws a cubic Bézier curve from the current position
|
||||
via two control points to a given endpoint.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.curve(Point cp1, Point cp2, Point to)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.curve() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(10, 20)
|
||||
points.cp1 = new Point(40, 0)
|
||||
points.cp2 = new Point(60, 40)
|
||||
points.to = new Point(90, 20)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
.curve(points.cp1, points.cp2, points.to)
|
||||
.setText("Path.curve()", "text-sm center fill-note")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
48
sites/dev/docs/reference/api/path/curve_/readme.mdx
Normal file
48
sites/dev/docs/reference/api/path/curve_/readme.mdx
Normal file
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
title: Path.curve_()
|
||||
---
|
||||
|
||||
The `Path.curve_()` method draws a cubic Bézier curve from the current position
|
||||
via two control points to a given endpoint. However, the end control point is
|
||||
identical to the end point.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.curve_(Point cp1, Point to)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
<Example caption="Example of the Path.curve\_() method">
|
||||
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(10, 20)
|
||||
points.cp1 = new Point(40, 0)
|
||||
points.to = new Point(90, 20)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
.curve_(points.cp1, points.to)
|
||||
.setText("Path.curve_()", "text-sm center fill-note")
|
||||
.attr("data-text-dy", -1)
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The main purpose of this method is to save your some typing,
|
||||
as the two following calls yield the same result:
|
||||
|
||||
```js
|
||||
.curve(point1, point2, point2)
|
||||
.curve_(point1, point2)
|
||||
```
|
48
sites/dev/docs/reference/api/path/divide/readme.mdx
Normal file
48
sites/dev/docs/reference/api/path/divide/readme.mdx
Normal file
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
title: Path.divide()
|
||||
---
|
||||
|
||||
The `Path.divide()` method breaks a path apart in an array of atomic paths. An
|
||||
atomic path is a path that can't be divided further and is always made up of
|
||||
one move + one drawing operation.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array path.divide()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.divide() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.A = new Point(55, 40)
|
||||
points.B = new Point(10, 70)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 60)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
points.D = new Point(50, 80)
|
||||
points.DCp1 = new Point(140, 50)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.curve(points.DCp1, points.DCp1, points.D)
|
||||
.close()
|
||||
|
||||
let style = "stroke-width: 4; stroke-opacity: 0.5;"
|
||||
let i = 0
|
||||
for (let p of paths.example.divide()) {
|
||||
i++
|
||||
paths[i] = p
|
||||
.attr("style", style)
|
||||
.attr('style', `stroke: hsl(${i * 70}, 100%, 50%)`)
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
53
sites/dev/docs/reference/api/path/edge/readme.mdx
Normal file
53
sites/dev/docs/reference/api/path/edge/readme.mdx
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: Path.edge()
|
||||
---
|
||||
|
||||
```js
|
||||
Point path.edge(string side)
|
||||
```
|
||||
|
||||
Returns the Point object at the edge of the path you specify. Edge must be one of:
|
||||
|
||||
- `top`
|
||||
- `bottom`
|
||||
- `left`
|
||||
- `right`
|
||||
- `topLeft`
|
||||
- `topRight`
|
||||
- `bottomLeft`
|
||||
- `bottomRight`
|
||||
|
||||
<Example caption="Example of the Path.edge() method">
|
||||
```js
|
||||
({ Point, points, Path, paths,snippets, Snippet, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
points.D = new Point(-60, 90)
|
||||
points.E = new Point(90, 190)
|
||||
|
||||
paths.demo = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.curve(points.E, points.D, points.A)
|
||||
.close()
|
||||
|
||||
for (let i of [
|
||||
"topLeft",
|
||||
"topRight",
|
||||
"bottomLeft",
|
||||
"bottomRight",
|
||||
"top",
|
||||
"left",
|
||||
"bottom",
|
||||
"right"
|
||||
]) snippets[i] = new Snippet("notch", paths.demo.edge(i))
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
37
sites/dev/docs/reference/api/path/end/readme.mdx
Normal file
37
sites/dev/docs/reference/api/path/end/readme.mdx
Normal file
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: Path.end()
|
||||
---
|
||||
|
||||
The `Path.end()` method returns the Point object at the end of the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Point path.end()
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.end() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.demo = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
|
||||
snippets.end = new Snippet("notch", paths.demo.end())
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
32
sites/dev/docs/reference/api/path/hide/readme.mdx
Normal file
32
sites/dev/docs/reference/api/path/hide/readme.mdx
Normal file
|
@ -0,0 +1,32 @@
|
|||
---
|
||||
title: Path.hide()
|
||||
---
|
||||
|
||||
The `Path.hide()` hides the path so it does not appear in the output.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.hide()
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.hide() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.top = new Point(50, 0)
|
||||
points.left = new Point (20,50)
|
||||
points.right = new Point (80,50)
|
||||
|
||||
paths.a = new Path().move(points.top).line(points.right).setText('a')
|
||||
paths.b = new Path().move(points.right).line(points.left).setText('b').hide()
|
||||
paths.c = new Path().move(points.left).line(points.top).setText('c')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
50
sites/dev/docs/reference/api/path/insop/readme.mdx
Normal file
50
sites/dev/docs/reference/api/path/insop/readme.mdx
Normal file
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Path.insop()
|
||||
---
|
||||
|
||||
The `Path.insop()` method injects a Path into the [`noop`
|
||||
operation](/reference/api/path/noop) with id `id`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.insop(string id, Path path)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
|
||||
<Example caption="Example of the Path.insop() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.left = new Point(10,10)
|
||||
points.dartLeft = new Point(40, 10)
|
||||
points.dartTip = new Point(50, 50)
|
||||
points.dartRight = new Point(60, 10)
|
||||
points.right = new Point(90, 10)
|
||||
|
||||
paths.withoutDart = new Path()
|
||||
.move(points.left)
|
||||
.line(points.dartLeft)
|
||||
.noop('dart')
|
||||
.line(points.right)
|
||||
|
||||
paths.withDart = paths.withoutDart
|
||||
.clone()
|
||||
.insop(
|
||||
'dart',
|
||||
new Path()
|
||||
.line(points.dartTip)
|
||||
.line(points.dartRight)
|
||||
)
|
||||
.attr('style', 'stroke-width: 2px; stroke-opacity: 0.5; stroke: orange;')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
This is often used to insert darts into a path.
|
70
sites/dev/docs/reference/api/path/intersects/readme.mdx
Normal file
70
sites/dev/docs/reference/api/path/intersects/readme.mdx
Normal file
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
title: Path.intersects()
|
||||
---
|
||||
|
||||
The `Path.intersects()` method returns the Point object(s) where the path
|
||||
intersects with a path you pass it.
|
||||
|
||||
:::warning
|
||||
|
||||
This method can sometimes fail to find intersections in some curves
|
||||
due to a limitation in an underlying Bézier library.
|
||||
Please see [Bug #3367](https://github.com/freesewing/freesewing/issues/3367)
|
||||
for more information.
|
||||
|
||||
:::
|
||||
|
||||
## Signature
|
||||
|
||||
```
|
||||
array|false path.intersects(Path path)
|
||||
```
|
||||
|
||||
|
||||
<Example caption="Example of the Path.intersects() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, getId, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
points.D = new Point(50, 130)
|
||||
points.DCp1 = new Point(150, 30)
|
||||
|
||||
points._A = new Point(55, 40)
|
||||
points._B = new Point(0, 55)
|
||||
points._BCp2 = new Point(40, -20)
|
||||
points._C = new Point(90, 40)
|
||||
points._CCp1 = new Point(50, -30)
|
||||
points._D = new Point(40, 120)
|
||||
points._DCp1 = new Point(180, 40)
|
||||
|
||||
paths.demo1 = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.curve(points.DCp1, points.DCp1, points.D)
|
||||
paths.demo2 = new Path()
|
||||
.move(points._A)
|
||||
.line(points._B)
|
||||
.curve(points._BCp2, points._CCp1, points._C)
|
||||
.curve(points._DCp1, points._DCp1, points._D)
|
||||
|
||||
for (let p of paths.demo1.intersects(paths.demo2)) {
|
||||
snippets[getId()] = new Snippet('notch', p)
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
This is an expensive (read: slow) method that you should only use when you don't know
|
||||
in advance in what segment of your path the intersection will occur.
|
||||
|
||||
If you do know, use one of the intersection methods in [Utils](/reference/api/utils).
|
58
sites/dev/docs/reference/api/path/intersectsx/readme.mdx
Normal file
58
sites/dev/docs/reference/api/path/intersectsx/readme.mdx
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
title: Path.intersectsX()
|
||||
---
|
||||
|
||||
The `Path.intersectsX()` method returns the Point object(s) where the path
|
||||
intersects with a given X-value.
|
||||
|
||||
:::warning
|
||||
|
||||
This method can sometimes fail to find intersections in some curves
|
||||
due to a limitation in an underlying Bézier library.
|
||||
Please see [Bug #3367](https://github.com/freesewing/freesewing/issues/3367)
|
||||
for more information.
|
||||
|
||||
:::
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array|false path.intersectsX(float x)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.intersectsX() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, getId, part }) => {
|
||||
|
||||
points.A = new Point(95, 50)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
points.D = new Point(50, 130)
|
||||
points.DCp1 = new Point(150, 30)
|
||||
|
||||
points.top = new Point(60, -10)
|
||||
points.bot = new Point(60, 140)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.top)
|
||||
.line(points.bot)
|
||||
.attr("class", "lining dashed")
|
||||
|
||||
paths.demo = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.curve(points.DCp1, points.DCp1, points.D)
|
||||
|
||||
for (let p of paths.demo.intersectsX(60)) {
|
||||
snippets[getId()] = new Snippet("notch", p)
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
58
sites/dev/docs/reference/api/path/intersectsy/readme.mdx
Normal file
58
sites/dev/docs/reference/api/path/intersectsy/readme.mdx
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
title: Path.intersectsY()
|
||||
---
|
||||
|
||||
The `Path.intersectsY()` method returns the Point object(s) where the path
|
||||
intersects with a given Y-value.
|
||||
|
||||
:::warning
|
||||
|
||||
This method can sometimes fail to find intersections in some curves
|
||||
due to a limitation in an underlying Bézier library.
|
||||
Please see [Bug #3367](https://github.com/freesewing/freesewing/issues/3367)
|
||||
for more information.
|
||||
|
||||
:::
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array|false path.intersectsY(float y)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.intersectsY() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, getId, part }) => {
|
||||
|
||||
points.A = new Point(55, 40)
|
||||
points.B = new Point(10, 70)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 60)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
points.D = new Point(50, 80)
|
||||
points.DCp1 = new Point(140, 50)
|
||||
|
||||
points.top = new Point(10, 58)
|
||||
points.bot = new Point(130, 58)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.top)
|
||||
.line(points.bot)
|
||||
.attr("class", "lining dashed")
|
||||
|
||||
paths.demo = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.curve(points.DCp1, points.DCp1, points.D)
|
||||
|
||||
for (let p of paths.demo.intersectsY(58)) {
|
||||
snippets[getId()] = new Snippet("notch", p)
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
59
sites/dev/docs/reference/api/path/join/readme.mdx
Normal file
59
sites/dev/docs/reference/api/path/join/readme.mdx
Normal file
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
title: Path.join()
|
||||
---
|
||||
|
||||
The `Path.join()` method joins this path with one or more other paths.
|
||||
|
||||
Any gaps in the path (caused by move operations) will be filled-in with a line.
|
||||
If that's not what you want, you should use
|
||||
[`Path.combine()`](/reference/api/path/combine) instead.
|
||||
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.join(path other)
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
<Example caption="Example of the Path.join() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.A1 = new Point(0, 0)
|
||||
points.A2 = new Point(60, 0)
|
||||
points.B1 = new Point(0, 10)
|
||||
points.B2 = new Point(60, 10)
|
||||
points.C1 = new Point(0, 20)
|
||||
points.C2 = new Point(60, 20)
|
||||
|
||||
paths.path1 = new Path()
|
||||
.move(points.A1)
|
||||
.line(points.A2)
|
||||
.setClass("various")
|
||||
|
||||
paths.path2 = new Path()
|
||||
.move(points.B1)
|
||||
.line(points.B2)
|
||||
.setClass("note")
|
||||
|
||||
paths.path3 = new Path()
|
||||
.move(points.C1)
|
||||
.line(points.C2)
|
||||
.setClass("canvas")
|
||||
|
||||
paths.joint = paths.path1
|
||||
.join(paths.path2, paths.path3)
|
||||
.setClass("lining dotted")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
- `Path.join()` is _variadic_, so you can pass multiple paths to join
|
||||
- You cannot join a closed path to another path
|
49
sites/dev/docs/reference/api/path/length/readme.mdx
Normal file
49
sites/dev/docs/reference/api/path/length/readme.mdx
Normal file
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
title: Path.length()
|
||||
---
|
||||
|
||||
The `Path.length()` method returns the length of the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
float path.length(bool withMoves = false)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.length() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, units, part }) => {
|
||||
|
||||
points.A1 = new Point(0, 0)
|
||||
points.A2 = new Point(160, 0)
|
||||
points.B1 = new Point(0, 10)
|
||||
points.B2 = new Point(160, 10)
|
||||
points.C1 = new Point(0, 20)
|
||||
points.C2 = new Point(160, 20)
|
||||
|
||||
paths.path1 = new Path()
|
||||
.move(points.A1)
|
||||
.line(points.A2)
|
||||
.move(points.B1)
|
||||
.line(points.B2)
|
||||
.move(points.C1)
|
||||
.line(points.C2)
|
||||
.setClass("various")
|
||||
|
||||
points.label1 = new Point(25, 8).addText('Total length = ' + units(paths.path1.length()))
|
||||
points.label2 = new Point(25, 18).addText('Total length with moves = ' + units(paths.path1.length(true)))
|
||||
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
By default, `Path.length()` will measure the combined length of all drawing operations in the Path, but skip
|
||||
over gaps in the path (caused by move operations).
|
||||
If you want the full length of the Path, including move operations, pass `true` to `Path.length()`.
|
||||
|
33
sites/dev/docs/reference/api/path/line/readme.mdx
Normal file
33
sites/dev/docs/reference/api/path/line/readme.mdx
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
title: Path.line()
|
||||
---
|
||||
|
||||
The `Path.line()` method draws a straight line from the current position to a
|
||||
given point.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.line(Point to)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.line() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(10, 10)
|
||||
points.to = new Point(90, 10)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
.line(points.to)
|
||||
.setText("Path.line()", "text-sm center fill-note")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
50
sites/dev/docs/reference/api/path/move/readme.mdx
Normal file
50
sites/dev/docs/reference/api/path/move/readme.mdx
Normal file
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Path.move()
|
||||
---
|
||||
|
||||
The `Path.move()` method moves to a given point without drawing a line.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.move(Point to)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
<Example caption="Example of the Path.move() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.to = new Point(50, 20)
|
||||
.setText("Path.move()", "text-xs fill-note center")
|
||||
|
||||
paths.noline = new Path().move(points.to)
|
||||
|
||||
// Prevents clipping
|
||||
paths.diag = new Path()
|
||||
.move(new Point(40,19))
|
||||
.move(new Point(70,21))
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
When drawing a path, **you must always start with a `move()` call**,
|
||||
followed by your `line()` and/or `curve()` calls
|
||||
and an optional `close()` call.
|
||||
|
||||
These calls are chainable, making your code easier to read:
|
||||
|
||||
```js
|
||||
paths.example = new Path()
|
||||
.move(points.a)
|
||||
.curve(points.b, points.c, points.d)
|
||||
.line(points.e)
|
||||
.close()
|
||||
```
|
48
sites/dev/docs/reference/api/path/noop/readme.mdx
Normal file
48
sites/dev/docs/reference/api/path/noop/readme.mdx
Normal file
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
title: Path.noop()
|
||||
---
|
||||
|
||||
The `Path.noop()` method adds a placeholder path operation.
|
||||
A `noop` operation does nothing, but is intended to be replaced later
|
||||
with [`Path.insop()`](/reference/api/path/insop).
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.noop(string id)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.noop() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.left = new Point(10,10)
|
||||
points.dartLeft = new Point(40, 10)
|
||||
points.dartTip = new Point(50, 50)
|
||||
points.dartRight = new Point(60, 10)
|
||||
points.right = new Point(90, 10)
|
||||
|
||||
paths.withoutDart = new Path()
|
||||
.move(points.left)
|
||||
.line(points.dartLeft)
|
||||
.noop('dart')
|
||||
.line(points.right)
|
||||
|
||||
paths.withDart = paths.withoutDart
|
||||
.clone()
|
||||
.insop(
|
||||
'dart',
|
||||
new Path()
|
||||
.line(points.dartTip)
|
||||
.line(points.dartRight)
|
||||
)
|
||||
.attr('style', 'stroke-width: 2px; stroke-opacity: 0.5; stroke: orange;')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
52
sites/dev/docs/reference/api/path/offset/readme.mdx
Normal file
52
sites/dev/docs/reference/api/path/offset/readme.mdx
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
title: Path.offset()
|
||||
---
|
||||
|
||||
The `Path.offset()` method returns a new Path that is offset by distance from
|
||||
the original path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.offset(float distance)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.offset() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.line(points.A)
|
||||
.close()
|
||||
|
||||
paths.offset = paths.example
|
||||
.offset(-10)
|
||||
.attr("class", "interfacing")
|
||||
|
||||
paths.lineOffset = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.offset(-5)
|
||||
.attr("class", "various")
|
||||
|
||||
paths.curveOffset = new Path()
|
||||
.move(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.offset(-5)
|
||||
.attr("class", "canvas")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
50
sites/dev/docs/reference/api/path/readme.mdx
Normal file
50
sites/dev/docs/reference/api/path/readme.mdx
Normal file
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Path
|
||||
---
|
||||
|
||||
A path represents an SVG path, which are the lines and curves on our pattern.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path new Path()
|
||||
```
|
||||
|
||||
The Path constructor takes no arguments.
|
||||
|
||||
## Properties
|
||||
|
||||
A Path object comes with the following properties:
|
||||
|
||||
- `attributes` : An [Attributes](/reference/api/attributes) instance holding
|
||||
the path's attributes
|
||||
- `hidden` : When this is `true` the path will be hidden (excluding it from the
|
||||
output). See [Path.hide()](/reference/api/path/hide),
|
||||
[Path.unhide()](/reference/api/path/unhide), and
|
||||
[Path.setHidden()](/reference/api/path/sethidden) for various methods that
|
||||
allow setting this in a chainable way.
|
||||
|
||||
:::note RELATED
|
||||
See [Using Attributes](/howtos/code/attributes)
|
||||
for information about custom Attributes that can be used with Paths.
|
||||
:::
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path contructor">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
paths.example = new Path()
|
||||
.move(new Point(0,0))
|
||||
.line(new Point(100,0))
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Methods
|
||||
|
||||
A Path object exposes the following methods:
|
||||
|
||||
<ReadMore />
|
47
sites/dev/docs/reference/api/path/reverse/readme.mdx
Normal file
47
sites/dev/docs/reference/api/path/reverse/readme.mdx
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
title: Path.reverse()
|
||||
---
|
||||
|
||||
The `Path.reverse()` returns a path that is the reversed version of this path.
|
||||
As in, start becomes end, and end becomes start.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.reverse(bool cloneAttributes=false)
|
||||
```
|
||||
|
||||
If you pass a truthy value to this method, it will return a deep clone of the
|
||||
path, including its attributes. By default, it will return a shallow
|
||||
copy, without the attributes.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
<Example caption="Example of the Path.reverse() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.setText("FreeSewing rocks", "text-xs fill-note center")
|
||||
|
||||
paths.reverse = paths.example.reverse(true)
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The reversed path is a shallow copy.
|
||||
It will in other words not inherit the attributes of the original path.
|
||||
|
||||
If you want a deep copy, including the attributes, use `Path.reverse(true)`.
|
53
sites/dev/docs/reference/api/path/rotate/readme.mdx
Normal file
53
sites/dev/docs/reference/api/path/rotate/readme.mdx
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
title: Path.rotate()
|
||||
---
|
||||
|
||||
The `Path.rotate()` returns a path that is a rotated copy of this path.
|
||||
This method behaves like calling [Point.rotate](/reference/api/point/rotate) on all nodes of this path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.rotate(number deg, Point rotationOrigin, cloneAttributes = false)
|
||||
```
|
||||
|
||||
If you pass a truthy value to the cloneAttributes parameter, it will return a deep clone of the
|
||||
path, including its attributes. By default, it will return a shallow
|
||||
copy, without the attributes.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
<Example caption="Example of the Path.rotate() method">
|
||||
```js
|
||||
({ Point, points, Path, Snippet, paths, snippets, part }) => {
|
||||
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
points.origin = new Point(6, 34)
|
||||
snippets.origin = new Snippet('notch', points.origin)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.setText("FreeSewing rocks", "text-xs fill-note center")
|
||||
|
||||
paths.rotated = paths.example
|
||||
.rotate(180, points.origin, true)
|
||||
.attr("class", "dotted")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The rotated path is a shallow copy.
|
||||
It will in other words not inherit the attributes of the original path.
|
||||
|
||||
If you want a deep copy, including the attributes, set the third parameter to true:
|
||||
|
||||
`Path.rotate(deg, origin, true)`
|
50
sites/dev/docs/reference/api/path/roughlength/readme.mdx
Normal file
50
sites/dev/docs/reference/api/path/roughlength/readme.mdx
Normal file
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Path.roughLength()
|
||||
---
|
||||
|
||||
The `Path.roughLength()` method returns a (very) rough estimate of the path's length.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Number path.roughLength()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.attr() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, macro, units, part }) => {
|
||||
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(120, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
|
||||
macro("pd", {
|
||||
path: paths.example,
|
||||
d: -10,
|
||||
text: `Path.roughLength() = ${units(paths.example.roughLength())}`
|
||||
})
|
||||
macro("pd", {
|
||||
path: paths.example,
|
||||
d: 10,
|
||||
text: `Path.length() = ${units(paths.example.length())}`
|
||||
})
|
||||
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The `Path.roughLength()` is not intended to give an estimate that is accurate, but rather differentiates between paths that are a few millimeter long, or meters long.
|
||||
|
||||
It calculates the length without *walking the (cubic) Bézier curve* making it very fast and very inaccurate (for curves).
|
||||
It is typically used to determine how much precision to apply when walking a curve.
|
42
sites/dev/docs/reference/api/path/setclass/readme.mdx
Normal file
42
sites/dev/docs/reference/api/path/setclass/readme.mdx
Normal file
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
title: Path.setClass()
|
||||
---
|
||||
|
||||
The `Path.setClass()` method sets the CSS class(es) of the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.setClass(string className)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.setClass() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.from = new Point(5, 10)
|
||||
points.to = new Point(95, 10)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
.line(points.to)
|
||||
.setClass('note dashed')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The main purpose of this method is to save your some typing,
|
||||
as the two following calls yield the same result:
|
||||
|
||||
```js
|
||||
path.attr('class', 'fabric', true)
|
||||
path.setClass('fabric')
|
||||
```
|
33
sites/dev/docs/reference/api/path/sethidden/readme.mdx
Normal file
33
sites/dev/docs/reference/api/path/sethidden/readme.mdx
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
title: Path.setHidden()
|
||||
---
|
||||
|
||||
The `Path.setHidden()` method either hides or unhides the path depending on the
|
||||
value you pass it.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.setHidden(bool hidden = false)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.setHidden() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.top = new Point(50, 0)
|
||||
points.left = new Point (20,50)
|
||||
points.right = new Point (80,50)
|
||||
|
||||
paths.a = new Path().move(points.top).line(points.right).setText('a')
|
||||
paths.b = new Path().move(points.right).line(points.left).setText('b').setHidden(true)
|
||||
paths.c = new Path().move(points.left).line(points.top).setText('c')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
47
sites/dev/docs/reference/api/path/settext/readme.mdx
Normal file
47
sites/dev/docs/reference/api/path/settext/readme.mdx
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
title: Path.setText()
|
||||
---
|
||||
|
||||
The `Path.setText()` method sets text on the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.setText(string text, string className = '')
|
||||
```
|
||||
|
||||
The second argument will optionally be used to set the CSS class for the text.
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.setText() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
points.from = new Point(5, 10)
|
||||
points.to = new Point(95, 10)
|
||||
|
||||
paths.line = new Path()
|
||||
.move(points.from)
|
||||
.line(points.to)
|
||||
.setText('FreeSewing rocks')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
The main purpose of this method is to save your some typing,
|
||||
as the two following calls yield the same result:
|
||||
|
||||
```js
|
||||
path.attr('data-text', 'Hello')
|
||||
path.setText('Hello')
|
||||
```
|
||||
|
||||
The difference with [Path.addText()](/reference/api/path/addtext) is that this
|
||||
method will overwrite existing text on the path, whereas `Path.addText()` will
|
||||
add to the existing text.
|
55
sites/dev/docs/reference/api/path/shiftalong/readme.mdx
Normal file
55
sites/dev/docs/reference/api/path/shiftalong/readme.mdx
Normal file
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
title: Path.shiftAlong()
|
||||
---
|
||||
|
||||
The `Path.shiftAlong()` method returns a point that lies at distance travelled
|
||||
along the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Point path.shiftAlong(float distance, int stepsPerMm = 10)
|
||||
```
|
||||
|
||||
The second parameter controls the precision by which the path will be _walked_.
|
||||
By default, we'll divide it into 10 steps per mm.
|
||||
|
||||
If you don't need that precision, you can pass a lower number.
|
||||
If you need more precision, you can pass a higher number.
|
||||
For most cases, the default will be fine.
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.shiftAlong() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, Snippet, snippets, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
|
||||
points.x1 = paths.example
|
||||
.shiftAlong(20)
|
||||
.attr("data-text", "2 cm")
|
||||
.attr("data-text-class", "center fill-note")
|
||||
.attr("data-text-lineheight", 6)
|
||||
points.x2 = paths.example
|
||||
.shiftAlong(90)
|
||||
.attr("data-text", "9 cm")
|
||||
.attr("data-text-class", "center fill-note")
|
||||
.attr("data-text-lineheight", 6)
|
||||
|
||||
snippets.x1 = new Snippet("notch", points.x1)
|
||||
snippets.x2 = new Snippet("notch", points.x2)
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
|
@ -0,0 +1,51 @@
|
|||
---
|
||||
title: Path.shiftFractionAlong()
|
||||
---
|
||||
|
||||
The `Path.shiftFractionAlong()` returns a point that lies at fraction of the
|
||||
length of the path travelled along the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Point path.shiftFractionAlong(float fraction, int stepsPerMm = 25)
|
||||
```
|
||||
|
||||
The second parameter controls the precision by which the path will be _walked_.
|
||||
By default, we'll divide it into 10 steps per mm.
|
||||
|
||||
If you don't need that precision, you can pass a lower number.
|
||||
If you need more precision, you can pass a higher number.
|
||||
For most cases, the default will be fine.
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.shiftFractionAlong() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, Snippet, snippets, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
|
||||
points.x1 = paths.example
|
||||
.shiftFractionAlong(0.2)
|
||||
.setText("0.2", "center")
|
||||
points.x2 = paths.example
|
||||
.shiftFractionAlong(0.9)
|
||||
.setText("0.9", "center")
|
||||
|
||||
snippets.xl = new Snippet("notch", points.x1)
|
||||
snippets.x2 = new Snippet("notch", points.x2)
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
40
sites/dev/docs/reference/api/path/smurve/readme.mdx
Normal file
40
sites/dev/docs/reference/api/path/smurve/readme.mdx
Normal file
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
title: Path.smurve()
|
||||
---
|
||||
|
||||
The `Path.smurve()` method draws a smooth curve from the current point via a control point to an endpoint.
|
||||
A smooth curve means it will use the reflection of the end control point of the previous curve.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.smurve(Point cp2, Point end)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.smurve() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.aFrom = new Point(10, 10)
|
||||
points.aCp1 = new Point(40, 40)
|
||||
points.aCp2 = new Point(70, -20)
|
||||
points.aTo = new Point(100, 10)
|
||||
|
||||
points.bCp2 = new Point(50,50)
|
||||
points.bTo = new Point(10,50)
|
||||
|
||||
paths.smurve = new Path()
|
||||
.move(points.aFrom)
|
||||
.curve(points.aCp1, points.aCp2,points.aTo)
|
||||
.smurve(points.bCp2, points.bTo)
|
||||
.reverse() // Puts text at the end
|
||||
.setText('Path.smurve()')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
41
sites/dev/docs/reference/api/path/smurve_/readme.mdx
Normal file
41
sites/dev/docs/reference/api/path/smurve_/readme.mdx
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
title: Path.smurve_()
|
||||
---
|
||||
|
||||
The `Path.smurve_()` method draws a smooth curve from the current point an endpoint.
|
||||
In addition, the end point's control point lies on top of the end point.
|
||||
|
||||
A smooth curve means it will use the reflection of the end control point of the previous curve.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.smurve_(Point cp2, Point end)
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.smurve_() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.aFrom = new Point(10, 10)
|
||||
points.aCp1 = new Point(40, 40)
|
||||
points.aCp2 = new Point(70, -20)
|
||||
points.aTo = new Point(100, 10)
|
||||
|
||||
points.bTo = new Point(10,50)
|
||||
|
||||
paths.smurve = new Path()
|
||||
.move(points.aFrom)
|
||||
.curve(points.aCp1, points.aCp2,points.aTo)
|
||||
.smurve_(points.bTo)
|
||||
.reverse() // Puts text at the end
|
||||
.setText('Path.smurve()')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
69
sites/dev/docs/reference/api/path/split/readme.mdx
Normal file
69
sites/dev/docs/reference/api/path/split/readme.mdx
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
title: Path.split()
|
||||
---
|
||||
|
||||
The `Path.split()` method splits a path in two halves, on a point along that
|
||||
path that you pass it.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
array path.split(Point splitPoint)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.split() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
points.D = new Point(50, 130)
|
||||
points.DCp1 = new Point(150, 30)
|
||||
|
||||
paths.demo = new Path()
|
||||
.move(points.D)
|
||||
.curve(points.DCp1, points.DCp1, points.C)
|
||||
.curve(points.CCp1, points.BCp2, points.B)
|
||||
.line(points.A)
|
||||
|
||||
points.split = paths.demo.shiftFractionAlong(0.75)
|
||||
snippets.split = new Snippet("notch", points.split)
|
||||
|
||||
let halves = paths.demo.split(points.split)
|
||||
for (let i in halves) {
|
||||
paths[i] = halves[i]
|
||||
.attr("style", "stroke-width: 3; stroke-opacity: 0.5;")
|
||||
.attr("style", `stroke: hsl(${i * 70}, 100%, 50%)`)
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
## Notes
|
||||
|
||||
### The returned array will hold null for edge cases
|
||||
|
||||
Typically, the returned array will hold a `Path` object for each half.
|
||||
But in some cases, one of the array entries can hold `null` if the split failed to find a path.
|
||||
For example because you are splitting a `Path` on its start or end point.
|
||||
|
||||
```mjs
|
||||
// Return value for a normal case
|
||||
[Path, Path]
|
||||
// Return value when calling Path.split() on/near the path's start point
|
||||
[null, Path]
|
||||
// Return value when calling Path.split() on/near the path's end point
|
||||
[Path, null]
|
||||
```
|
||||
|
||||
### This method will snap the split point to start or end points
|
||||
This method will also _snap_ to the start or end point if you are splitting a path
|
||||
(very) close to it, as it checks with [`Point.sitsRoughlyOn()`](/reference/api/point/sitsroughlyon).
|
||||
|
37
sites/dev/docs/reference/api/path/start/readme.mdx
Normal file
37
sites/dev/docs/reference/api/path/start/readme.mdx
Normal file
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: Path.start()
|
||||
---
|
||||
|
||||
The `Path.start()` method returns the Point object at the start of the path.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Point path.start()
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.start() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, snippets, Snippet, part }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.demo = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
|
||||
snippets.end = new Snippet("notch", paths.demo.start())
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
50
sites/dev/docs/reference/api/path/translate/readme.mdx
Normal file
50
sites/dev/docs/reference/api/path/translate/readme.mdx
Normal file
|
@ -0,0 +1,50 @@
|
|||
---
|
||||
title: Path.translate()
|
||||
---
|
||||
|
||||
The `Path.translate()` method returns a path with
|
||||
[a translate transform](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform#Translate)
|
||||
applied.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
Path path.translate(float deltaX, float deltaY)
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.translate() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part, macro }) => {
|
||||
|
||||
points.A = new Point(45, 60)
|
||||
points.B = new Point(10, 30)
|
||||
points.BCp2 = new Point(40, 20)
|
||||
points.C = new Point(90, 30)
|
||||
points.CCp1 = new Point(50, -30)
|
||||
|
||||
paths.A = new Path()
|
||||
.move(points.A)
|
||||
.line(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
|
||||
paths.B = paths.A.translate(60, 30)
|
||||
|
||||
points.step1 = points.B.shift(0, 60)
|
||||
points.step2 = points.step1.shift(-90, 30)
|
||||
macro("ld", {
|
||||
from: points.B,
|
||||
to: points.step1,
|
||||
noStartMarker: true
|
||||
})
|
||||
macro("ld", {
|
||||
from: points.step1,
|
||||
to: points.step2,
|
||||
noStartMarker: true
|
||||
})
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
74
sites/dev/docs/reference/api/path/trim/readme.mdx
Normal file
74
sites/dev/docs/reference/api/path/trim/readme.mdx
Normal file
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
title: Path.trim()
|
||||
---
|
||||
|
||||
The `Path.trim()` method Returns a new Path that is this path with overlapping
|
||||
parts removed.
|
||||
|
||||
```js
|
||||
Path path.trim()
|
||||
```
|
||||
|
||||
|
||||
|
||||
<Example caption="Example of the Path.trim() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.center = new Point(0, 0)
|
||||
points.base = new Point(0, 10)
|
||||
points.tip = new Point(0, 50)
|
||||
points.tipCpRight = new Point(30, 50)
|
||||
points.tipCpLeft = new Point(-30, 50)
|
||||
paths.example = new Path().move(points.base)
|
||||
for (let i = 0; i < 4; i++) {
|
||||
points["base" + i] = points.base.rotate(60 * i, points.center)
|
||||
points["tip" + i] = points.tip.rotate(60 * i, points.center)
|
||||
points["tipCpRight" + i] = points.tipCpRight.rotate(60 * i, points.center)
|
||||
points["tipCpLeft" + i] = points.tipCpLeft.rotate(60 * i, points.center)
|
||||
if (i < 2) {
|
||||
paths.example
|
||||
.line(points["base" + i])
|
||||
.curve(points["base" + i], points["tipCpLeft" + i], points["tip" + i])
|
||||
.curve(
|
||||
points["tipCpRight" + i],
|
||||
points["base" + i],
|
||||
points["base" + i]
|
||||
)
|
||||
} else {
|
||||
paths.example
|
||||
.line(points["base" + i])
|
||||
.line(points["tip" + i])
|
||||
.line(points["tipCpRight" + i])
|
||||
.line(points["base" + i])
|
||||
}
|
||||
}
|
||||
|
||||
paths.offset = paths.example
|
||||
.offset(10)
|
||||
.setClass("lining dotted stroke-sm")
|
||||
|
||||
paths.trimmed = paths.offset
|
||||
.trim()
|
||||
.setClass("various stroke-xl")
|
||||
.attr("style", "stroke-opacity: 0.5")
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
|
||||
## Notes
|
||||
|
||||
This method is typically used when [Path.offset()](/reference/api/path/offset) caused some overlap.
|
||||
However, use this sparsely or performance will suffer.
|
||||
|
||||
This method is recursive and complex, and the performance penalty for using
|
||||
it on a long/complex path will be significant.
|
||||
|
||||
To limit the impact of path.trim(), follow this approach:
|
||||
|
||||
- construct a minimal path that contains the overlap
|
||||
- trim it
|
||||
- now join it to the rest of your path
|
34
sites/dev/docs/reference/api/path/unhide/readme.mdx
Normal file
34
sites/dev/docs/reference/api/path/unhide/readme.mdx
Normal file
|
@ -0,0 +1,34 @@
|
|||
---
|
||||
title: Path.unhide()
|
||||
---
|
||||
|
||||
The `Path.unhide()` method unhides the path so it appears in the output. By
|
||||
default, paths are not hidden. So you should only call this on path previously
|
||||
hidden via `Path.hide()`.
|
||||
|
||||
## Signature
|
||||
|
||||
```js
|
||||
Path path.unhide()
|
||||
```
|
||||
|
||||
:::tipThis method is chainable as it returns the `Path` object:::
|
||||
|
||||
## Example
|
||||
|
||||
<Example caption="Example of the Path.unhide() method">
|
||||
```js
|
||||
({ Point, points, Path, paths, part }) => {
|
||||
|
||||
points.top = new Point(50, 0)
|
||||
points.left = new Point (20,50)
|
||||
points.right = new Point (80,50)
|
||||
|
||||
paths.a = new Path().move(points.top).line(points.right).setText('a')
|
||||
paths.b = new Path().move(points.right).line(points.left).setText('b').hide().unhide()
|
||||
paths.c = new Path().move(points.left).line(points.top).setText('c')
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
48
sites/dev/docs/reference/api/pattern/addpart/readme.mdx
Normal file
48
sites/dev/docs/reference/api/pattern/addpart/readme.mdx
Normal file
|
@ -0,0 +1,48 @@
|
|||
---
|
||||
title: Pattern.addPart()
|
||||
---
|
||||
|
||||
The `Pattern.addPart()` method allows you to add a part to a pattern.
|
||||
It has the same effect as passing a part to the Design constructor.
|
||||
|
||||
:::noteThis method is chainable as it returns the Pattern object:::
|
||||
|
||||
## Pattern.addPart() signature
|
||||
|
||||
```js
|
||||
Pattern pattern.addPart(object part)
|
||||
```
|
||||
|
||||
## Pattern.addPart() example
|
||||
|
||||
```js
|
||||
import { Aaron } from "@freesewing/aaron"
|
||||
|
||||
const extra = {
|
||||
name: 'aaron.extra',
|
||||
draft: ({ points, Point, paths, Path, part }) => {
|
||||
points.msg = new Point(50,15)
|
||||
.attr('data-text', "I am an extra part")
|
||||
paths.box = new Path()
|
||||
.move(new Point(0,0))
|
||||
.line(new Point(0,30))
|
||||
.line(new Point(100,30))
|
||||
.line(new Point(100,0))
|
||||
.close(new Point(100,0))
|
||||
.addClass('note')
|
||||
|
||||
return part
|
||||
}
|
||||
}
|
||||
|
||||
// Load some public test measurements from the FreeSewing backend
|
||||
const measurements = (
|
||||
await (
|
||||
await fetch("https://backend3.freesewing.org/curated-sets/1.json")
|
||||
).json()
|
||||
).measurements
|
||||
|
||||
const pattern = new Aaron({ measurements }).addPart(extra)
|
||||
|
||||
const svg = pattern.draft().render()
|
||||
```
|
33
sites/dev/docs/reference/api/pattern/draft/readme.mdx
Normal file
33
sites/dev/docs/reference/api/pattern/draft/readme.mdx
Normal file
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
title: Pattern.draft()
|
||||
---
|
||||
|
||||
A pattern's `draft()` method will draft the different pattern parts
|
||||
making sure to do so in the right order, handle dependencies, resolve
|
||||
options to their absolute values and a number of other housekeeping things
|
||||
that are required for the pattern to be drafted.
|
||||
|
||||
:::noteThis method is chainable as it returns the Pattern object:::
|
||||
|
||||
## Pattern.draft() signature
|
||||
|
||||
```js
|
||||
Pattern pattern.draft()
|
||||
```
|
||||
|
||||
## Pattern.draft() example
|
||||
|
||||
```js
|
||||
import { Aaron } from "@freesewing/aaron"
|
||||
|
||||
// Load some public test measurements from the FreeSewing backend
|
||||
const measurements = (
|
||||
await (
|
||||
await fetch("https://backend3.freesewing.org/curated-sets/1.json")
|
||||
).json()
|
||||
).measurements
|
||||
|
||||
const pattern = new Aaron({ measurements })
|
||||
|
||||
const svg = pattern.draft().render()
|
||||
```
|
|
@ -0,0 +1,33 @@
|
|||
---
|
||||
title: Pattern.draftPartForSet()
|
||||
---
|
||||
|
||||
A pattern's `draftPartForSet()` method will draft a part using a
|
||||
given set of settings.
|
||||
|
||||
:::noteThis method is chainable as it returns the Pattern object:::
|
||||
|
||||
## Pattern.draftPartForSet() signature
|
||||
|
||||
```js
|
||||
Pattern pattern.draftPartForSet(part, set)
|
||||
```
|
||||
|
||||
## Pattern.draftPartForSet() example
|
||||
|
||||
```js
|
||||
import { Aaron } from "@freesewing/aaron"
|
||||
|
||||
// Load a public test settings set from the FreeSewing backend
|
||||
const set = (
|
||||
await (
|
||||
await fetch("https://backend3.freesewing.org/curated-sets/1.json")
|
||||
).json()
|
||||
)
|
||||
|
||||
const pattern = new Aaron()
|
||||
|
||||
for (const part in pattern.parts) {
|
||||
const svg = pattern.draftPartForSet(part, set).render()
|
||||
}
|
||||
```
|
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