feat(markdown): Ported code howtos to v3
This commit is contained in:
parent
d1edf93750
commit
af99d3e8c0
25 changed files with 451 additions and 636 deletions
|
@ -1,18 +1,22 @@
|
|||
---
|
||||
title: Accessing measurements
|
||||
for: developers
|
||||
about: Shows you how to access user measurements from inside your pattern
|
||||
---
|
||||
|
||||
Measurements are stored in `pattern.settings.measurements`.
|
||||
Measurements are available on the `measurements` key of from the object passed
|
||||
to your part's draft method. You can destructure them for easy access.
|
||||
|
||||
You can pull them out of there with
|
||||
the [shorthand](/howtos/code/shorthand/) call:
|
||||
```design/src/part.mjs
|
||||
function draftPart = ({
|
||||
// highlight-start
|
||||
measurements,
|
||||
// highlight-end
|
||||
part
|
||||
}) {
|
||||
|
||||
```js
|
||||
const { measurements, options } = part.shorthand()
|
||||
// Do something here
|
||||
|
||||
let sleeveBonus = measurements.shoulderToWrist * (1 + options.sleeveLengthBonus);
|
||||
return part
|
||||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
|
|
@ -1,16 +1,26 @@
|
|||
---
|
||||
title: Accessing user options
|
||||
for: developers
|
||||
about: Shows you how to access user options from inside your pattern
|
||||
title: Accessing options
|
||||
---
|
||||
|
||||
Options are stored in `pattern.settings.options`.
|
||||
(the value of) Options are available on the `options` key of from the object
|
||||
passed to your part's draft method. You can destructure them for easy access.
|
||||
|
||||
You can pull them out of there with
|
||||
the [shorthand](/howtos/code/shorthand/) call:
|
||||
```design/src/part.mjs
|
||||
function draftPart = ({
|
||||
// highlight-start
|
||||
options,
|
||||
// highlight-end
|
||||
part
|
||||
}) {
|
||||
|
||||
```js
|
||||
const { measurements, options } = part.shorthand()
|
||||
// Do something here
|
||||
|
||||
let sleeveBonus = measurements.shoulderToWrist * (1 + options.sleeveLengthBonus);
|
||||
return part
|
||||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
Unlike measurements, options come with default values.
|
||||
|
||||
</Note>
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
---
|
||||
title: Add instructions to your design
|
||||
for: developers
|
||||
about: While documentation is good, sometimes you want to add some instructions to your design itself
|
||||
---
|
||||
|
||||
<Note>
|
||||
|
||||
##### See this example in our source code
|
||||
|
||||
- [designs/aaron/src/back.js](https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/aaron/src/back.js#L66)
|
||||
|
||||
</Note>
|
||||
|
||||
Adding instructions to your pattern is _just_ a matter of adding text.
|
||||
The tricky part is to make sure your text can be translated.
|
||||
|
||||
Below is a rather involved example from Aaron:
|
||||
|
||||
```js
|
||||
points.bindingAnchor = new Point(points.armhole.x / 4, points.armhole.y)
|
||||
.attr('data-text', 'cutTwoStripsToFinishTheArmholes')
|
||||
.attr('data-text', ':\n')
|
||||
.attr('data-text', `2x: ${units(sa * 6 || 60)} x ${units(armholeLength * 0.95 + 2 * sa)}`)
|
||||
.attr('data-text', '\n \n')
|
||||
.attr('data-text', 'cutOneStripToFinishTheNeckOpening')
|
||||
.attr('data-text', ':\n')
|
||||
.attr('data-text', 'width')
|
||||
.attr('data-text', ':')
|
||||
.attr(
|
||||
'data-text',
|
||||
`${units((sa || 10) * 6)} x ${units(neckOpeningLength * 2 * 0.95 + 2 * sa)}`
|
||||
)
|
||||
```
|
||||
|
||||
If you want to add text along a path, you can do that too:
|
||||
|
||||
```js
|
||||
paths.breakLine.attr('data-text', 'breakLine').attr('data-text-class', 'center')
|
||||
paths.flb.attr('data-text', 'facingLiningBoundary')
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
Refer to [the sprinkle macro documentation](/reference/api/macros/sprinkle/) for details on how
|
||||
to use this macro
|
||||
|
||||
</Tip>
|
|
@ -1,42 +1,29 @@
|
|||
---
|
||||
title: Adding pattern parts
|
||||
for: developers
|
||||
about: Shows you how to add new parts to your pattern
|
||||
---
|
||||
|
||||
Since the patterns parts are listed
|
||||
in [the configuration file](/reference/api/config/), freesewing knows about
|
||||
all the parts that belong to your pattern.
|
||||
Parts can be added to the design add build time, by passing them to [the Design
|
||||
constructor](/reference/api/design), or at runtime by calling
|
||||
[Pattern.addPart()](/reference/api/pattern/addpart). The latter approach is
|
||||
rarely used, but it's there if you need it.
|
||||
|
||||
It expects that each pattern has its own draft method, that is called `draft`
|
||||
followed by the capitalized name of the pattern part.
|
||||
## At build time
|
||||
|
||||
For example, if our pattern `Sorcha` has a part called `back`, you should
|
||||
have a `draftBack` method. It's good practice to keep each part in its own
|
||||
file, so create a file called `back.js`. Inside, you export your method
|
||||
to draft this part:
|
||||
```mjs
|
||||
import { Design } from '@freesewing/core'
|
||||
import { myPart } from './mypart.mjs'
|
||||
|
||||
```js
|
||||
export default part => {
|
||||
// Your part code here
|
||||
|
||||
return part
|
||||
}
|
||||
const Sorcha = new Design({
|
||||
parts: [ myPart ]
|
||||
})
|
||||
```
|
||||
|
||||
Then, in your `index.js` file, you import this file, and attach the
|
||||
method to your pattern's prototype:
|
||||
## At run time
|
||||
|
||||
```js
|
||||
import freesewing from "freesewing"
|
||||
import plugins from "@freesewing/plugin-bundle"
|
||||
import config from "../config"
|
||||
// Parts
|
||||
import draftBack from "./back"
|
||||
```mjs
|
||||
import { Aaron } from '@freesewing/aaron'
|
||||
import { myRuntimePart } from './mypart.mjs'
|
||||
|
||||
// Create new design
|
||||
const Sorcha = new freesewing.Design(config, plugins)
|
||||
|
||||
// Attach to pattern prototype
|
||||
Sorcha.prototype.draftBack = part => draftBack(part)
|
||||
const pattern = new Aaron()
|
||||
pattern.addPart(myRuntimePart)
|
||||
```
|
||||
|
|
|
@ -1,22 +1,30 @@
|
|||
---
|
||||
title: Adding paths
|
||||
for: developers
|
||||
icon: pattern
|
||||
about: Shows you how to add paths to your pattern
|
||||
---
|
||||
|
||||
After using the [shorthand](/howtos/code/shorthand/) call,
|
||||
`Path` contains the path constructor, while `paths` is a reference to `part.paths`,
|
||||
which is where you should store your paths.
|
||||
Paths should be stored in the `paths` key of the object passed to your part's
|
||||
draft method. The contructor for paths is available in the `Path` key. You can
|
||||
destructure them for easy access.
|
||||
|
||||
Things will now _just work_ when you do this:
|
||||
<Example caption="An example of adding a path" tutorial>
|
||||
```design/src/part.mjs
|
||||
function draftPart = ({
|
||||
Point,
|
||||
// highlight-start
|
||||
Path,
|
||||
paths,
|
||||
// highlight-end
|
||||
part
|
||||
}) {
|
||||
|
||||
```js
|
||||
paths.example = new Path()
|
||||
// highlight-start
|
||||
paths.demo = new Path()
|
||||
.move(new Point(0,0))
|
||||
.line(new Point(100,20))
|
||||
.addClass('lining lashed')
|
||||
// highlight-end
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
The [Path API docs](/reference/api/path) list all the things you can do with a path object.
|
||||
|
||||
</Tip>
|
||||
</Example>
|
||||
|
|
|
@ -1,21 +1,26 @@
|
|||
---
|
||||
title: Adding points
|
||||
for: developers
|
||||
about: Shows you how to add points to your pattern
|
||||
---
|
||||
|
||||
After using the [shorthand](/howtos/code/shorthand/) call,
|
||||
`Point` contains the point constructor, while `points` is a reference to `part.points`,
|
||||
which is where you should store your points.
|
||||
Points should be stored in the `points` key of the object passed to your part's
|
||||
draft method. The contructor for points is available in the `Point` key. You
|
||||
can destructure them for easy access.
|
||||
|
||||
Things will now _just work_ when you do this:
|
||||
<Example caption="An example of adding a point" tutorial>
|
||||
```design/src/part.mjs
|
||||
function draftPart = ({
|
||||
// highlight-start
|
||||
Point,
|
||||
points,
|
||||
// highlight-end
|
||||
part
|
||||
}) {
|
||||
|
||||
```js
|
||||
points.centerBack = new Point(0,0);
|
||||
// highlight-start
|
||||
points.demo = new Point(0,0).addText('hi')
|
||||
// highlight-end
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
The [Point API docs](/reference/api/point/) list many ways to create a point.
|
||||
|
||||
</Tip>
|
||||
</Example>
|
||||
|
|
|
@ -1,32 +1,51 @@
|
|||
---
|
||||
title: Adding snippets
|
||||
for: developers
|
||||
about: Shows you how to add snippets to your pattern
|
||||
---
|
||||
|
||||
After using the [shorthand](/howtos/code/shorthand/) call,
|
||||
`Snippet` contains the path constructor, while `snippets` is a reference to `part.snippets`,
|
||||
which is where you should store your paths.
|
||||
Snippets should be stored in the `snippets` key of the object passed to your part's
|
||||
draft method. The contructor for snippets is available in the `Snippets` key. You can
|
||||
destructure them for easy access.
|
||||
|
||||
Things will now _just work_ when you do this:
|
||||
<Example caption="An example of adding a snippet" tutorial>
|
||||
```design/src/part.mjs
|
||||
function draftPart = ({
|
||||
Point,
|
||||
Path,
|
||||
paths,
|
||||
// highlight-start
|
||||
Snippet,
|
||||
snippets,
|
||||
// highlight-end
|
||||
part
|
||||
}) {
|
||||
|
||||
```js
|
||||
snippets.logo = new Snippet('logo', points.logoAnchor);
|
||||
// highlight-start
|
||||
snippets.logo = new Snippet('logo', new Point(50,50))
|
||||
.attr('data-scale', 0.5)
|
||||
.attr('data-rotate', 180)
|
||||
// highlight-end
|
||||
|
||||
// prevent clipping
|
||||
paths.demo = new Path()
|
||||
.move(new Point(0,0))
|
||||
.move(new Point(100,100))
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
You can scale and rotate a snippet by setting the `data-scale` and `data-rotate` attributes respectively.
|
||||
|
||||
- **data-scale** : Either a single scale factor, or a set of 2 scale factors for the X and Y axis respectively. See [the SVG scale transform](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform#Scale) for details.
|
||||
- **data-rotate**: A rotation in degrees. The center of the rotation will be the snippet's anchor point
|
||||
- **data-scale** : Either a single scale factor, or a set of 2 scale factors
|
||||
for the X and Y axis respectively. See [the SVG scale
|
||||
transform](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/transform#Scale)
|
||||
for details.
|
||||
- **data-rotate**: A rotation in degrees. The center of the rotation will be
|
||||
the snippet's anchor point
|
||||
|
||||
<Tip>
|
||||
|
||||
See [Using attributes](/howtos/code/attributes/) for details on how to set attributes.
|
||||
|
||||
</Tip>
|
||||
|
||||
Below is an example of the available snippets, and the use of the `data-scale` and `data-rotate` attributes:
|
||||
|
||||
<Example pattern="rendertest" options_only="snippets">
|
||||
Overview of available snippets
|
||||
</Example>
|
||||
|
|
|
@ -4,45 +4,37 @@ title: Adding text
|
|||
|
||||
SVG is pretty great, but its text handling leaves much to be desired.
|
||||
|
||||
To abstract away the intricacies of adding text to an SVG document,
|
||||
FreeSewing lets you add text to patterns by adding it to the attributes
|
||||
of points and paths.
|
||||
To abstract away the intricacies of adding text to an SVG document, FreeSewing
|
||||
provides the [Point.addText()](/reference/api/point/addtext) and
|
||||
[Path.addText()](/reference/api/path/addtext) methods to let you add text to
|
||||
points and paths.
|
||||
|
||||
All you have to do is set the `data-text` attribute to the text you want to add to the pattern:
|
||||
<Example caption="An example of adding text" tutorial>
|
||||
```design/src/part.mjs
|
||||
function draftPart = ({
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
part
|
||||
}) {
|
||||
|
||||
```js
|
||||
points.anchor = new Point(100, 25)
|
||||
.attr("data-text", "freesewingIsMadeByJoostDeCockAndContributors")
|
||||
.attr("data-text-class", "center");
|
||||
points.demo = new Point(70,10)
|
||||
// highlight-start
|
||||
.addText('Text on a point', 'center')
|
||||
// highlight-end
|
||||
|
||||
paths.demo = new Path()
|
||||
.move(new Point(0,0))
|
||||
.line(new Point(100, 40))
|
||||
.addClass('note dotted stroke-sm')
|
||||
// highlight-start
|
||||
.addText('Text on a path', 'center')
|
||||
// highlight-end
|
||||
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
|
||||
<Example part="point_attr">Text inserted in a FreeSewing pattern</Example>
|
||||
|
||||
<Note>
|
||||
|
||||
You may have noticed that the text we inserted isn't the text that's shown.
|
||||
That is because, in line with our [best practices](/guides/best-practices) we allow translation of
|
||||
our pattern by inserting a key that is used to lookup the string in the language
|
||||
of the pattern, using [the i18n plugin](/reference/plugins/i18n).
|
||||
|
||||
</Note>
|
||||
|
||||
You can use the same approach to add text to a path:
|
||||
|
||||
```js
|
||||
points.B = new Point(10, 50);
|
||||
points.BCp2 = new Point(40, 10);
|
||||
points.C = new Point(90, 30);
|
||||
points.CCp1 = new Point(50, 90);
|
||||
|
||||
paths.example = new Path()
|
||||
.move(points.B)
|
||||
.curve(points.BCp2, points.CCp1, points.C)
|
||||
.attr("class", "canvas")
|
||||
.attr("data-text", "freesewingIsMadeByJoostDeCockAndContributors")
|
||||
.attr("data-text-class", "text-xs center");
|
||||
```
|
||||
|
||||
<Example part="path_attr">
|
||||
Text on a path
|
||||
</Example>
|
||||
```
|
||||
|
|
37
markdown/dev/howtos/code/after/en.md
Normal file
37
markdown/dev/howtos/code/after/en.md
Normal file
|
@ -0,0 +1,37 @@
|
|||
---
|
||||
title: Part dependencies
|
||||
---
|
||||
|
||||
Part dependencies control the order in which parts are drafted. FreeSewing will
|
||||
make sure to draft all of a part's dependencies before drafting the part
|
||||
itself.
|
||||
|
||||
<Warning compact>
|
||||
Do not confuse this with [part inheritance](/howtos/code/from).
|
||||
</Warning>
|
||||
|
||||
Part dependencies are configured with [the `after`
|
||||
keyword](/reference/api/part/config/dependencies#after). Let's look at an
|
||||
example:
|
||||
|
||||
```js
|
||||
// highlight-start
|
||||
import { otherPart } from './otherpart.mjs'
|
||||
// highlight-end
|
||||
|
||||
export const myPart = {
|
||||
name: 'example.myPart',
|
||||
// highlight-start
|
||||
after: otherPart,
|
||||
// highlight-end
|
||||
draft: function ({ part }) {
|
||||
// Design part here
|
||||
return part
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Refer to [the part documentation on
|
||||
dependencies](/reference/api/part/config/dependencies) for all details.
|
||||
</Tip>
|
|
@ -1,11 +1,51 @@
|
|||
---
|
||||
title: Using attributes
|
||||
for: developers
|
||||
about: Show s you have to use attributes on points, paths, and snippets
|
||||
---
|
||||
|
||||
Points, Paths, and Snippets all have [attributes](/reference/api/attributes/) that you can use to
|
||||
influence how they behave.
|
||||
Points, Paths, and Snippets all have [attributes](/reference/api/attributes/)
|
||||
that you can use to influence how they behave.
|
||||
|
||||
Under the hood, text, css classes, and even circles are all set in attributes.
|
||||
There are plenty of higher-level helper methods available, but knowing how to
|
||||
manipulate attributes is useful in case you want to accomplish something for
|
||||
which there is no higher-level helper method.
|
||||
|
||||
Let's use an example to see the different ways we can assign a css class:
|
||||
|
||||
<Example caption="Various ways to set attributes on a point">
|
||||
```mjs
|
||||
({ points, Point, paths, Path, part }) => {
|
||||
/*
|
||||
* Via the high-level Point.addText method
|
||||
*/
|
||||
points.a = new Point(0,0)
|
||||
.addText('I am bold and colorful', 'bold fill-note')
|
||||
|
||||
/*
|
||||
* Via the lower-level Point.attr method
|
||||
*/
|
||||
points.b = new Point(0,10)
|
||||
.attr('data-text', 'I am bold and colorful')
|
||||
.attr('data-text-class', 'bold fill-lining')
|
||||
|
||||
/*
|
||||
* Via low-level access to the attributes property
|
||||
*/
|
||||
points.c = new Point(0,20)
|
||||
points.c.attributes.add('data-text', 'I am bold and colorful')
|
||||
points.c.attributes.add('data-text-class', 'bold fill-contrast')
|
||||
|
||||
// Prevent clipping
|
||||
paths.diag = new Path()
|
||||
.move(new Point(-10,-5))
|
||||
.move(new Point(80,25))
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
kEven though there are helpers methods available for them.
|
||||
|
||||
A common scenario is to apply CSS classes to style a path:
|
||||
|
||||
|
|
|
@ -4,39 +4,40 @@ for: developers
|
|||
about: Shows you how to create a new design
|
||||
---
|
||||
|
||||
To create a new pattern, call `new freesewing.Design()`.
|
||||
It takes your pattern configuration,
|
||||
and any plugins you want to load as parameters.
|
||||
When creating a new design, you have two options:
|
||||
|
||||
For example, if we were creating a new pattern called `Sorcha`:
|
||||
- Create it in a stand-along development environment
|
||||
- Create it inside (your fork of ) the FreeSewing monorepo
|
||||
|
||||
```js
|
||||
import freesewing from "@freesewing/core"
|
||||
import plugins from "@freesewing/plugin-bundle"
|
||||
import config from "../config"
|
||||
If you are unsure what to pick, go with the standalong development environment.
|
||||
It is the best choice for people new to FreeSewing.
|
||||
|
||||
// Create new design
|
||||
const Sorcha = new freesewing.Design(config, plugins)
|
||||
Working inside the monorepo is the preferred way of regular contributors, but
|
||||
if you were a regular contributor, you would probably already know this. So
|
||||
when in doubt, go stand-alone. You can always change track later.
|
||||
|
||||
## Stand-alone
|
||||
|
||||
To setup the standalong development environment, you need NodeJS 16 or higher.
|
||||
Then run:
|
||||
|
||||
```sh
|
||||
npx @freesewing/new-design@next
|
||||
```
|
||||
|
||||
This method does not return a `Design` object. Instead it returns
|
||||
a constructor method for your pattern.
|
||||
This command will setup FreeSewing's stand-alone development environment.
|
||||
|
||||
When importing your pattern, it is itself a constructor:
|
||||
## Work inside the monorepo
|
||||
|
||||
```js
|
||||
import Sorcha from "@freesewing/sorcha"
|
||||
First, [fork our monorepo](https://github.com/freesewing/freesewing/fork). Then run:
|
||||
|
||||
// Sorcha is a constructor for your pattern.
|
||||
let pattern = new Sorcha()
|
||||
```sh
|
||||
git clone <url to your fork>
|
||||
cd freesewing
|
||||
yarn kickstart
|
||||
yarn new design
|
||||
```
|
||||
|
||||
<Tip>
|
||||
|
||||
##### Design() is a super-constructor
|
||||
|
||||
Constructors are functions you can call with `new` to create an object.
|
||||
As `freesewing.Design()` returns a constructor, you can think of it
|
||||
as a super-constructor.
|
||||
|
||||
</Tip>
|
||||
These commands will clone your fork of the
|
||||
[freesewing/freesewing](https://github.com/freesewing/freesewing) repository on
|
||||
Github and set it up for development.
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
---
|
||||
title: Part dependencies
|
||||
for: developers
|
||||
about: Shows you how to create dependencies between pattern parts
|
||||
---
|
||||
|
||||
Part dependencies are set in the [pattern configuration](/reference/api/config), and
|
||||
control the order in which parts are drawn. FreeSewing will make sure
|
||||
that before drafting a part, it will first draft all its dependencies.
|
||||
|
||||
Let's look at an example:
|
||||
|
||||
```js
|
||||
dependencies: {
|
||||
front: "base",
|
||||
back: "base",
|
||||
sleeve: ["front", "back"]
|
||||
}
|
||||
```
|
||||
|
||||
This could be from a T-shirt pattern where the `front` and `back` patterns are very similar,
|
||||
so they both are inheriting a `base` part.
|
||||
In addition, the `sleeve` part needs to be drafted after the `front` and `back` part because
|
||||
in `front` and `back` we store the length of the armhole seam in the [store](/reference/api/store) and
|
||||
we need that info to fit the sleevecap to the armhole.
|
||||
|
||||
Now if a user requests to draft only the `sleeve` part, FreeSewing will still draft:
|
||||
|
||||
- First the `base` part
|
||||
- Then the `front` and `back` parts
|
||||
- Finally the `sleeve` part
|
||||
|
||||
but it will only render the `sleeve` part, as that's the only thing the user requested.
|
||||
|
||||
<Note>
|
||||
|
||||
For inheriting parts, please refer to [part inheritance](/howtos/code/inject/).
|
||||
|
||||
</Note>
|
|
@ -2,21 +2,44 @@
|
|||
title: Drawing circles
|
||||
---
|
||||
|
||||
Real circles are rarely used in pattern design, and they are not part of the SVG path specification,
|
||||
but rather a different SVG element.
|
||||
Real circles are rarely used in pattern design, and they are not part of the
|
||||
SVG path specification, but rather a different SVG element.
|
||||
|
||||
Still, if you want a circle, you can draw one by setting a Point's `data-circle` attribute
|
||||
to the radius of the circle you want to draw.
|
||||
Still, if you want a circle, you can draw one by calling
|
||||
[`Point.addCircle()`](/reference/api/point/addcircle):
|
||||
|
||||
In addition, all attributes that have a `data-circle-` prefix will apply to the circle, rather than the point.
|
||||
<Example caption="An example of adding a path" tutorial>
|
||||
```design/src/part.mjs
|
||||
function draftPart = ({
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
part
|
||||
}) {
|
||||
|
||||
Practically, you will probably want to use
|
||||
the [Point.addCircle()](/reference/api/point/adcircle) which does all of this for you behind the scenes:
|
||||
points.anchor = new Point(0,0)
|
||||
// highlight-start
|
||||
.addCircle(5, 'lining dotted')
|
||||
.addCircle(10, 'note dashed ')
|
||||
.addCircle(15, 'facing lashed')
|
||||
.addCircle(20, 'interfacing')
|
||||
// highlight-end
|
||||
|
||||
<Example part="point_addcircle">
|
||||
Examples of circles drawn on a pattern
|
||||
// Prevent clipping
|
||||
paths.demo = new Path()
|
||||
.move(new Point(-20,-20))
|
||||
.move(new Point(20,20))
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
<Warning>
|
||||
Circles are not taken into account when calculating the part's boundary.
|
||||
</Warning>
|
||||
|
||||
<Comment by="joost">
|
||||
##### How multiple circles are implemented
|
||||
|
||||
|
@ -45,3 +68,4 @@ While this is probably what you'd intuitively expect, it is somewhat inconsisten
|
|||
other attributes are rendered, so I felt it was best to point it out explicitly.
|
||||
|
||||
</Comment>
|
||||
|
||||
|
|
|
@ -1,147 +0,0 @@
|
|||
---
|
||||
title: Create a new design based on an existing design
|
||||
---
|
||||
|
||||
<Note>
|
||||
|
||||
##### See this example in our source code
|
||||
|
||||
- [designs/aaron/config/index.js](https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/aaron/config/index.js#L36)
|
||||
- [designs/aaron/src/index.js](https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/aaron/src/index.js#L2)
|
||||
- [designs/carlita/src/index.js](https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/carlita/src/index.js#L25)
|
||||
|
||||
</Note>
|
||||
|
||||
## Setup
|
||||
|
||||
To be able to extend existing patterns, you will have to access them on your local machine. There are two ways to do this:
|
||||
|
||||
- add needed dependencies when using `npx @freesewing/new-design`
|
||||
- create your new pattern in a clone of the [freesewing monorepo](https://github.com/freesewing/freesewing)
|
||||
|
||||
### When using `npx @freesewing/new-design`
|
||||
|
||||
If you want to use one of our blocks, you can simply pick that option when you run `npx @freesewing/new-design`.
|
||||
Doing so will set everything up for you, so you won't have to worry about a thing.
|
||||
|
||||
If you want to extend an existing design, you'll have to do some work yourself.
|
||||
|
||||
#### Start from scratch
|
||||
|
||||
First step is to spin up the development environment. Pick _from scratch_ when prompted:
|
||||
|
||||
```bash
|
||||
npx @freesewing/new-design
|
||||
```
|
||||
|
||||
### Install dependencies
|
||||
|
||||
Let's assume you want to extend **Simon**. You will first need to install it as a dependency.
|
||||
We also need to install **Brian** since Simon is based on Brian:
|
||||
|
||||
```bash
|
||||
npm install --save @freesewing/simon @freesewing/brian
|
||||
```
|
||||
|
||||
This will install both Simon and Brian as a dependency, which you can then access in your pattern.
|
||||
|
||||
<Tip>
|
||||
If the design you extend relies on a design you did not install, error messages will tell you what you are missing
|
||||
</Tip>
|
||||
|
||||
### Import your dependencies
|
||||
|
||||
<Fixme>Complete this documentation</Fixme>
|
||||
|
||||
### Using the freesewing monorepo
|
||||
|
||||
You can use the power of robots to install the needed dependencies if you work in a clone of the [freesewing monorepo](https://github.com/freesewing/freesewing).
|
||||
|
||||
- First, clone the monorepo (or your fork of it) to your local machine.
|
||||
- If you haven't already, now is also a good time to create a feature branch so that you don't work directly in the `develop`-branch of the git-repository: `git checkout -b mycoolnewpattern` (adjust name accordingly).
|
||||
- Go to the root and run `yarn kickstart`. This will take a while, so grab a coffee and come back later.
|
||||
- Once that is done, edit the file `config/descriptions.yaml` to include the name and description of your new pattern (take care to start the description with `A FreeSewing pattern`).
|
||||
- Create a folder for your new pattern in `packages`.
|
||||
- Run `yarn reconfigure`. This will read the changes in `config/descriptions.yaml` and create the needed files in your new folder.
|
||||
- You can now start the actual pattern design work (i.e. editing and adding `src` and `config` files for your pattern.
|
||||
- For dependencies, configure them in `config/dependencies.yaml`.
|
||||
- Run `yarn reconfigure` again, and the magic will make sure that your `package.json` is updated accordingly.
|
||||
- You can set yourself as an author in `config/exceptions.yaml`, and - you guessed it - run `yarn reconfigure` again.
|
||||
- To spin up the development environment, you also need to run `npm install` (or `yarn install`) in the `example`-folder of any pattern you want to work on. (This is because the neccessary `node_modules`-folder is excluded from the git-repository.)
|
||||
|
||||
Now you can work on extending existing patterns into something new and exciting. And the best part about using this method is that making a pull request will be much easier once you're done developing your new pattern.
|
||||
|
||||
## Examples
|
||||
|
||||
The example below is from Aaron, which is based on Brian.
|
||||
|
||||
Brian has a part called `base` that is hidden by default.
|
||||
We will use this part as a dependency, and also hide it.
|
||||
|
||||
This is what it looks like in the Aaron config file:
|
||||
|
||||
```js
|
||||
dependencies: {
|
||||
front: 'base',
|
||||
back: 'front'
|
||||
},
|
||||
inject: {
|
||||
front: 'base',
|
||||
back: 'front'
|
||||
},
|
||||
hide: ['base'],
|
||||
```
|
||||
|
||||
And here is the code:
|
||||
|
||||
```js
|
||||
import freesewing from '@freesewing/core'
|
||||
import Brian from '@freesewing/brian'
|
||||
import plugins from '@freesewing/plugin-bundle'
|
||||
import config from '../config'
|
||||
// Parts
|
||||
import draftBack from './back'
|
||||
import draftFront from './front'
|
||||
|
||||
// Create design
|
||||
const Pattern = new freesewing.Design(config, plugins)
|
||||
|
||||
// Attach draft methods to prototype
|
||||
Pattern.prototype.draftBase = function(part) {
|
||||
// Getting the base part from Brian
|
||||
return new Brian(this.settings).draftBase(part)
|
||||
}
|
||||
Pattern.prototype.draftFront = part => draftFront(part)
|
||||
Pattern.prototype.draftBack = part => draftBack(part)
|
||||
|
||||
export default Pattern
|
||||
```
|
||||
|
||||
If you have a lot of parts to inherit, you can create a loop like in this
|
||||
example from Carlita:
|
||||
|
||||
```js
|
||||
// Attach draft methods from Carlton to prototype
|
||||
for (let m of [
|
||||
'draftBack',
|
||||
'draftTail',
|
||||
'draftTopSleeve',
|
||||
'draftUnderSleeve',
|
||||
'draftBelt',
|
||||
'draftCollarStand',
|
||||
'draftCollar',
|
||||
'draftCuffFacing',
|
||||
'draftPocket',
|
||||
'draftPocketFlap',
|
||||
'draftPocketLining',
|
||||
'draftChestPocketWelt',
|
||||
'draftChestPocketBag',
|
||||
'draftInnerPocketWelt',
|
||||
'draftInnerPocketBag',
|
||||
'draftInnerPocketTab'
|
||||
]) {
|
||||
Pattern.prototype[m] = function(part) {
|
||||
return new Carlton(this.settings)[m](part)
|
||||
}
|
||||
}
|
||||
```
|
36
markdown/dev/howtos/code/from/en.md
Normal file
36
markdown/dev/howtos/code/from/en.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
title: Part inheritance
|
||||
---
|
||||
|
||||
Part inheritance means that rather than start your part from a blank slate, your starting point is another part.
|
||||
You will _inherit_ all its points, paths, and snippets, hence the name.
|
||||
|
||||
<Warning compact>
|
||||
Do not confuse this with [part dependencies](/howtos/code/after).
|
||||
</Warning>
|
||||
|
||||
Part inheritance is configured with [the `from`
|
||||
keyword](/reference/api/part/config/dependencies#from). Let's look at an
|
||||
example:
|
||||
|
||||
```js
|
||||
// highlight-start
|
||||
import { front as brianFront } from '@freesewing/brian'
|
||||
// highlight-end
|
||||
|
||||
export const front = {
|
||||
name: 'example.front',
|
||||
// highlight-start
|
||||
from: brianFront,
|
||||
// highlight-end
|
||||
draft: function ({ part }) {
|
||||
// Design part here
|
||||
return part
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Refer to [the part documentation on
|
||||
dependencies](/reference/api/part/config/dependencies) for all details.
|
||||
</Tip>
|
|
@ -1,22 +1,30 @@
|
|||
---
|
||||
title: Hide paths from an inherited part
|
||||
for: developers
|
||||
about: When you inherit a part, it comes with a bunch of paths. Here'show to hide them
|
||||
title: Hide ore remove paths from an inherited part
|
||||
---
|
||||
|
||||
<Note>
|
||||
To hide remove paths from an inherited part, iterate over the `paths` object
|
||||
and call `Path.hide()` on all entries:
|
||||
|
||||
##### See this example in our source code
|
||||
|
||||
- [designs/aaron/src/front.js](https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/aaron/src/front.js#L22)
|
||||
|
||||
</Note>
|
||||
|
||||
The example below is from Aaron which inherits from Brian.
|
||||
|
||||
We iterate over the paths and set their render property to false.
|
||||
|
||||
```js
|
||||
// Hide Brian paths
|
||||
for (let key of Object.keys(paths)) paths[key].render = false
|
||||
```mjs
|
||||
for (const i in paths) paths[i].hide()
|
||||
```
|
||||
|
||||
To outright remove the paths all together, delete them:
|
||||
|
||||
```mjs
|
||||
for (const i in paths) delete paths[i]
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Do __not__ replace the `path` object:
|
||||
|
||||
```mjs
|
||||
paths = {}
|
||||
```
|
||||
|
||||
as the `paths` object is more than a pojo (plain old javascript object)
|
||||
</Warning>
|
||||
|
||||
<Tip>
|
||||
You can use the same strategy for hiding or removing points or snippets.
|
||||
</Tip>
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
---
|
||||
title: Design inheritance
|
||||
for: developers
|
||||
about: Shows how you can use one design as the basis for another
|
||||
---
|
||||
|
||||
If your pattern is based on, or extending, another pattern (some of) your
|
||||
pattern parts will need to be drafted by the parent pattern.
|
||||
|
||||
In such a case, rather than return our own draft method for the part, you
|
||||
should instantiate the parent pattern, and return its part draft method:
|
||||
|
||||
```js
|
||||
import freesewing from "@freesewing/core";
|
||||
import Brian from "@freesewing/brian";
|
||||
import plugins from "@freesewing/plugin-bundle";
|
||||
import config from "../config";
|
||||
// Parts
|
||||
import draftBack from "./back";
|
||||
|
||||
// Create new design
|
||||
const Sorcha = new freesewing.Design(config, plugins);
|
||||
|
||||
// Attach our own draft method to the prototype
|
||||
Sorcha.prototype.draftBack = part => draftBack(part);
|
||||
|
||||
// Attach the inherited draft method to the prototype
|
||||
Sorcha.prototype.draftBase = function(part) {
|
||||
// Getting the base part from Brian
|
||||
return new Brian(this.settings).draftBase(part);
|
||||
};
|
||||
```
|
||||
|
||||
<Warning>
|
||||
|
||||
Because we're using the `this` keyword here, you cannot use the arrow notation.
|
||||
|
||||
</Warning>
|
||||
|
||||
## Configuration
|
||||
|
||||
The inherited pattern parts will use the configuration of your pattern.
|
||||
You must take care to make sure that
|
||||
your pattern has all the options the parent pattern requires.
|
||||
|
||||
For example, if you inherit from a pattern that has a `chestEase` option, you will
|
||||
need to add that option to your own patter, because the inherited parts will depend on it.
|
||||
|
||||
## Dependencies
|
||||
|
||||
When extending a pattern, you should add it as a peer dependency, rather than a regular dependency.
|
||||
Doing so will avoid that the parent pattern will get bundled with your own pattern.
|
|
@ -1,34 +0,0 @@
|
|||
---
|
||||
title: Part inheritance
|
||||
for: developers
|
||||
about: Shows how you can use one part of your pattern as the basis for another
|
||||
---
|
||||
|
||||
Part inheritance within your own pattern is handled via the `inject` settings in
|
||||
the [pattern configuration](/reference/api/config/). Here is a simple example:
|
||||
|
||||
```js
|
||||
inject: {
|
||||
front: "base",
|
||||
back: "base",
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
The `front` and `back` parts will be _injected_ with the `base` part. As a result, both
|
||||
the `front` and `back` parts will be instantiated with a cloned copy of all the points, paths,
|
||||
and snippets of the `base` part.
|
||||
|
||||
This is a common design pattern where one part builds on another. In our example, we can imagine
|
||||
a T-shirt pattern where the front and back are rather similar, apart from the neckline.
|
||||
So rather than repeating ourselves, we draft a `base` part and inject that in the `front` and
|
||||
`back` parts.
|
||||
|
||||
Using `inject` will cause FreeSewing to always draft the injected part prior to
|
||||
drafting the part it gets injected to. It will, in other words, influece the draft order.
|
||||
|
||||
<Note>
|
||||
|
||||
For inheriting parts from other patterns, please refer to [Design inheritance](/howtos/code/inheritance/).
|
||||
|
||||
</Note>
|
|
@ -5,13 +5,7 @@ about: Shows how you can use macros within your pattern
|
|||
---
|
||||
|
||||
Macros are a way to facilitate pattern design by bundling a bunch of individual actions
|
||||
into a little routine.
|
||||
|
||||
Macros are provided by [plugins](/reference/plugins/). Here are some examples:
|
||||
|
||||
<Example pattern="rendertest" options_only="macros">
|
||||
Some examples of macros
|
||||
</Example>
|
||||
into a little routine. Macros are provided by [plugins](/reference/plugins/).
|
||||
|
||||
Refer to the [macros documentation](/reference/api/macros/) for details on how to use macros,
|
||||
and the [plugins](/reference/plugins/) documentation for info on how to create your
|
||||
|
|
|
@ -1,18 +1,7 @@
|
|||
---
|
||||
title: Share dimensions between pattern parts
|
||||
for: developers
|
||||
about: Shows how to share dimensions between similar pattern parts
|
||||
---
|
||||
|
||||
<Note>
|
||||
|
||||
##### See this example in our source code
|
||||
|
||||
- [designs/aaron/src/shared.js](https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/aaron/src/shared.js)
|
||||
- [designs/aaron/src/front.js](https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/aaron/src/front.js#L160)
|
||||
|
||||
</Note>
|
||||
|
||||
When you have different pattern parts that look similar -- like the front
|
||||
and back of a garment -- you may find that there's a lot of dimensions
|
||||
shared between them.
|
||||
|
@ -20,7 +9,7 @@ shared between them.
|
|||
The example below is from Aaron where dimensions are shared between
|
||||
the back and front part.
|
||||
|
||||
Aaron has a file called `shared.js` that looks like this:
|
||||
Aaron has a file called `shared.mjs` that looks like this:
|
||||
|
||||
```js
|
||||
export function dimensions(macro, points, sa) {
|
||||
|
@ -33,7 +22,8 @@ export function dimensions(macro, points, sa) {
|
|||
}
|
||||
```
|
||||
|
||||
In both `front.js` and `back.js` we use this code to add these shared dimensions:
|
||||
In both `front.mjs` and `back.mjs` we use this code to add these shared
|
||||
dimensions:
|
||||
|
||||
```js
|
||||
import { dimensions } from './shared'
|
||||
|
@ -42,13 +32,6 @@ import { dimensions } from './shared'
|
|||
|
||||
if (paperless) {
|
||||
dimensions(macro, points, sa)
|
||||
// ... specific dimensions
|
||||
// ... dimensions specific to this part
|
||||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
Since our shared dimension method is a so-called _named export_ we need to
|
||||
import it with the syntax you see above.
|
||||
|
||||
</Note>
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
---
|
||||
title: Using shorthand
|
||||
for: developers
|
||||
about: Shows you how to use our shorthand method and notation
|
||||
---
|
||||
|
||||
The [Part.shorthand()](/reference/api/part/shorthand) method will become your best friend.
|
||||
|
||||
By using [object destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring) you'll get access to a bunch
|
||||
of handy variables to make your code more concise and readable.
|
||||
|
||||
[Part.shorthand()](/reference/api/part/shorthand) provides a lot of things, and you typically
|
||||
don't need all of them, but here's everything it has to offer:
|
||||
|
||||
```js
|
||||
const {
|
||||
options, // Pattern options
|
||||
measurements, // Model measurements
|
||||
Point, // Point constructor
|
||||
Path, // Path constructor
|
||||
Snippet, // Snippet constructor
|
||||
points, // Holds part points
|
||||
paths, // Holds part paths
|
||||
snippets, // Holds part snippets
|
||||
store, // The store allows you to share data between parts
|
||||
utils, // A collection of utilities
|
||||
macro, // Method to call a macro
|
||||
debug, // Method to log debug info
|
||||
sa, // Requested seam allowance
|
||||
final, // Whether to draft a complete pattern or not
|
||||
paperless, // Whether to draft a paperless pattern or not
|
||||
units, // Requested units
|
||||
} = part.shorthand();
|
||||
```
|
||||
|
||||
<Note>
|
||||
|
||||
Many examples throughout our documentation use shorthand notation.
|
||||
|
||||
</Note>
|
|
@ -1,33 +1,49 @@
|
|||
---
|
||||
title: Sharing data between parts
|
||||
for: developers
|
||||
about: Shows how you use the pattern store to share data between parts
|
||||
---
|
||||
|
||||
Sometimes, you'll want to access data from one part into another part.
|
||||
For example, you may store the length of the armhole in your front and back parts,
|
||||
and then read that value when drafting the sleeve so you can verify the sleeve fits the armhole.
|
||||
Sometimes, you'll want to access data from one part into another part. For
|
||||
example, you may store the length of the armhole in your front and back parts,
|
||||
and then read that value when drafting the sleeve so you can verify the sleeve
|
||||
fits the armhole.
|
||||
|
||||
For this, you should use the [Store](/reference/api/store/), which is available via
|
||||
the [shorthand](/howtos/code/shorthand/) call:
|
||||
For this, you should use the [Store](/reference/api/store/), which is available
|
||||
via _destructuring_ in your part's draft method.
|
||||
|
||||
```js
|
||||
export default function(part) {
|
||||
let { store } = part.shorthand();
|
||||
store.set('hello', 'world');
|
||||
Setting a value in one part:
|
||||
|
||||
return part();
|
||||
```mjs
|
||||
function draftPartA({
|
||||
// highlight-start
|
||||
store,
|
||||
// highlight-end
|
||||
part,
|
||||
}) {
|
||||
// highlight-start
|
||||
store.set('hello', 'world')
|
||||
// highlight-end
|
||||
|
||||
return part()
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
export default function(part) {
|
||||
let { store } = part.shorthand();
|
||||
store.get('hello'); // Returns 'world'
|
||||
Reading a value in another part:
|
||||
|
||||
return part();
|
||||
```mjs
|
||||
function draftPartB({
|
||||
// highlight-start
|
||||
store,
|
||||
// highlight-end
|
||||
part,
|
||||
}) {
|
||||
// highlight-start
|
||||
const value = store.get('hello')
|
||||
// value now contains 'world'
|
||||
// highlight-end
|
||||
|
||||
return part()
|
||||
}
|
||||
```
|
||||
|
||||
In a case like this, the order in which parts are drafted becomes important, so you
|
||||
should reflect that in the [pattern configuration](/reference/api/config/).
|
||||
should reflect that in the [part dependencies](/howtos/code/after).
|
||||
|
|
|
@ -1,29 +1,21 @@
|
|||
---
|
||||
title: Storing the seam length to use in another part
|
||||
for: developers
|
||||
about: Shows how to store a seam length so you can true the seam of another part
|
||||
---
|
||||
|
||||
<Note>
|
||||
|
||||
##### See this example in our source code
|
||||
|
||||
- [designs/aaron/src/front.js](https://github.com/freesewing/freesewing/blob/3ca5d0edfe54c7ac20aaf3af2f3544aee72f9b99/designs/aaron/src/front.js#L103)
|
||||
|
||||
</Note>
|
||||
|
||||
Often when designing patterns, we need to _true a seam_ which means to make sure
|
||||
that two parts that need to be joined together are the same distance.
|
||||
|
||||
The example below is from Aaron and stores the length of the armhole seam:
|
||||
|
||||
```js
|
||||
// Store length of armhole and neck opening
|
||||
store.set(
|
||||
'frontArmholeLength',
|
||||
new Path()
|
||||
.move(points.armhole)
|
||||
.curve(points.armholeCp2, points.strapRightCp1, points.strapRight)
|
||||
.length()
|
||||
)
|
||||
```mjs
|
||||
// Store length of armhole and neck opening
|
||||
store.set(
|
||||
'frontArmholeLength',
|
||||
new Path()
|
||||
.move(points.armhole)
|
||||
.curve(points.armholeCp2, points.strapRightCp1, points.strapRight)
|
||||
.length()
|
||||
)
|
||||
// Seam length is now available in other parts via:
|
||||
store.get('frontArmholeLength')
|
||||
```
|
||||
|
|
|
@ -14,41 +14,59 @@ To add linebreaks to text, you merely have to include them in your text.
|
|||
When doing so, keep in mind that single-quoted strings in Javascript
|
||||
will **not** pick up linebreaks.
|
||||
|
||||
```js
|
||||
points.example1.attr('data-text', 'this\nwill\nnot\nwork')
|
||||
points.example2.attr('data-text', "this\nwill\nwork")
|
||||
points.example2.attr('data-text', `this
|
||||
will
|
||||
also
|
||||
work`)
|
||||
<Example caption="An example of whitespace in text">
|
||||
```design/src/part.mjs
|
||||
function draftPart = ({
|
||||
Point,
|
||||
points,
|
||||
Path,
|
||||
paths,
|
||||
part
|
||||
}) {
|
||||
points.demo1 = new Point(10,20)
|
||||
// highlight-start
|
||||
.addText('this\nwill\nwork')
|
||||
// highlight-end
|
||||
points.demo2 = new Point(40,20)
|
||||
// highlight-start
|
||||
.addText("this\nwill\nalso\nwork")
|
||||
// highlight-end
|
||||
points.demo3 = new Point(70,20)
|
||||
// highlight-start
|
||||
.addText(`And
|
||||
this
|
||||
will
|
||||
also
|
||||
work`).attr('data-text-lineheight', 7)
|
||||
// highlight-end
|
||||
|
||||
// Prevent clipping
|
||||
paths.diag = new Path()
|
||||
.move(new Point(0,10))
|
||||
.move(new Point(90, 70))
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
<Tip>
|
||||
|
||||
You can control the lineheight by setting the `data-text-lineheight` attribute:
|
||||
|
||||
```js
|
||||
points.example2
|
||||
.attr('data-text', "this\nwill\nwork")
|
||||
.attr('data-text-lineheight', settings.scale * 8)
|
||||
```
|
||||
|
||||
You can control the lineheight by setting the `data-text-lineheight` attribute.
|
||||
</Tip>
|
||||
|
||||
## Adding spaces to text
|
||||
## Adding consecutive spaces to text
|
||||
|
||||
Adding a single space between two words is not a problem.
|
||||
But what if you want to add a couple of spaces in a row?
|
||||
Both in HTML and SVG they will get collapsed into a single space.
|
||||
|
||||
To get around that, use ` ` for space:
|
||||
To get around that, use ` ` for space.
|
||||
|
||||
```js
|
||||
points.example.attr(
|
||||
'data-text',
|
||||
"far      apart"
|
||||
)
|
||||
```mjs
|
||||
points.demo = new Point(0, 0)
|
||||
// highlight-start
|
||||
.addText('far      apart')
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
Whether you're rendering to SVG or React, by using ` ` your spaces
|
||||
will be properly rendered in both environments.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue