Compare commits

...

11 Commits

10 changed files with 173 additions and 28 deletions

View File

@ -6,7 +6,6 @@ from api import uploads
default_pattern = { default_pattern = {
'warp': { 'warp': {
'shafts': 8, 'shafts': 8,
'threads': 100,
'threading': [{'shaft': 0}] * 100, 'threading': [{'shaft': 0}] * 100,
'defaultColour': '178,53,111', 'defaultColour': '178,53,111',
'defaultSpacing': 1, 'defaultSpacing': 1,
@ -14,7 +13,6 @@ default_pattern = {
}, },
'weft': { 'weft': {
'treadles': 8, 'treadles': 8,
'threads': 50,
'treadling': [{'treadle': 0}] * 50, 'treadling': [{'treadle': 0}] * 50,
'defaultColour': '53,69,178', 'defaultColour': '53,69,178',
'defaultSpacing': 1, 'defaultSpacing': 1,

View File

@ -62,7 +62,7 @@ def dumps(obj):
wif.append('\n[WARP]') wif.append('\n[WARP]')
wif.append('Units=centimeters') wif.append('Units=centimeters')
wif.append('Color={0}'.format(get_colour_index(obj['pattern']['colours'], obj['pattern']['warp']['defaultColour']))) wif.append('Color={0}'.format(get_colour_index(obj['pattern']['colours'], obj['pattern']['warp']['defaultColour'])))
wif.append('Threads={0}'.format(obj['pattern']['warp']['threads'])) wif.append('Threads={0}'.format(len(obj['pattern']['warp']['threading'])))
wif.append('Spacing=0.212') wif.append('Spacing=0.212')
wif.append('Thickness=0.212') wif.append('Thickness=0.212')
@ -78,7 +78,7 @@ def dumps(obj):
wif.append('\n[WEFT]') wif.append('\n[WEFT]')
wif.append('Units=centimeters') wif.append('Units=centimeters')
wif.append('Color={0}'.format(get_colour_index(obj['pattern']['colours'], obj['pattern']['weft']['defaultColour']))) wif.append('Color={0}'.format(get_colour_index(obj['pattern']['colours'], obj['pattern']['weft']['defaultColour'])))
wif.append('Threads={0}'.format(obj['pattern']['weft']['threads'])) wif.append('Threads={0}'.format(len(obj['pattern']['weft']['treadling'])))
wif.append('Spacing=0.212') wif.append('Spacing=0.212')
wif.append('Thickness=0.212') wif.append('Thickness=0.212')
@ -151,7 +151,6 @@ def loads(wif_file):
while int(x) >= len(draft['warp']['threading']) - 1: while int(x) >= len(draft['warp']['threading']) - 1:
draft['warp']['threading'].append({'shaft': 0}) draft['warp']['threading'].append({'shaft': 0})
draft['warp']['threading'][int(x) - 1] = {'shaft': shaft} draft['warp']['threading'][int(x) - 1] = {'shaft': shaft}
draft['warp']['threads'] = len(draft['warp']['threading'])
try: try:
warp_colours = config['warp colors'] warp_colours = config['warp colors']
for x in warp_colours: for x in warp_colours:
@ -180,7 +179,6 @@ def loads(wif_file):
while int(x) >= len(draft['weft']['treadling']) - 1: while int(x) >= len(draft['weft']['treadling']) - 1:
draft['weft']['treadling'].append({'treadle': 0}) draft['weft']['treadling'].append({'treadle': 0})
draft['weft']['treadling'][int(x) - 1] = {'treadle': shaft} draft['weft']['treadling'][int(x) - 1] = {'treadle': shaft}
draft['weft']['threads'] = len(draft['weft']['treadling'])
try: try:
weft_colours = config['weft colors'] weft_colours = config['weft colors']
for x in weft_colours: for x in weft_colours:

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

View File

@ -91,6 +91,26 @@ To begin, select the **colour** tool, click a colour from the **palette**, and t
As you paint, you'll notice the drawdown update to show your new colours. As you paint, you'll notice the drawdown update to show your new colours.
### Selecting and deleting threads
You can delete threads from the warp and weft.
First, enable the **select** tool from the toolbox. Once selected, you can click on individual threads, or click and drag along the warp or weft, in order to select threads.
Once you have threads selected, a button will display to allow you to delete the selected threads.
![Deleting threads](/images/docs/editing19.png)
### Inserting threads
Threads can be inserted at any point along the warp or weft.
To do so, select the **insert** tool from the toolbox and then click on the thread that you'd like to shift leftwards along the warp or downwards along the weft.
You'll be asked how many threads you'd like to insert before completing the process.
![Inserting threads](/images/docs/editing20.png)
### Configuring your pattern ### Configuring your pattern
You can rename and adjust the number of **treadles** and **shafts** your pattern uses in the **properties** menu. This information can be changed at any time. You can rename and adjust the number of **treadles** and **shafts** your pattern uses in the **properties** menu. This information can be changed at any time.

View File

@ -8,8 +8,6 @@ const StyledDrawdown = styled.canvas`
border:1px dashed rgb(70,70,70); border:1px dashed rgb(70,70,70);
top: ${props => (props.warp.shafts * props.baseSize) + 20}px; top: ${props => (props.warp.shafts * props.baseSize) + 20}px;
right: ${props => (props.weft.treadles * props.baseSize) + 20}px; right: ${props => (props.weft.treadles * props.baseSize) + 20}px;
height: ${props => props.weft.threads * props.baseSize}px;
width: ${props => props.warp.threads * props.baseSize}px;
`; `;
// Cache // Cache
@ -86,10 +84,12 @@ function Drawdown({ baseSize, warp, weft, tieups }) {
} }
}; };
const warpThreads = warp.threading?.length || 0;
const weftThreads = weft.treadling?.length || 0;
return ( return (
<StyledDrawdown ref={drawdownRef} className="drawdown joyride-drawdown" <StyledDrawdown ref={drawdownRef} className="drawdown joyride-drawdown"
width={warp.threads * baseSize} width={warpThreads * baseSize}
height={weft.threads * baseSize} height={weftThreads * baseSize}
weft={weft} warp={warp} baseSize={baseSize} weft={weft} warp={warp} baseSize={baseSize}
/> />
); );

View File

@ -40,7 +40,7 @@ function Tieups({ cellStyle, warp, weft, tieups, updatePattern, baseSize }) {
const paintTieups = () => { const paintTieups = () => {
const canvas = tieupRef.current; const canvas = tieupRef.current;
const ctx = canvas.getContext('2d');// , { alpha: false }); const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.clearRect(0, 0, canvas.width, canvas.height);

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react'; import React, { useState, useEffect } from 'react';
import { import {
Confirm, Select, Segment, Accordion, Grid, Icon, Input, Button, Popup Confirm, Header, Select, Segment, Accordion, Grid, Icon, Input, Button, Popup
} from 'semantic-ui-react'; } from 'semantic-ui-react';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
@ -40,6 +40,7 @@ function Tools({ object, pattern, warp, weft, unsaved, saving, baseSize, updateP
const [activeDrawers, setActiveDrawers] = useState(['properties', 'drawing', 'palette']); const [activeDrawers, setActiveDrawers] = useState(['properties', 'drawing', 'palette']);
const [deleteModalOpen, setDeleteModalOpen] = useState(false); const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const [newColour, setNewColour] = useState('#22194D'); const [newColour, setNewColour] = useState('#22194D');
const [selectedThreadCount, setSelectedThreadCount] = useState(0);
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useDispatch(); const dispatch = useDispatch();
const { objectId, username, projectPath } = useParams(); const { objectId, username, projectPath } = useParams();
@ -52,6 +53,15 @@ function Tools({ object, pattern, warp, weft, unsaved, saving, baseSize, updateP
return { project, editor: state.objects.editor }; return { project, editor: state.objects.editor };
}); });
useEffect(() => {
if (!pattern) return;
const { warp, weft } = pattern;
let selected = 0;
selected += warp?.threading?.filter(t => t.isSelected)?.length;
selected += weft?.treadling?.filter(t => t.isSelected)?.length;
setSelectedThreadCount(selected);
}, [pattern]);
const enableTool = (tool) => { const enableTool = (tool) => {
dispatch(actions.objects.updateEditor({ tool, colour: editor.colour })); dispatch(actions.objects.updateEditor({ tool, colour: editor.colour }));
}; };
@ -76,6 +86,27 @@ function Tools({ object, pattern, warp, weft, unsaved, saving, baseSize, updateP
updatePattern({ weft: { ...weft, treadles: parseInt(event.target.value, 10) || 1 } }); updatePattern({ weft: { ...weft, treadles: parseInt(event.target.value, 10) || 1 } });
}; };
const deleteSelectedThreads = () => {
const sure = window.confirm('Really delete the selected threads?');
if (!sure) return;
const newWarp = Object.assign({}, pattern.warp);
const newWeft = Object.assign({}, pattern.weft);
if (pattern?.warp?.threading) {
newWarp.threading = newWarp.threading.filter(t => !t.isSelected);
}
if (pattern?.weft?.treadling) {
newWeft.treadling = newWeft.treadling.filter(t => !t.isSelected);
}
updatePattern({ warp: newWarp, weft: newWeft });
}
const deselectThreads = () => {
const newWarp = Object.assign({}, pattern.warp);
const newWeft = Object.assign({}, pattern.weft);
newWarp.threading = newWarp?.threading?.map(t => ({ ...t, isSelected: undefined }));
newWeft.treadling = newWeft?.treadling?.map(t => ({ ...t, isSelected: undefined }));
updatePattern({ warp: newWarp, weft: newWeft });
}
const onZoomChange = zoom => updatePattern({ baseSize: zoom || 10 }); const onZoomChange = zoom => updatePattern({ baseSize: zoom || 10 });
const drawerIsActive = drawer => activeDrawers.indexOf(drawer) > -1; const drawerIsActive = drawer => activeDrawers.indexOf(drawer) > -1;
@ -143,8 +174,16 @@ function Tools({ object, pattern, warp, weft, unsaved, saving, baseSize, updateP
return ( return (
<div className="pattern-toolbox joyride-tools"> <div className="pattern-toolbox joyride-tools">
{unsaved && {selectedThreadCount > 0 &&
<Segment attached="top"> <Segment attached="top">
<Header>{selectedThreadCount} threads selected</Header>
<Button basic onClick={deselectThreads}>De-select all</Button>
<Button color='orange' onClick={deleteSelectedThreads}>Delete threads</Button>
</Segment>
}
{unsaved &&
<Segment attached>
<Button fluid color="teal" icon="save" content="Save pattern" onClick={() => saveObject(/*this.refs.canvas*/)} loading={saving}/> <Button fluid color="teal" icon="save" content="Save pattern" onClick={() => saveObject(/*this.refs.canvas*/)} loading={saving}/>
<Button style={{marginTop: 5}} fluid icon='refresh' content='Undo changes' onClick={revertChanges} /> <Button style={{marginTop: 5}} fluid icon='refresh' content='Undo changes' onClick={revertChanges} />
</Segment> </Segment>
@ -214,7 +253,9 @@ function Tools({ object, pattern, warp, weft, unsaved, saving, baseSize, updateP
<Accordion.Content active={drawerIsActive('drawing')}> <Accordion.Content active={drawerIsActive('drawing')}>
<Button.Group fluid> <Button.Group fluid>
<Button className='joyride-pan' data-tooltip="Pan (drag to move) pattern" color={editor.tool === 'pan' && 'blue'} size="tiny" icon onClick={() => enableTool('pan')}><Icon name="move" /></Button> <Button className='joyride-pan' data-tooltip="Pan (drag to move) pattern" color={editor.tool === 'pan' && 'blue'} size="tiny" icon onClick={() => enableTool('pan')}><Icon name="move" /></Button>
<Button className='joyride-colour' data-tooltip="Paint selected colour" color={editor.tool === 'colour' && 'blue'} size="tiny" icon onClick={() => enableTool('colour')}><Icon name="paint brush" /></Button> <Button data-tooltip="Select threads" color={editor.tool === 'select' && 'blue'} size="tiny" icon onClick={() => enableTool('select')}><Icon name="i cursor" /></Button>
<Button data-tooltip="Insert threads" color={editor.tool === 'insert' && 'blue'} size="tiny" icon onClick={() => enableTool('insert')}><Icon name="plus" /></Button>
<Button className='joyride-colour' data-tooltip="Apply thread colour" color={editor.tool === 'colour' && 'blue'} size="tiny" icon onClick={() => enableTool('colour')}><Icon name="paint brush" /></Button>
<Button className='joyride-straight' data-tooltip="Straight draw" color={editor.tool === 'straight' && 'blue'} size="tiny" icon onClick={() => enableTool('straight')}>/ /</Button> <Button className='joyride-straight' data-tooltip="Straight draw" color={editor.tool === 'straight' && 'blue'} size="tiny" icon onClick={() => enableTool('straight')}>/ /</Button>
<Button className='joyride-point' data-tooltip="Point draw" color={editor.tool === 'point' && 'blue'} size="tiny" icon onClick={() => enableTool('point')}><Icon name="chevron up" /></Button> <Button className='joyride-point' data-tooltip="Point draw" color={editor.tool === 'point' && 'blue'} size="tiny" icon onClick={() => enableTool('point')}><Icon name="chevron up" /></Button>
</Button.Group> </Button.Group>

View File

@ -8,8 +8,9 @@ const StyledWarp = styled.div`
right:0px; right:0px;
position: absolute; position: absolute;
right: ${props => (props.treadles * props.baseSize) + 20}px; right: ${props => (props.treadles * props.baseSize) + 20}px;
height: ${props => (props.shafts * props.baseSize) + 10}px; height: ${props => (props.shafts * props.baseSize) + 40}px;
width: ${props => (props.threading * props.baseSize) + 10}px; width: 100%;
cursor: ${props => props.tool === 'insert' ? 'w-resize': 'initial'};
.warp-colourway td{ .warp-colourway td{
border:none; border:none;
border-top:1px solid rgb(150,150,150); border-top:1px solid rgb(150,150,150);
@ -18,6 +19,7 @@ const StyledWarp = styled.div`
const squares = {}; const squares = {};
const markers = {}; const markers = {};
const selectedMarkers = {};
let dragging = false; let dragging = false;
let startShaft = null; let startShaft = null;
let startThread = null; let startThread = null;
@ -154,18 +156,39 @@ function Warp({ baseSize, cellStyle, warp, weft, updatePattern }) {
if (y > hY || y <= lY) yDirection = 0 - yDirection; if (y > hY || y <= lY) yDirection = 0 - yDirection;
} }
} }
if (editor.tool === 'select') {
while (x <= hX && x >= lX) {
newWarp.threading[x].isSelected = true;
x += xDirection;
}
}
updatePattern({ warp: newWarp }); updatePattern({ warp: newWarp });
} }
}; };
const click = (event) => { const click = (event) => {
const { thread, shaft } = getThreadShaft(event, warpRef.current);
if (editor.tool === 'point' || editor.tool === 'straight') { if (editor.tool === 'point' || editor.tool === 'straight') {
const { thread, shaft } = getThreadShaft(event, warpRef.current);
const newWarp = Object.assign({}, warp); const newWarp = Object.assign({}, warp);
if (thread > warp.threading.length || warp.threading.length - thread < 5) fillUpTo(newWarp, thread + 5); if (thread > warp.threading.length || warp.threading.length - thread < 5) fillUpTo(newWarp, thread + 5);
const warpThread = newWarp.threading[thread]; const warpThread = newWarp.threading[thread];
warpThread.shaft = warpThread.shaft === shaft ? 0 : shaft; warpThread.shaft = warpThread.shaft === shaft ? 0 : shaft;
updatePattern({ warp: newWarp }); updatePattern({ warp: newWarp });
} }
if (editor.tool === 'select') {
const newWarp = Object.assign({}, warp);
const warpThread = newWarp.threading[thread];
warpThread.isSelected = !warpThread.isSelected;
updatePattern({ warp: newWarp });
}
if (editor.tool === 'insert') {
const number = parseInt(prompt('Enter a number of threads to insert before this point.'));
if (number && number > 0) {
const newThreads = [...new Array(number)].map(() => ({ shaft: 0 }));
const newWarp = Object.assign({}, warp);
newWarp.threading?.splice(thread, 0, ...newThreads);
updatePattern({ warp: newWarp });
}
}
}; };
const fillUpTo = (w, limit) => { const fillUpTo = (w, limit) => {
@ -188,6 +211,22 @@ function Warp({ baseSize, cellStyle, warp, weft, updatePattern }) {
markers[size] = m_canvas; markers[size] = m_canvas;
return m_canvas; return m_canvas;
}; };
const getSelectedMarker = (size, height) => {
const m_canvas = document.createElement('canvas');
m_canvas.width = baseSize + 1;
m_canvas.height = height;
const mc = m_canvas.getContext('2d');
mc.fillStyle = 'rgb(233,245,248)';
mc.fillRect(0, 1, baseSize, height);
mc.moveTo(0, 0);
mc.lineTo(baseSize+1, 0);
mc.lineTo(baseSize+1, height);
mc.lineTo(0, height);
mc.lineTo(0, 0);
mc.strokeStyle = 'rgb(99,184,205)';
mc.stroke();
return m_canvas;
};
const getSquare = (size, colour) => { const getSquare = (size, colour) => {
if (squares[size] && squares[size][colour]) return squares[size][colour]; if (squares[size] && squares[size][colour]) return squares[size][colour];
@ -221,9 +260,14 @@ function Warp({ baseSize, cellStyle, warp, weft, updatePattern }) {
ctx.strokeStyle = 'rgba(0,0,0,0.3)'; ctx.strokeStyle = 'rgba(0,0,0,0.3)';
ctx.stroke(); ctx.stroke();
const selectedMarker = getSelectedMarker(baseSize, canvas.height);
const marker = getMarker(baseSize);
for (let thread = 0; thread < warp.threading.length; thread++) { for (let thread = 0; thread < warp.threading.length; thread++) {
const shaft = warp.threading[thread].shaft; const shaft = warp.threading[thread].shaft;
const marker = getMarker(baseSize); const isSelected = warp.threading[thread].isSelected;
if (isSelected) {
ctx.drawImage(selectedMarker, canvas.width - ((thread + 1) * baseSize), 0);
}
ctx.drawImage(marker, canvas.width - ((thread + 1) * baseSize), canvas.height - (shaft * baseSize)); ctx.drawImage(marker, canvas.width - ((thread + 1) * baseSize), canvas.height - (shaft * baseSize));
const colourSquare = getSquare(baseSize, warp.threading[thread].colour || warp.defaultColour); const colourSquare = getSquare(baseSize, warp.threading[thread].colour || warp.defaultColour);
ctx2.drawImage(colourSquare, canvas.width - ((thread + 1) * baseSize), 0); ctx2.drawImage(colourSquare, canvas.width - ((thread + 1) * baseSize), 0);
@ -231,7 +275,7 @@ function Warp({ baseSize, cellStyle, warp, weft, updatePattern }) {
}; };
return ( return (
<StyledWarp treadles={weft.treadles} shafts={warp.shafts} baseSize={baseSize}> <StyledWarp treadles={weft.treadles} shafts={warp.shafts} baseSize={baseSize} tool={tool}>
<canvas className='warp-colourway joyride-warpColourway' ref={colourwayRef} width={warp.threading.length * baseSize} height={10} <canvas className='warp-colourway joyride-warpColourway' ref={colourwayRef} width={warp.threading.length * baseSize} height={10}
style={{ style={{
position: 'absolute', top: 0, right: 0, height: 10, width: warp.threading.length * baseSize, position: 'absolute', top: 0, right: 0, height: 10, width: warp.threading.length * baseSize,

View File

@ -12,6 +12,7 @@ const StyledWeft = styled.div`
min-height: 1000px; min-height: 1000px;
width: ${props => (props.treadles * props.baseSize)}px; width: ${props => (props.treadles * props.baseSize)}px;
height: ${props => props.threads * props.baseSize}px; height: ${props => props.threads * props.baseSize}px;
cursor: ${props => props.tool === 'insert' ? 's-resize': 'initial'};
.weft-colourway{ .weft-colourway{
border:none; border:none;
border-right:1px solid rgb(150,150,150); border-right:1px solid rgb(150,150,150);
@ -157,12 +158,18 @@ function Weft({ cellStyle, warp, weft, baseSize, updatePattern }) {
if (x > hX || x <= lX) xDirection = 0 - xDirection; if (x > hX || x <= lX) xDirection = 0 - xDirection;
} }
} }
if (editor.tool === 'select') {
while (y <= hY && y >= lY) {
newWeft.treadling[y - 1].isSelected = true;
y += yDirection;
}
}
updatePattern({ weft: newWeft }); updatePattern({ weft: newWeft });
} }
}; };
const click = (event) => { const click = (event) => {
let { thread, treadle } = getThreadTreadle(event, weftRef.current);
if (editor.tool === 'point' || editor.tool === 'straight') { if (editor.tool === 'point' || editor.tool === 'straight') {
let { thread, treadle } = getThreadTreadle(event, weftRef.current);
treadle += 1; treadle += 1;
const newWeft = Object.assign({}, weft); const newWeft = Object.assign({}, weft);
if (thread >= newWeft.treadling.length || newWeft.treadling.length - thread < 5) fillUpTo(newWeft, thread + 5); if (thread >= newWeft.treadling.length || newWeft.treadling.length - thread < 5) fillUpTo(newWeft, thread + 5);
@ -170,6 +177,21 @@ function Weft({ cellStyle, warp, weft, baseSize, updatePattern }) {
weftThread.treadle = weftThread.treadle === treadle ? 0 : treadle; weftThread.treadle = weftThread.treadle === treadle ? 0 : treadle;
updatePattern({ weft: newWeft }); updatePattern({ weft: newWeft });
} }
if (editor.tool === 'select') {
const newWeft = Object.assign({}, weft);
const weftThread = newWeft.treadling[thread - 1];
weftThread.isSelected = !weftThread.isSelected;
updatePattern({ weft: newWeft });
}
if (editor.tool === 'insert') {
const number = parseInt(prompt('Enter a number of threads to insert above this point.'));
if (number && number > 0) {
const newThreads = [...new Array(number)].map(() => ({ treadle: 0 }));
const newWeft = Object.assign({}, weft);
newWeft.treadling?.splice(thread - 1, 0, ...newThreads);
updatePattern({ weft: newWeft });
}
}
}; };
const fillUpTo = (weft, limit) => { const fillUpTo = (weft, limit) => {
@ -192,6 +214,22 @@ function Weft({ cellStyle, warp, weft, baseSize, updatePattern }) {
markers[size] = m_canvas; markers[size] = m_canvas;
return m_canvas; return m_canvas;
}; };
const getSelectedMarker = (size, width) => {
const m_canvas = document.createElement('canvas');
m_canvas.width = width + 1;
m_canvas.height = baseSize;
const mc = m_canvas.getContext('2d');
mc.fillStyle = 'rgb(233,245,248)';
mc.fillRect(0, 1, width, baseSize);
mc.moveTo(0, 0);
mc.lineTo(width+1, 0);
mc.lineTo(width+1, baseSize);
mc.lineTo(0, baseSize);
mc.lineTo(0, 0);
mc.strokeStyle = 'rgb(99,184,205)';
mc.stroke();
return m_canvas;
};
const getSquare = (size, colour) => { const getSquare = (size, colour) => {
if (squares[size] && squares[size][colour]) return squares[size][colour]; if (squares[size] && squares[size][colour]) return squares[size][colour];
@ -225,29 +263,35 @@ function Weft({ cellStyle, warp, weft, baseSize, updatePattern }) {
ctx.strokeStyle = 'rgba(0,0,0,0.3)'; ctx.strokeStyle = 'rgba(0,0,0,0.3)';
ctx.stroke(); ctx.stroke();
for (let thread = 0; thread < weft.threads; thread++) { const marker = getMarker(baseSize);
const selectedMarker = getSelectedMarker(baseSize, canvas.width);
for (let thread = 0; thread < weft.treadling.length; thread++) {
const treadle = weft.treadling[thread].treadle; const treadle = weft.treadling[thread].treadle;
const marker = getMarker(baseSize); const isSelected = weft.treadling[thread].isSelected;
if (isSelected) {
ctx.drawImage(selectedMarker, 0, ((thread) * baseSize));
}
ctx.drawImage(marker, ((treadle - 1) * baseSize), ((thread) * baseSize)); ctx.drawImage(marker, ((treadle - 1) * baseSize), ((thread) * baseSize));
const colourSquare = getSquare(baseSize, weft.treadling[thread].colour || weft.defaultColour); const colourSquare = getSquare(baseSize, weft.treadling[thread].colour || weft.defaultColour);
ctx2.drawImage(colourSquare, 0, (thread * baseSize)); ctx2.drawImage(colourSquare, 0, (thread * baseSize));
} }
} }
const threadCount = weft.treadling?.length || 0;
return ( return (
<StyledWeft baseSize={baseSize} treadles={weft.treadles} shafts={warp.shafts} threads={weft.threads}> <StyledWeft baseSize={baseSize} treadles={weft.treadles} shafts={warp.shafts} threads={threadCount} tool={tool}>
<canvas className='weft-colourway' ref={colourwayRef} width={10} height={weft.threads * baseSize} <canvas className='weft-colourway' ref={colourwayRef} width={10} height={threadCount * baseSize}
style={{ position: 'absolute', top: 0, right: 0, width: 10, height: weft.threads * baseSize}} style={{ position: 'absolute', top: 0, right: 0, width: 10, height: threadCount * baseSize}}
onClick={mouseClickColourway} onClick={mouseClickColourway}
onMouseDown={mouseDownColourway} onMouseDown={mouseDownColourway}
onMouseMove={mouseMoveColourway} onMouseMove={mouseMoveColourway}
onMouseUp={mouseUpColourway} onMouseUp={mouseUpColourway}
onMouseLeave={mouseUpColourway} onMouseLeave={mouseUpColourway}
/> />
<canvas className='weft-threads joyride-weft' ref={weftRef} width={weft.treadles * baseSize} height={weft.threads * baseSize} <canvas className='weft-threads joyride-weft' ref={weftRef} width={weft.treadles * baseSize} height={threadCount * baseSize}
style={{ style={{
position: 'absolute', position: 'absolute',
top: 0, right: 10, height: weft.threads * baseSize, width: weft.treadles * baseSize, top: 0, right: 10, height: threadCount * baseSize, width: weft.treadles * baseSize,
borderRadius: 4, boxShadow: '0px 0px 10px rgba(0,0,0,0.15)', borderRadius: 4, boxShadow: '0px 0px 10px rgba(0,0,0,0.15)',
}} }}
onClick={click} onClick={click}