Selaa lähdekoodia

Adds zoom controls

main
Steve Ruiz 4 vuotta sitten
vanhempi
commit
09659ab9ba

+ 17
- 24
components/canvas/shape.tsx Näytä tiedosto

43
           strokeWidth={+shape.style.strokeWidth + 8}
43
           strokeWidth={+shape.style.strokeWidth + 8}
44
         />
44
         />
45
       )}
45
       )}
46
-      <StyledShape id={id} style={shape.style} />
47
-      {/* 
48
-      <text
49
-        y={4}
50
-        x={4}
51
-        fontSize={18}
52
-        fill="black"
53
-        stroke="none"
54
-        alignmentBaseline="text-before-edge"
55
-        pointerEvents="none"
56
-      >
57
-        {center.toString()}
58
-      </text> */}
46
+      {!shape.isHidden && <StyledShape id={id} style={shape.style} />}
59
     </StyledGroup>
47
     </StyledGroup>
60
   )
48
   )
61
 }
49
 }
62
 
50
 
63
 const StyledShape = memo(
51
 const StyledShape = memo(
64
   ({ id, style }: { id: string; style: ShapeStyles }) => {
52
   ({ id, style }: { id: string; style: ShapeStyles }) => {
65
-    return (
66
-      <MainShape
67
-        as="use"
68
-        href={'#' + id}
69
-        {...style}
70
-        // css={{ zStrokeWidth: Number(style.strokeWidth) }}
71
-      />
72
-    )
53
+    return <use href={'#' + id} {...style} />
73
   }
54
   }
74
 )
55
 )
75
 
56
 
76
-const MainShape = styled('use', {
77
-  // zStrokeWidth: 1,
78
-})
57
+function Label({ text }: { text: string }) {
58
+  return (
59
+    <text
60
+      y={4}
61
+      x={4}
62
+      fontSize={18}
63
+      fill="black"
64
+      stroke="none"
65
+      alignmentBaseline="text-before-edge"
66
+      pointerEvents="none"
67
+    >
68
+      {text}
69
+    </text>
70
+  )
71
+}
79
 
72
 
80
 const HoverIndicator = styled('path', {
73
 const HoverIndicator = styled('path', {
81
   fill: 'none',
74
   fill: 'none',

+ 1
- 4
components/style-panel/color-picker.tsx Näytä tiedosto

29
 
29
 
30
 function ColorIcon({ color }: { color: string }) {
30
 function ColorIcon({ color }: { color: string }) {
31
   return (
31
   return (
32
-    <Square
33
-      fill={color}
34
-      strokeDasharray={color === 'transparent' ? '2, 3' : 'none'}
35
-    />
32
+    <Square fill={color} strokeDasharray={color === 'none' ? '2, 3' : 'none'} />
36
   )
33
   )
37
 }
34
 }
38
 
35
 

+ 6
- 6
components/style-panel/style-panel.tsx Näytä tiedosto

145
           >
145
           >
146
             <RotateCounterClockwiseIcon />
146
             <RotateCounterClockwiseIcon />
147
           </IconButton>
147
           </IconButton>
148
-          <IconButton
149
-            disabled={!hasSelection}
150
-            onClick={() => state.send('DELETED')}
151
-          >
152
-            <TrashIcon />
153
-          </IconButton>
154
           <IconButton
148
           <IconButton
155
             disabled={!hasSelection}
149
             disabled={!hasSelection}
156
             onClick={() => state.send('TOGGLED_SHAPE_HIDE')}
150
             onClick={() => state.send('TOGGLED_SHAPE_HIDE')}
169
           >
163
           >
170
             {isAllAspectLocked ? <AspectRatioIcon /> : <BoxIcon />}
164
             {isAllAspectLocked ? <AspectRatioIcon /> : <BoxIcon />}
171
           </IconButton>
165
           </IconButton>
166
+          <IconButton
167
+            disabled={!hasSelection}
168
+            onClick={() => state.send('DELETED')}
169
+          >
170
+            <TrashIcon />
171
+          </IconButton>
172
         </ButtonsRow>
172
         </ButtonsRow>
173
       </Content>
173
       </Content>
174
     </Panel.Layout>
174
     </Panel.Layout>

+ 5
- 0
components/tools-panel/tools-panel.tsx Näytä tiedosto

16
 import state, { useSelector } from 'state'
16
 import state, { useSelector } from 'state'
17
 import styled from 'styles'
17
 import styled from 'styles'
18
 import { ShapeType } from 'types'
18
 import { ShapeType } from 'types'
19
+import Zoom from './zoom'
19
 
20
 
20
 const selectSelectTool = () => state.send('SELECTED_SELECT_TOOL')
21
 const selectSelectTool = () => state.send('SELECTED_SELECT_TOOL')
21
 const selectDrawTool = () => state.send('SELECTED_DRAW_TOOL')
22
 const selectDrawTool = () => state.send('SELECTED_DRAW_TOOL')
49
 
50
 
50
   return (
51
   return (
51
     <OuterContainer>
52
     <OuterContainer>
53
+      <Zoom />
52
       <Container>
54
       <Container>
53
         <IconButton
55
         <IconButton
54
           name="select"
56
           name="select"
131
   )
133
   )
132
 }
134
 }
133
 
135
 
136
+const Spacer = styled('div', { flexGrow: 2 })
137
+
134
 const OuterContainer = styled('div', {
138
 const OuterContainer = styled('div', {
139
+  position: 'relative',
135
   gridArea: 'tools',
140
   gridArea: 'tools',
136
   padding: '0 8px 12px 8px',
141
   padding: '0 8px 12px 8px',
137
   height: '100%',
142
   height: '100%',

+ 59
- 0
components/tools-panel/zoom.tsx Näytä tiedosto

1
+import { ZoomInIcon, ZoomOutIcon } from '@radix-ui/react-icons'
2
+import { IconButton } from 'components/shared'
3
+import state, { useSelector } from 'state'
4
+import styled from 'styles'
5
+
6
+const zoomIn = () => state.send('ZOOMED_IN')
7
+const zoomOut = () => state.send('ZOOMED_OUT')
8
+const zoomToFit = () => state.send('ZOOMED_TO_FIT')
9
+const zoomToActual = () => state.send('ZOOMED_TO_ACTUAL')
10
+
11
+export default function Zoom() {
12
+  return (
13
+    <Container>
14
+      <IconButton onClick={zoomOut}>
15
+        <ZoomOutIcon />
16
+      </IconButton>
17
+      <IconButton onClick={zoomIn}>
18
+        <ZoomInIcon />
19
+      </IconButton>
20
+      <ZoomCounter />
21
+    </Container>
22
+  )
23
+}
24
+
25
+function ZoomCounter() {
26
+  const camera = useSelector((s) => s.data.camera)
27
+  return (
28
+    <ZoomButton onClick={zoomToActual} onDoubleClick={zoomToFit}>
29
+      {Math.round(camera.zoom * 100)}%
30
+    </ZoomButton>
31
+  )
32
+}
33
+
34
+const Container = styled('div', {
35
+  position: 'absolute',
36
+  bottom: 12,
37
+  left: 12,
38
+  backgroundColor: '$panel',
39
+  borderRadius: '4px',
40
+  overflow: 'hidden',
41
+  alignSelf: 'flex-end',
42
+  border: '1px solid $border',
43
+  pointerEvents: 'all',
44
+  userSelect: 'none',
45
+  zIndex: 200,
46
+  boxShadow: '0px 2px 12px rgba(0,0,0,.08)',
47
+  display: 'flex',
48
+  padding: 4,
49
+
50
+  '& svg': {
51
+    strokeWidth: 0,
52
+  },
53
+})
54
+
55
+const ZoomButton = styled(IconButton, {
56
+  fontSize: '$0',
57
+  padding: 8,
58
+  width: 44,
59
+})

+ 12
- 0
hooks/useKeyboardEvents.ts Näytä tiedosto

27
           state.send('NUDGED', { delta: [-1, 0], ...getKeyboardEventInfo(e) })
27
           state.send('NUDGED', { delta: [-1, 0], ...getKeyboardEventInfo(e) })
28
           break
28
           break
29
         }
29
         }
30
+        case '=': {
31
+          if (e.metaKey) {
32
+            state.send('ZOOMED_IN')
33
+          }
34
+          break
35
+        }
36
+        case '-': {
37
+          if (e.metaKey) {
38
+            state.send('ZOOMED_OUT')
39
+          }
40
+          break
41
+        }
30
         case '!': {
42
         case '!': {
31
           // Shift + 1
43
           // Shift + 1
32
           if (e.shiftKey) {
44
           if (e.shiftKey) {

+ 12
- 17
lib/shape-utils/draw.tsx Näytä tiedosto

12
   translateBounds,
12
   translateBounds,
13
 } from 'utils/utils'
13
 } from 'utils/utils'
14
 
14
 
15
-const pathCache = new WeakMap<DrawShape, string>([])
15
+const pathCache = new WeakMap<DrawShape['points'], string>([])
16
 
16
 
17
 const draw = registerShapeUtils<DrawShape>({
17
 const draw = registerShapeUtils<DrawShape>({
18
   boundsCache: new WeakMap([]),
18
   boundsCache: new WeakMap([]),
45
   render(shape) {
45
   render(shape) {
46
     const { id, points, style } = shape
46
     const { id, points, style } = shape
47
 
47
 
48
-    if (!pathCache.has(shape)) {
49
-      if (points.length < 2) {
50
-        const left = [+style.strokeWidth, 0]
51
-        let d: number[][] = []
52
-        for (let i = 0; i < 10; i++) {
53
-          d.push(vec.rotWith(left, [0, 0], i * ((Math.PI * 2) / 8)))
54
-        }
55
-        pathCache.set(shape, getSvgPathFromStroke(d))
56
-      } else {
57
-        pathCache.set(
58
-          shape,
59
-          getSvgPathFromStroke(
60
-            getStroke(points, { size: +style.strokeWidth * 2, thinning: 0.9 })
61
-          )
48
+    if (!pathCache.has(points)) {
49
+      pathCache.set(
50
+        points,
51
+        getSvgPathFromStroke(
52
+          getStroke(points, { size: +style.strokeWidth * 2, thinning: 0.9 })
62
         )
53
         )
63
-      }
54
+      )
55
+    }
56
+
57
+    if (points.length < 2) {
58
+      return <circle id={id} r={+style.strokeWidth * 0.618} />
64
     }
59
     }
65
 
60
 
66
-    return <path id={id} d={pathCache.get(shape)} />
61
+    return <path id={id} d={pathCache.get(points)} />
67
   },
62
   },
68
 
63
 
69
   applyStyles(shape, style) {
64
   applyStyles(shape, style) {

+ 2
- 0
lib/shape-utils/ellipse.tsx Näytä tiedosto

124
   },
124
   },
125
 
125
 
126
   transform(shape, bounds, { scaleX, scaleY, initialShape }) {
126
   transform(shape, bounds, { scaleX, scaleY, initialShape }) {
127
+    // TODO: Locked aspect ratio transform
128
+
127
     shape.point = [bounds.minX, bounds.minY]
129
     shape.point = [bounds.minX, bounds.minY]
128
     shape.radiusX = bounds.width / 2
130
     shape.radiusX = bounds.width / 2
129
     shape.radiusY = bounds.height / 2
131
     shape.radiusY = bounds.height / 2

+ 1
- 1
lib/shape-utils/rectangle.tsx Näytä tiedosto

110
   },
110
   },
111
 
111
 
112
   transform(shape, bounds, { initialShape, transformOrigin, scaleX, scaleY }) {
112
   transform(shape, bounds, { initialShape, transformOrigin, scaleX, scaleY }) {
113
-    if (shape.rotation === 0) {
113
+    if (shape.rotation === 0 && !shape.isAspectRatioLocked) {
114
       shape.size = [bounds.width, bounds.height]
114
       shape.size = [bounds.width, bounds.height]
115
       shape.point = [bounds.minX, bounds.minY]
115
       shape.point = [bounds.minX, bounds.minY]
116
     } else {
116
     } else {

+ 20
- 12
state/commands/move.ts Näytä tiedosto

1
-import Command from "./command"
2
-import history from "../history"
3
-import { Data, MoveType, Shape } from "types"
4
-import { forceIntegerChildIndices, getChildren, getPage } from "utils/utils"
5
-import { getShapeUtils } from "lib/shape-utils"
1
+import Command from './command'
2
+import history from '../history'
3
+import { Data, MoveType, Shape } from 'types'
4
+import { forceIntegerChildIndices, getChildren, getPage } from 'utils/utils'
5
+import { getShapeUtils } from 'lib/shape-utils'
6
 
6
 
7
 export default function moveCommand(data: Data, type: MoveType) {
7
 export default function moveCommand(data: Data, type: MoveType) {
8
   const { currentPageId } = data
8
   const { currentPageId } = data
18
   history.execute(
18
   history.execute(
19
     data,
19
     data,
20
     new Command({
20
     new Command({
21
-      name: "move_shapes",
22
-      category: "canvas",
21
+      name: 'move_shapes',
22
+      category: 'canvas',
23
       manualSelection: true,
23
       manualSelection: true,
24
       do(data) {
24
       do(data) {
25
         const page = getPage(data, currentPageId)
25
         const page = getPage(data, currentPageId)
77
 
77
 
78
         for (let id of selectedIds) {
78
         for (let id of selectedIds) {
79
           const shape = page.shapes[id]
79
           const shape = page.shapes[id]
80
-          getShapeUtils(shape).setChildIndex(shape, initialIndices[id])
80
+          getShapeUtils(shape).setProperty(
81
+            shape,
82
+            'childIndex',
83
+            initialIndices[id]
84
+          )
81
         }
85
         }
82
       },
86
       },
83
     })
87
     })
96
   const startIndex = Math.ceil(diff[0].childIndex) + 1
100
   const startIndex = Math.ceil(diff[0].childIndex) + 1
97
 
101
 
98
   shapes.forEach((shape, i) =>
102
   shapes.forEach((shape, i) =>
99
-    getShapeUtils(shape).setChildIndex(shape, startIndex + i)
103
+    getShapeUtils(shape).setProperty(shape, 'childIndex', startIndex + i)
100
   )
104
   )
101
 }
105
 }
102
 
106
 
114
   const step = startIndex / (shapes.length + 1)
118
   const step = startIndex / (shapes.length + 1)
115
 
119
 
116
   shapes.forEach((shape, i) =>
120
   shapes.forEach((shape, i) =>
117
-    getShapeUtils(shape).setChildIndex(shape, startIndex - (i + 1) * step)
121
+    getShapeUtils(shape).setProperty(
122
+      shape,
123
+      'childIndex',
124
+      startIndex - (i + 1) * step
125
+    )
118
   )
126
   )
119
 }
127
 }
120
 
128
 
138
         : Math.ceil(nextSibling.childIndex + 1)
146
         : Math.ceil(nextSibling.childIndex + 1)
139
     }
147
     }
140
 
148
 
141
-    getShapeUtils(shape).setChildIndex(shape, nextIndex)
149
+    getShapeUtils(shape).setProperty(shape, 'childIndex', nextIndex)
142
 
150
 
143
     siblings.sort((a, b) => a.childIndex - b.childIndex)
151
     siblings.sort((a, b) => a.childIndex - b.childIndex)
144
   }
152
   }
164
         : nextSibling.childIndex / 2
172
         : nextSibling.childIndex / 2
165
     }
173
     }
166
 
174
 
167
-    getShapeUtils(shape).setChildIndex(shape, nextIndex)
175
+    getShapeUtils(shape).setProperty(shape, 'childIndex', nextIndex)
168
 
176
 
169
     siblings.sort((a, b) => a.childIndex - b.childIndex)
177
     siblings.sort((a, b) => a.childIndex - b.childIndex)
170
   }
178
   }

+ 7
- 2
state/sessions/transform-session.ts Näytä tiedosto

32
   update(data: Data, point: number[], isAspectRatioLocked = false) {
32
   update(data: Data, point: number[], isAspectRatioLocked = false) {
33
     const { transformType } = this
33
     const { transformType } = this
34
 
34
 
35
-    const { shapeBounds, initialBounds } = this.snapshot
35
+    const { shapeBounds, initialBounds, isAllAspectRatioLocked } = this.snapshot
36
 
36
 
37
     const { shapes } = getPage(data)
37
     const { shapes } = getPage(data)
38
 
38
 
41
       transformType,
41
       transformType,
42
       vec.vec(this.origin, point),
42
       vec.vec(this.origin, point),
43
       data.boundsRotation,
43
       data.boundsRotation,
44
-      isAspectRatioLocked
44
+      isAspectRatioLocked || isAllAspectRatioLocked
45
     )
45
     )
46
 
46
 
47
     this.scaleX = newBoundingBox.scaleX
47
     this.scaleX = newBoundingBox.scaleX
115
 
115
 
116
   const hasUnlockedShapes = initialShapes.length > 0
116
   const hasUnlockedShapes = initialShapes.length > 0
117
 
117
 
118
+  const isAllAspectRatioLocked = initialShapes.every(
119
+    (shape) => shape.isAspectRatioLocked
120
+  )
121
+
118
   const shapesBounds = Object.fromEntries(
122
   const shapesBounds = Object.fromEntries(
119
     initialShapes.map((shape) => [
123
     initialShapes.map((shape) => [
120
       shape.id,
124
       shape.id,
133
   return {
137
   return {
134
     type: transformType,
138
     type: transformType,
135
     hasUnlockedShapes,
139
     hasUnlockedShapes,
140
+    isAllAspectRatioLocked,
136
     currentPageId,
141
     currentPageId,
137
     initialBounds: commonBounds,
142
     initialBounds: commonBounds,
138
     shapeBounds: Object.fromEntries(
143
     shapeBounds: Object.fromEntries(

+ 56
- 26
state/state.ts Näytä tiedosto

75
     PANNED_CAMERA: {
75
     PANNED_CAMERA: {
76
       do: 'panCamera',
76
       do: 'panCamera',
77
     },
77
     },
78
+    ZOOMED_TO_ACTUAL: {
79
+      if: 'hasSelection',
80
+      do: 'zoomCameraToSelectionActual',
81
+      else: 'zoomCameraToActual',
82
+    },
83
+    ZOOMED_TO_SELECTION: {
84
+      if: 'hasSelection',
85
+      do: 'zoomCameraToSelection',
86
+    },
87
+    ZOOMED_TO_FIT: ['zoomCameraToFit', 'zoomCameraToActual'],
88
+    ZOOMED_IN: 'zoomIn',
89
+    ZOOMED_OUT: 'zoomOut',
90
+    RESET_CAMERA: 'resetCamera',
78
     TOGGLED_SHAPE_LOCK: { if: 'hasSelection', do: 'lockSelection' },
91
     TOGGLED_SHAPE_LOCK: { if: 'hasSelection', do: 'lockSelection' },
79
     TOGGLED_SHAPE_HIDE: { if: 'hasSelection', do: 'hideSelection' },
92
     TOGGLED_SHAPE_HIDE: { if: 'hasSelection', do: 'hideSelection' },
80
     TOGGLED_SHAPE_ASPECT_LOCK: {
93
     TOGGLED_SHAPE_ASPECT_LOCK: {
93
     TOGGLED_CODE_PANEL_OPEN: 'toggleCodePanel',
106
     TOGGLED_CODE_PANEL_OPEN: 'toggleCodePanel',
94
     TOGGLED_STYLE_PANEL_OPEN: 'toggleStylePanel',
107
     TOGGLED_STYLE_PANEL_OPEN: 'toggleStylePanel',
95
     CHANGED_STYLE: ['updateStyles', 'applyStylesToSelection'],
108
     CHANGED_STYLE: ['updateStyles', 'applyStylesToSelection'],
96
-    RESET_CAMERA: 'resetCamera',
97
-    ZOOMED_TO_FIT: 'zoomCameraToFit',
98
-    ZOOMED_TO_SELECTION: {
99
-      if: 'hasSelection',
100
-      do: 'zoomCameraToSelection',
101
-    },
102
-    ZOOMED_TO_ACTUAL: {
103
-      if: 'hasSelection',
104
-      do: 'zoomCameraToSelectionActual',
105
-      else: 'zoomCameraToActual',
106
-    },
107
     SELECTED_ALL: { to: 'selecting', do: 'selectAll' },
109
     SELECTED_ALL: { to: 'selecting', do: 'selectAll' },
108
     NUDGED: { do: 'nudgeSelection' },
110
     NUDGED: { do: 'nudgeSelection' },
109
     USED_PEN_DEVICE: 'enablePenLock',
111
     USED_PEN_DEVICE: 'enablePenLock',
115
       on: {
117
       on: {
116
         MOUNTED: [
118
         MOUNTED: [
117
           'restoreSavedData',
119
           'restoreSavedData',
118
-          {
119
-            if: 'hasSelection',
120
-            do: 'zoomCameraToSelectionActual',
121
-            else: ['zoomCameraToFit', 'zoomCameraToActual'],
122
-          },
123
           {
120
           {
124
             to: 'ready',
121
             to: 'ready',
125
           },
122
           },
127
       },
124
       },
128
     },
125
     },
129
     ready: {
126
     ready: {
127
+      onEnter: {
128
+        wait: 0.01,
129
+        if: 'hasSelection',
130
+        do: 'zoomCameraToSelectionActual',
131
+        else: ['zoomCameraToFit', 'zoomCameraToActual'],
132
+      },
130
       on: {
133
       on: {
131
         UNMOUNTED: [
134
         UNMOUNTED: [
132
           { unless: 'isReadOnly', do: 'forceSave' },
135
           { unless: 'isReadOnly', do: 'forceSave' },
141
             UNDO: 'undo',
144
             UNDO: 'undo',
142
             REDO: 'redo',
145
             REDO: 'redo',
143
             SAVED_CODE: 'saveCode',
146
             SAVED_CODE: 'saveCode',
144
-            DELETED: 'deleteSelectedIds',
147
+            DELETED: 'deleteSelection',
145
             STARTED_PINCHING: { to: 'pinching' },
148
             STARTED_PINCHING: { to: 'pinching' },
146
             INCREASED_CODE_FONT_SIZE: 'increaseCodeFontSize',
149
             INCREASED_CODE_FONT_SIZE: 'increaseCodeFontSize',
147
             DECREASED_CODE_FONT_SIZE: 'decreaseCodeFontSize',
150
             DECREASED_CODE_FONT_SIZE: 'decreaseCodeFontSize',
282
         usingTool: {
285
         usingTool: {
283
           initial: 'draw',
286
           initial: 'draw',
284
           onEnter: 'clearSelectedIds',
287
           onEnter: 'clearSelectedIds',
288
+          on: {
289
+            TOGGLED_TOOL_LOCK: 'toggleToolLock',
290
+          },
285
           states: {
291
           states: {
286
             draw: {
292
             draw: {
287
               initial: 'creating',
293
               initial: 'creating',
311
                       to: 'draw.creating',
317
                       to: 'draw.creating',
312
                     },
318
                     },
313
                     CANCELLED: {
319
                     CANCELLED: {
314
-                      do: ['cancelSession', 'deleteSelectedIds'],
320
+                      do: ['cancelSession', 'deleteSelection'],
315
                       to: 'selecting',
321
                       to: 'selecting',
316
                     },
322
                     },
317
                     MOVED_POINTER: 'updateDrawSession',
323
                     MOVED_POINTER: 'updateDrawSession',
351
                       },
357
                       },
352
                     ],
358
                     ],
353
                     CANCELLED: {
359
                     CANCELLED: {
354
-                      do: ['cancelSession', 'deleteSelectedIds'],
360
+                      do: ['cancelSession', 'deleteSelection'],
355
                       to: 'selecting',
361
                       to: 'selecting',
356
                     },
362
                     },
357
                   },
363
                   },
537
               },
543
               },
538
             ],
544
             ],
539
             CANCELLED: {
545
             CANCELLED: {
540
-              do: ['cancelSession', 'deleteSelectedIds'],
546
+              do: ['cancelSession', 'deleteSelection'],
541
               to: 'selecting',
547
               to: 'selecting',
542
             },
548
             },
543
           },
549
           },
849
     aspectLockSelection(data) {
855
     aspectLockSelection(data) {
850
       commands.toggle(data, 'isAspectRatioLocked')
856
       commands.toggle(data, 'isAspectRatioLocked')
851
     },
857
     },
858
+    deleteSelection(data) {
859
+      commands.deleteSelected(data)
860
+    },
852
 
861
 
853
     /* --------------------- Camera --------------------- */
862
     /* --------------------- Camera --------------------- */
854
 
863
 
855
-    resetCamera(data) {
856
-      data.camera.zoom = 1
857
-      data.camera.point = [window.innerWidth / 2, window.innerHeight / 2]
864
+    zoomIn(data) {
865
+      const { camera } = data
866
+      const i = Math.round((camera.zoom * 100) / 25)
867
+      const center = [window.innerWidth / 2, window.innerHeight / 2]
858
 
868
 
859
-      document.documentElement.style.setProperty('--camera-zoom', '1')
869
+      const p0 = screenToWorld(center, data)
870
+      camera.zoom = Math.min(3, (i + 1) * 0.25)
871
+      const p1 = screenToWorld(center, data)
872
+      camera.point = vec.add(camera.point, vec.sub(p1, p0))
873
+
874
+      setZoomCSS(camera.zoom)
875
+    },
876
+    zoomOut(data) {
877
+      const { camera } = data
878
+      const i = Math.round((camera.zoom * 100) / 25)
879
+      const center = [window.innerWidth / 2, window.innerHeight / 2]
880
+
881
+      const p0 = screenToWorld(center, data)
882
+      camera.zoom = Math.max(0.1, (i - 1) * 0.25)
883
+      const p1 = screenToWorld(center, data)
884
+      camera.point = vec.add(camera.point, vec.sub(p1, p0))
885
+
886
+      setZoomCSS(camera.zoom)
860
     },
887
     },
861
     zoomCameraToActual(data) {
888
     zoomCameraToActual(data) {
862
       const { camera } = data
889
       const { camera } = data
967
 
994
 
968
       setZoomCSS(camera.zoom)
995
       setZoomCSS(camera.zoom)
969
     },
996
     },
970
-    deleteSelectedIds(data) {
971
-      commands.deleteSelected(data)
997
+    resetCamera(data) {
998
+      data.camera.zoom = 1
999
+      data.camera.point = [window.innerWidth / 2, window.innerHeight / 2]
1000
+
1001
+      document.documentElement.style.setProperty('--camera-zoom', '1')
972
     },
1002
     },
973
 
1003
 
974
     /* ---------------------- History ---------------------- */
1004
     /* ---------------------- History ---------------------- */

+ 1
- 1
utils/utils.ts Näytä tiedosto

1487
 export function forceIntegerChildIndices(shapes: Shape[]) {
1487
 export function forceIntegerChildIndices(shapes: Shape[]) {
1488
   for (let i = 0; i < shapes.length; i++) {
1488
   for (let i = 0; i < shapes.length; i++) {
1489
     const shape = shapes[i]
1489
     const shape = shapes[i]
1490
-    getShapeUtils(shape).setChildIndex(shape, i + 1)
1490
+    getShapeUtils(shape).setProperty(shape, 'childIndex', i + 1)
1491
   }
1491
   }
1492
 }
1492
 }
1493
 export function setZoomCSS(zoom: number) {
1493
 export function setZoomCSS(zoom: number) {

Loading…
Peruuta
Tallenna