Skip to content

Commit

Permalink
Polygon tool (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
edemaine committed Aug 9, 2023
1 parent 5dddff2 commit 69cc78a
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 27 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ instead of version numbers.

## 2023-08-09

* Fix PDF export of LaTeX text and arrows
* New polygonal line tool!
[[#35](https://github.com/edemaine/cocreate/issues/35)]
* Reduce zoom speed via <kbd>Ctrl</kbd> + mouse wheel by 4x
* Fix PDF export of LaTeX text and arrows

## 2023-05-01

Expand Down
3 changes: 2 additions & 1 deletion client/DrawApp.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ export DrawAppRoom = ->
onCleanup dom.listen window,
keydown: (e) ->
return if e.target.classList.contains 'modal'
return if tools[currentTool()].key? e
switch e.key
when 'z', 'Z'
if e.ctrlKey or e.metaKey
Expand Down Expand Up @@ -487,7 +488,7 @@ export DrawAppRoom = ->
</filter>
{### Filter+ from Dark Reader, https://github.com/darkreader/darkreader/blob/7f047b20909b09b8cdb3e45550d0c586abeb98a4/src/generators/utils/matrix.ts#L42 ###}
<filter id="invertFilter" x="0" y="0" width="999999" height="999999"
style="color-interpolation-filters: srgb">
style={"color-interpolation-filters": "srgb"}>
<feColorMatrix type="matrix"
values="0.33333 -0.66667 -0.66667 0 1 -0.66667 0.33333 -0.66667 0 1 -0.66667 -0.66667 0.33333 0 1 0 0 0 1 0"/>
</filter>
Expand Down
13 changes: 7 additions & 6 deletions client/Page.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,13 @@ export class Page
options.start = old.pts.length
else
## For other types such as `poly`, `rect`, `ellipse`, do a diff
for start in [0...old.pts.length]
oldPt = old.pts[start]
newPt = obj.pts[start]
if oldPt.x != newPt.x or oldPt.y != newPt.y or oldPt.w != newPt.w
break
options.start = start
if old.pts.length == obj.pts.length
for start in [0...old.pts.length]
oldPt = old.pts[start]
newPt = obj.pts[start]
if oldPt.x != newPt.x or oldPt.y != newPt.y or oldPt.w != newPt.w
break
options.start = start
for own key of obj when key not of noDiff
options[key] = obj[key] != old[key]
@render.render obj, options
Expand Down
3 changes: 2 additions & 1 deletion client/RenderObjects.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ export class RenderObjects
'stroke-dasharray': scaleDash obj.dash, obj.width
'stroke-linecap': 'round'
'stroke-linejoin': 'round'
fill: 'none'
fill: obj.fill or 'none'
'fill-opacity': obj.opacity
'marker-start': if obj.arrowStart then arrow
'marker-end': if obj.arrowEnd then arrow
poly
Expand Down
2 changes: 1 addition & 1 deletion client/Selection.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export class Selection
when 'width'
continue unless obj.type in ['pen', 'poly', 'rect', 'ellipse']
when 'fill'
continue unless obj.type in ['rect', 'ellipse']
continue unless obj.type in ['poly', 'rect', 'ellipse']
when 'color'
continue unless obj.type in ['pen', 'poly', 'rect', 'ellipse', 'text']
when 'arrowStart', 'arrowEnd'
Expand Down
2 changes: 2 additions & 0 deletions client/lib/icons.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ export icons =
'<path d="M424,0h-97.9H320h-32H88C74.7,0,64,10.7,64,24v159v305c0,13.3,10.7,24,24,24h336c13.3,0,24-10.7,24-24V183v-23v-32v-6.1V24C448,10.7,437.3,0,424,0zM364.5,377.4L268,473.1c-6.7,6.6-17.4,6.6-24,0l-96.4-95.7c-10.2-10.1-3-27.4,11.3-27.4H224v-80c0-8.8,7.2-16,16-16h32c8.8,0,16,7.2,16,16v80h65.2C367.5,350,374.6,367.3,364.5,377.4zM192,101h-38.3V88.2c0-6-0.5-9.8-1.5-11.4c-1-1.6-2.6-2.5-4.9-2.5c-2.5,0-4.4,1.1-5.6,3.3c-1.3,2.2-1.9,5.6-1.9,10.1c0,5.8,0.7,10.1,2.1,13.1c1.4,2.9,5.2,6.5,11.6,10.6c18.3,11.9,29.9,21.7,34.7,29.3c4.8,7.6,7.1,19.9,7.1,36.9c0,12.3-1.3,21.4-4,27.3c-2.6,5.8-7.7,10.7-15.3,14.7c-7.6,4-16.4,5.9-26.4,5.9c-11,0-20.4-2.3-28.2-6.8c-7.8-4.6-12.9-10.4-15.3-17.4c-2.4-7.1-3.6-17.1-3.6-30v-11.3h38.3v21.1c0,6.5,0.5,10.7,1.6,12.5c1.1,1.9,3,2.8,5.7,2.8c2.7,0,4.8-1.2,6.1-3.5c1.3-2.4,2-5.8,2-10.5c0-10.2-1.3-16.9-3.8-20c-2.6-3.1-9-8.4-19.3-15.7c-10.2-7.4-17-12.8-20.4-16.1c-3.3-3.4-6.1-8-8.3-13.9c-2.2-5.9-3.3-13.5-3.3-22.7c0-13.3,1.5-23,4.6-29.1c3.1-6.1,8.1-10.9,15-14.4c6.9-3.5,15.3-5.2,25.1-5.2c10.7,0,19.8,1.9,27.4,5.7c7.5,3.8,12.5,8.5,15,14.3c2.4,5.7,3.7,15.5,3.7,29.2V101zM306.3,48.6l-21,173.1h-62.6L198.9,48.6h43.5c5.1,47.7,8.7,88,10.8,121c2.1-33.4,4.4-63,6.8-88.9l2.9-32.2H306.3zM407.8,112.3h-41.2V96.6c0-9.9-0.4-16.1-1.2-18.6c-0.8-2.5-2.6-3.7-5.6-3.7c-2.5,0-4.3,1.1-5.2,3.2c-0.9,2.1-1.4,7.6-1.4,16.5V177c0,7.8,0.5,12.9,1.4,15.3c0.9,2.5,2.7,3.7,5.5,3.7c3,0,5-1.4,6.1-4.2c1.1-2.8,1.6-8.2,1.6-16.3v-20.5h-8.3v-26.3h48.3v92.9h-25.9l-3.8-12.4c-2.8,5.3-6.4,9.4-10.6,12c-4.3,2.7-9.3,4-15.1,4c-6.9,0-13.4-1.8-19.4-5.5c-6-3.7-10.6-8.2-13.8-13.6c-3.1-5.4-5.1-11.1-5.9-17.1c-0.8-6-1.2-14.9-1.2-26.8v-51.4c0-16.5,0.8-28.5,2.4-36c1.6-7.5,6.3-14.3,14-20.6c7.7-6.2,17.7-9.4,30-9.4c12.1,0,22.1,2.7,30,8.1c8,5.4,13.1,11.9,15.6,19.3c2.4,7.4,3.6,18.3,3.6,32.5V112.3z"/>'
'download-pdf': # like download-svg but with "PDF" text
'<path d="M424,0h-97.9H320h-32H88C74.7,0,64,10.7,64,24v159v305c0,13.3,10.7,24,24,24h336c13.3,0,24-10.7,24-24V183v-23v-32v-6.1V24C448,10.7,437.3,0,424,0z M364.5,377.4L268,473.1c-6.7,6.6-17.4,6.6-24,0l-96.4-95.7c-10.2-10.1-3-27.4,11.3-27.4H224v-80c0-8.8,7.2-16,16-16h32c8.8,0,16,7.2,16,16v80h65.2C367.5,350,374.6,367.3,364.5,377.4z M118.7,48.6h41.5c11.2,0,19.9,1,25.9,2.9c6,1.9,10.6,4.7,13.6,8.3c3,3.6,5.1,8,6.2,13.2c1.1,5.2,1.6,13.2,1.6,24v15.1c0,11.1-1,19.1-3.1,24.2c-2.1,5.1-5.9,8.9-11.5,11.7c-5.6,2.7-12.9,4.1-21.9,4.1h-11.1v69.7h-41.2V48.6z M159.9,78.2v44.1c1.2,0.1,2.2,0.1,3,0.1c3.8,0,6.4-1,7.9-3c1.5-2,2.2-6.3,2.2-12.7V92.4c0-5.9-0.8-9.8-2.5-11.5C168.7,79.1,165.2,78.2,159.9,78.2z M219.3,48.6h30.8c19.9,0,33.4,1,40.4,3c7,2,12.3,5.3,16,9.8c3.7,4.6,5.9,9.6,6.9,15.2c0.9,5.6,1.4,16.6,1.4,33v60.6c0,15.5-0.7,25.9-2,31.2c-1.3,5.2-3.7,9.3-7,12.3c-3.3,3-7.4,5-12.3,6.2c-4.9,1.2-12.3,1.8-22.1,1.8h-52V48.6z M260.5,78.2v113.9c5.9,0,9.6-1.3,11-3.9c1.4-2.6,2.1-9.7,2.1-21.2V99.7c0-7.8-0.2-12.9-0.7-15.1c-0.5-2.2-1.5-3.8-3.1-4.9C268,78.7,265,78.2,260.5,78.2z M330.1,48.6h69.8v34.6h-28.6v32.8h25.4V149h-25.4v72.7h-41.2V48.6z"/>'
'draw-polygon':
'<path d="M128,151.4v209.2c9.7,5.6,17.8,13.7,23.4,23.4h209.2c0-0.1,0.1-0.2,0.1-0.3l-4.5-7.9l-32-56l0,0c-1.4,0.1-2.8,0.1-4.2,0.1c-35.3,0-64-28.7-64-64s28.7-64,64-64c1.4,0,2.8,0,4.2,0.1l0,0l32-56l4.5-7.9l-0.1-0.3H151.4c-5.6,9.7-13.7,17.8-23.4,23.4V151.4zM416.3,352c35.2,0.2,63.7,28.7,63.7,64s-28.7,64-64,64c-23.7,0-44.4-12.9-55.4-32H151.4c-11.1,19.1-31.7,32-55.4,32c-35.3,0-64-28.7-64-64c0-23.7,12.9-44.4,32-55.4V151.4c-19.1-11-32-31.7-32-55.4c0-35.3,28.7-64,64-64c23.7,0,44.4,12.9,55.4,32h209.2c11.1-19.1,31.7-32,55.4-32c35.3,0,64,28.7,64,64s-28.5,63.8-63.7,64l-4.5,7.9l-32,56l-2.3,4c4.2,8.5,6.5,18,6.5,28.1s-2.3,19.6-6.5,28.1l2.3,4l32,56L416.3,352z"/>'
ellipse: # edited rect below
'<path d="M256,468c-67.1,0-130.5-21.2-178.4-59.8c-24-19.3-42.9-41.9-56.3-67.3C7.2,314.1,0,285.5,0,256s7.2-58.1,21.3-85c13.3-25.3,32.3-48,56.3-67.3C125.5,65.2,188.9,44,256,44c67.1,0,130.5,21.2,178.4,59.8c24,19.3,42.9,41.9,56.3,67.3c14.1,26.8,21.3,55.4,21.3,85s-7.2,58.1-21.3,85c-13.3,25.3-32.3,48-56.3,67.3C386.5,446.8,323.1,468,256,468zM256,108c-52.6,0-101.7,16.2-138.3,45.7C83.1,181.5,64,217.8,64,256s19.1,74.5,53.7,102.3C154.3,387.8,203.4,404,256,404c52.6,0,101.7-16.2,138.3-45.7C428.9,330.5,448,294.2,448,256s-19.1-74.5-53.7-102.3C357.7,124.2,308.6,108,256,108z"/>'
'ellipse-fill': # center of above
Expand Down
5 changes: 4 additions & 1 deletion client/tools/history.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,10 @@ defineTool
switch key
when 'pts'
for subkey, subvalue of value
obj[key][subkey] = subvalue
if subvalue?
obj[key][subkey] = subvalue
else
obj[key].splice subkey, 1
else
obj[key] = value
toRender.add obj.id
Expand Down
110 changes: 107 additions & 3 deletions client/tools/modes.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -538,9 +538,7 @@ rectLikeTool = (type, fillable, constrain) ->
pointers[e.pointerId].alt = e.altKey
return if JSON.stringify(last) == JSON.stringify(pts)
pointers[e.pointerId].last = pts
edit
id: id
pts: pts
edit {id, pts}

defineTool Object.assign rectLikeTool('poly', false, orthogonalPoint),
name: 'segment'
Expand Down Expand Up @@ -568,6 +566,112 @@ defineTool Object.assign rectLikeTool('ellipse', true, equalXYPoint),
help: <>Draw axis-aligned ellipsis inside rectangle between endpoints (drag). Hold <kbd>Shift</kbd> to constrain to circle, <kbd>{Alt}</kbd> to center at first point. Click without dragging to center a circular dot proportional to line width.</>
hotkey: 'o'

defineTool
name: 'poly'
category: 'mode'
icon: 'draw-polygon'
hotspot: [0.1875, 0.83]
hotkey: ['P', 'g']
help: <>Draw polygonal line by clicking successive points. Right click or double click last point; or type <kbd>Escape</kbd> or switch modes to finish. <kbd>Backspace</kbd>/<kbd>Delete</kbd> removes last vertex. Hold <kbd>Shift</kbd> to constrain to horizontal/vertical.</>
stop: ->
return unless pointers.active?
## Remove last vertex by simulating Escape key
@key key: 'Escape'
return unless pointers.active?
@finish()
finish: (del) ->
## Finish and optionally delete current poly
return unless pointers.active?
{id, prev, last, edit} = pointers.active
if JSON.stringify(prev) == JSON.stringify(last) # duplicate last vertex
edit
id: id
pts:
"#{pointers.active.index}": null
edit.flush()
obj = Objects.findOne id
if del or obj.pts.length == 1
Meteor.call 'objectDel', id
else
undoStack.push
type: 'new'
obj: obj
delete pointers.active
key: (e) ->
return unless pointers.active?
return unless e.key in ['Delete', 'Backspace', 'Escape']
{id, index, last, edit} = pointers.active
## If we hit Escape or Delete/Backspace and we've only clicked one point,
## delete the object.
del = index <= 1
unless del
if e.key == 'Escape'
## If we hit Escape, pop the last vertex.
edit
id: id
pts:
"#{index}": null
else
## If we hit Delete/Backspace, pop the previous vertex.
pointers.active.prev = Objects.findOne(id).pts[index-2]
edit
id: id
pts:
"#{index-1}": last
"#{index}": null
pointers.active.index--
@finish del if del or e.key == 'Escape'
true
down: (e) ->
pt = maybeSnapPointToGrid currentBoard().eventToPoint e
if pointers.active? # new point in existing poly
{last, prev, edit} = pointers.active
pt = orthogonalPoint pt, e, prev
unless (same = (JSON.stringify(pt) == JSON.stringify(last)))
edit
id: pointers.active.id
pts: "#{pointers.active.index}": pt
if (dupe = (JSON.stringify(prev) == JSON.stringify(pt)))
## Avoid duplicate vertex
pointers.active.last = pt
else
pointers.active.prev = pt
pointers.active.index++
pointers.active.last = null # haven't sent new point yet
## Right click or double click to finish
@finish() if e.button == 2 or (dupe and (same or not last?))
else # new poly
object =
room: currentRoom().id
page: currentPage().id
type: 'poly'
pts: [pt]
color: currentColor()
width: currentWidth()
object.dash = currentDash() if currentDash()
object.fill = currentFill() if currentFillOn()
object.opacity = currentOpacity() if currentOpacityOn()
object.arrowStart = currentArrowStart() if currentArrowStart()
object.arrowEnd = currentArrowEnd() if currentArrowEnd()
pointers.active =
origin: pt # TODO: snap to close polygon
prev: pt # previous fixed vertex
last: null # last sent coordinates for current vertex
index: 1 # current vertex index in pts array
id: Meteor.apply 'objectNew', [object], returnStubValue: true
edit: throttle.method 'objectEdit', ([edit1], [edit2]) ->
edit2.pts = Object.assign {}, edit1.pts, edit2.pts
[edit2]
move: (e) ->
return unless pointers.active?
{id, index, last, prev, edit} = pointers.active
pt = maybeSnapPointToGrid currentBoard().eventToPoint e
pt = orthogonalPoint pt, e, prev
return if JSON.stringify(pt) == JSON.stringify(last)
pts = "#{index}": pt
edit {id, pts}
pointers.active.last = pt

defineTool
name: 'eraser'
category: 'mode'
Expand Down
1 change: 1 addition & 0 deletions client/tools/tools.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export drawingTools =
segment: true
rect: true
ellipse: true
poly: true
text: true
export historyTools =
pan: true
Expand Down
50 changes: 39 additions & 11 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,9 @@ geometry of existing drawn objects. Specifically, you can drag the points
that define a
[<img src="icons/segment.svg" width="18" alt="Segment Icon"> Segment](#-segment-tool),
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangle](#-rectangle-tool),
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipse](#-ellipse-tool),
or
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipse](#-ellipse-tool).
[<img src="icons/draw-polygon.svg" width="18" alt="Polygon Icon"> Polygon](#-polygon-tool).

Switching to this mode displays small squares at all the draggable points,
called "anchors".
Expand Down Expand Up @@ -351,6 +352,24 @@ You can use both modifiers at once to draw a circle centered at a point,
and you can play with these toggles while you're drawing an ellipse.
(This behavior matches Adobe Illustrator.)

### <img src="icons/polygon.svg" width="18" alt="Polygon Icon"> Polygon Tool

The Polygon Tool is a drawing mode that lets you draw polygonal lines
(open or closed).
Click/tap successive points.
To finish your polygon (e.g. to start a new one), you have several options:

* Right click the final point
* Double click the final point (easiest to achieve in grid snapping mode)
* Type <kbd>Escape</kbd> (which removes the floating point of the cursor)
* Switch drawing modes (which also removes the floating point of the cursor)

You can also type <kbd>Backscape</kbd> or <kbd>Delete</kbd> to undo the
last clicked point, in case you make a mistake.

If you hold <kbd>Shift</kbd>, then
the current line segment will be constrained to be horizontal or vertical.

### <img src="icons/eraser.svg" width="18" alt="Erase Icon"> Erase Tool

The Erase Tool is a drawing mode that erases/deletes previously drawn objects.
Expand Down Expand Up @@ -584,8 +603,10 @@ or
[<img src="icons/grid-tri.svg" width="18" alt="Triangular Grid Icon"> Triangular Grid Toggle](#-triangular-grid-toggle).
(Even if the grid is invisible, the last chosen grid defines the snapping behavior.)
[<img src="icons/segment.svg" width="18" alt="Segment Icon"> Segments](#-segment-tool),
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool), and
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool)
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool),
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool),
and
[<img src="icons/draw-polygon.svg" width="18" alt="Polygon Icon"> Polygons](#-polygon-tool)
will have their defining points rounded to the nearest grid point.
The [<img src="icons/pencil-alt.svg" width="18" alt="Pen Icon"> Pen Tool](#-pen-tool)
is unaffected by grid snapping.
Expand Down Expand Up @@ -838,7 +859,9 @@ These buttons control the outline/stroke width of objects with an outline:
[<img src="icons/pencil-alt.svg" width="18" alt="Pen Icon"> Pen](#-pen-tool),
[<img src="icons/segment.svg" width="18" alt="Segment Icon"> Segments](#-segment-tool),
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool),
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool).
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool),
and
[<img src="icons/draw-polygon.svg" width="18" alt="Polygon Icon"> Polygons](#-polygon-tool).
Currently, you have seven integral choices.

### Font Size
Expand All @@ -858,7 +881,9 @@ These buttons control the outline/stroke style of objects with an outline:
[<img src="icons/pencil-alt.svg" width="18" alt="Pen Icon"> Pen](#-pen-tool),
[<img src="icons/segment.svg" width="18" alt="Segment Icon"> Segments](#-segment-tool),
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool),
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool).
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool),
and
[<img src="icons/draw-polygon.svg" width="18" alt="Polygon Icon"> Polygons](#-polygon-tool).
Currently, you have four choices: solid, dotted, dashed, and dot-dashed.

### <img src="icons/arrow-start.svg" width="18" alt="Start-Arrow Icon"> <img src="icons/arrow-end.svg" width="18" alt="End-Arrow Icon"> Arrow Toggles
Expand All @@ -881,9 +906,10 @@ Click/tap the button to switch between the normal fully opaque mode
In partially transparent/opaque mode, three additional buttons will display
for selecting among 25%, 50%, or 75% opacity.
This setting will affect both stroke and fill opacity for fillable objects:
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool)
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool),
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool),
and
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool).
[<img src="icons/draw-polygon.svg" width="18" alt="Polygon Icon"> Polygons](#-polygon-tool).

Currently,
[<img src="icons/pencil-alt.svg" width="18" alt="Pen Icon"> Pen](#-pen-tool)
Expand All @@ -902,9 +928,10 @@ set by <kbd>Shift</kbd>-clicking on a color in the
[Color Palette](#color-palette).

This toggle only affects objects that support fill:
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool)
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool),
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool),
and
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool).
[<img src="icons/draw-polygon.svg" width="18" alt="Polygon Icon"> Polygons](#-polygon-tool).

### Color Palette

Expand All @@ -913,9 +940,10 @@ These buttons normally control the **outline/stroke** color of objects.

If you hold down <kbd>Shift</kbd> on your keyboard when choosing a color,
you control the **fill** color of objects that support fill:
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool)
[<img src="icons/rect.svg" width="18" alt="Rectangle Icon"> Rectangles](#-rectangle-tool),
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool),
and
[<img src="icons/ellipse.svg" width="18" alt="Ellipse Icon"> Ellipses](#-ellipse-tool).
[<img src="icons/draw-polygon.svg" width="18" alt="Polygon Icon"> Polygons](#-polygon-tool).
When you choose a fill color, you automatically turn on
[<img src="icons/tint.svg" width="18" alt="Fill Icon"> Fill](#-fill---no-fill-toggle).

Expand Down
5 changes: 5 additions & 0 deletions doc/icons/draw-polygon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 69cc78a

Please sign in to comment.