Last active
November 5, 2021 06:28
-
-
Save yllan/42d296f72796cbebb9d9529cee452d57 to your computer and use it in GitHub Desktop.
Generated by XState Viz: https://xstate.js.org/viz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const IDX = { | |
| VHS: { P2: 6, P3: 7, P4: 8, P5: 9, P6: 10 } | |
| } | |
| const nudgePoints = (elementIndexes) => assign((ctx, evt) => { | |
| const [x, y] = [evt.clientX, evt.clientY] | |
| const [sx, sy] = ctx.lastClientPoint | |
| const [dx, dy] = [x - sx, y - sy] | |
| const paths = elementIndexes.map(idx => [0, ctx.groupIndex, idx]) | |
| ctx.editorMethods.nudgeElementsAtPath(dx, dy, paths) | |
| return { ...ctx, lastClientPoint: [x, y] } | |
| }) | |
| const setPoints = (elementIndexes) => assign((ctx, evt) => { | |
| const [vx, vy] = [evt.offsetX, evt.offsetY] // viewport | |
| const [x, y] = multiply(ctx.invMatrix, [vx, vy, 1]) // dataspace | |
| const paths = elementIndexes.map(idx => [0, ctx.groupIndex, idx]) | |
| ctx.editorMethods.moveCirclesAtPathTo(x, y, paths) | |
| return { ...ctx, lastClientPoint: [evt.clientX, evt.clientY] } | |
| }) | |
| /* Finite State Machine definition */ | |
| // https://xstate.js.org/viz/?gist=42d296f72796cbebb9d9529cee452d57 | |
| const editMachine = Machine({ | |
| id: 'roiEdit', | |
| initial: 'idle', | |
| context: { | |
| // dependencies | |
| mode: 'readonly', | |
| invMatrix: [], | |
| editorMethods: {}, | |
| groupsBehaviors: {}, | |
| onUpdateCallback: () => { }, | |
| // variables | |
| lastClientPoint: [0, 0], | |
| groupIndex: 0, | |
| colorIndex: 0, | |
| colors: [ | |
| '#01f601', // green | |
| '#ffb80a', // yellow | |
| '#f35252', // red | |
| '#0086ff' // blue | |
| ] | |
| }, | |
| states: { | |
| idle: { | |
| on: { | |
| mousemove: [ | |
| { | |
| actions: 'highlightElement', | |
| cond: 'hitElement' | |
| }, | |
| { | |
| actions: 'clearHighlights' | |
| } | |
| ], | |
| mousedown: [ | |
| { | |
| actions: ['selectElement', 'setLastClientPoint'], | |
| target: 'selection', | |
| cond: 'hitElement' | |
| }, | |
| { | |
| actions: ['createSimpleShape', 'setLastClientPoint'], | |
| target: 'simple_shape_creation', | |
| cond: 'isSimpleShape' | |
| }, | |
| { | |
| actions: ['createAngle', 'setLastClientPoint'], | |
| target: 'angle_creation', | |
| cond: 'isAngle' | |
| }, | |
| { | |
| actions: ['createVHS', 'setLastClientPoint'], | |
| target: 'vhs_creation', | |
| cond: 'isVHS' | |
| }, | |
| { | |
| actions: ['createText', 'setLastClientPoint'], | |
| target: 'decide_text_position', | |
| cond: 'isText' | |
| } | |
| ], | |
| dblclick: [{ | |
| actions: ['selectElement', 'setGroupIndex', 'prepareTextInput'], | |
| target: 'edit_text', | |
| cond: 'targetIsText' | |
| }], | |
| delete: { | |
| actions: 'deleteSelectedROIs' | |
| } | |
| } | |
| }, | |
| selection: { | |
| on: { | |
| mousemove: { // nudge element | |
| actions: 'nudgeSelection', | |
| target: 'selection_dragged' | |
| }, | |
| mouseup: { // just click, not dragged | |
| target: 'idle' | |
| } | |
| } | |
| }, | |
| selection_dragged: { | |
| on: { | |
| mousemove: { | |
| actions: 'nudgeSelection' | |
| }, | |
| mouseup: { | |
| actions: 'saveROI', | |
| target: 'idle' | |
| } | |
| } | |
| }, | |
| vhs_creation: { | |
| initial: 'p1_commited', | |
| states: { | |
| p1_commited: { // 第一個點決定好位置 | |
| on: { | |
| mousemove: { | |
| actions: 'nudgeVHSP2', | |
| target: 'p2_moving' | |
| } | |
| } | |
| }, | |
| p2_moving: { // 移動第二個點 | |
| on: { | |
| mousemove: { actions: 'nudgeVHSP2' }, | |
| mouseup: { target: 'p2_commited' } | |
| } | |
| }, | |
| p2_commited: { | |
| on: { | |
| mousedown: { | |
| actions: 'setVHSP3P4', | |
| target: 'p3_commited' | |
| } | |
| } | |
| }, | |
| p3_commited: { | |
| on: { | |
| mousemove: { | |
| actions: 'nudgeVHSP4', | |
| target: 'p4_moving' | |
| } | |
| } | |
| }, | |
| p4_moving: { | |
| on: { | |
| mousemove: { actions: 'nudgeVHSP4' }, | |
| mouseup: { target: 'p4_commited' } | |
| } | |
| }, | |
| p4_commited: { | |
| on: { | |
| mousedown: { | |
| actions: 'setVHSP5P6', | |
| target: 'p5_commited' | |
| } | |
| } | |
| }, | |
| p5_commited: { | |
| on: { | |
| mousemove: { | |
| actions: 'nudgeVHSP6', | |
| target: 'p6_moving' | |
| } | |
| } | |
| }, | |
| p6_moving: { | |
| on: { | |
| mousemove: { actions: 'nudgeVHSP6' }, | |
| mouseup: { // 結束編輯, 儲存 | |
| actions: ['saveROI', 'clearSelection', send('saved')] | |
| } | |
| } | |
| } | |
| }, | |
| on: { | |
| saved: { target: 'idle' } | |
| } | |
| }, | |
| angle_creation: { | |
| initial: 'p1_commited', | |
| states: { | |
| p1_commited: { | |
| on: { | |
| mousemove: { | |
| actions: 'nudgeAngleP2P3', | |
| target: 'p2_moving' | |
| } | |
| } | |
| }, | |
| p2_moving: { | |
| on: { | |
| mousemove: { actions: 'nudgeAngleP2P3' }, | |
| mouseup: { target: 'p2_commited' } | |
| } | |
| }, | |
| p2_commited: { | |
| on: { | |
| mousemove: { actions: 'nudgeAngleP3' }, | |
| mouseup: { actions: ['saveROI', 'clearSelection', send('saved')] } | |
| } | |
| } | |
| }, | |
| on: { | |
| saved: { target: 'idle' } | |
| } | |
| }, | |
| simple_shape_creation: { | |
| initial: 'p1_commited', | |
| states: { | |
| p1_commited: { | |
| on: { | |
| mousemove: { | |
| actions: 'nudgeSelection', | |
| target: 'p2_moving' | |
| }, | |
| mouseup: { | |
| actions: ['saveROI', 'clearSelection', send('saved')], | |
| cond: 'isLabel' | |
| } | |
| } | |
| }, | |
| p2_moving: { | |
| on: { | |
| mousemove: { actions: 'nudgeSelection' }, | |
| mouseup: { actions: ['saveROI', 'clearSelection', send('saved')] } | |
| } | |
| } | |
| }, | |
| on: { | |
| saved: { target: 'idle' } | |
| } | |
| }, | |
| decide_text_position: { | |
| on: { | |
| mousemove: { actions: 'nudgeSelection' }, | |
| mouseup: { actions: 'prepareTextInput', target: 'edit_text' } | |
| } | |
| }, | |
| edit_text: { | |
| initial: 'normal_mode', | |
| states: { | |
| normal_mode: { | |
| on: { | |
| input: { actions: 'handleInput' }, | |
| close: [ | |
| { | |
| actions: ['discardROI', 'clearSelection', send('discard')], | |
| cond: 'emptyText' | |
| }, | |
| { | |
| actions: ['saveROI', 'clearSelection', send('saved')] | |
| } | |
| ], | |
| begin_ime: { target: 'ime_mode' } | |
| } | |
| }, | |
| ime_mode: { | |
| on: { | |
| input: { actions: 'handleInput' }, | |
| end_ime: { target: 'normal_mode' } | |
| } | |
| } | |
| }, | |
| on: { | |
| saved: { target: 'idle' }, | |
| discard: { target: 'idle' } | |
| } | |
| } | |
| }, | |
| on: { | |
| // 更新 props 時傳進來 machine | |
| UPDATE: { actions: assign((ctx, evt) => ({ ...ctx, ...evt.content })) } | |
| } | |
| }, { | |
| actions: { | |
| setLastClientPoint: (ctx, evt) => { /*STUB*/ }, | |
| selectElement: (ctx, evt) => { /*STUB*/ }, | |
| setGroupIndex: (ctx, evt) => { /*STUB*/ }, | |
| clearHighlights: (ctx) => { /*STUB*/ }, | |
| highlightElement: (ctx, evt) => { /*STUB*/ }, | |
| nudgeSelection: (ctx, evt) => { /*STUB*/ }, | |
| createSimpleShape: (ctx, evt) => { /*STUB*/ }, | |
| createText: (ctx, evt) => { /*STUB*/ }, | |
| prepareTextInput: (ctx) => { /*STUB*/ }, | |
| handleInput: (ctx, evt) => { /*STUB*/ }, | |
| clearSelection: (ctx) => { /*STUB*/ }, | |
| deleteSelectedROIs: (ctx) => { /*STUB*/ }, | |
| saveROI: (ctx) => { /*STUB*/ }, | |
| discardROI: (ctx) => { /*STUB*/ }, | |
| createAngle: (ctx, evt) => { /*STUB*/ }, | |
| nudgeVHSP2: nudgePoints([IDX.VHS.P2]), | |
| nudgeVHSP4: nudgePoints([IDX.VHS.P4]), | |
| nudgeVHSP6: nudgePoints([IDX.VHS.P6]), | |
| setVHSP3P4: setPoints([IDX.VHS.P3, IDX.VHS.P4]), | |
| setVHSP5P6: setPoints([IDX.VHS.P5, IDX.VHS.P6]), | |
| nudgeAngleP2P3: nudgePoints([3, 4]), | |
| nudgeAngleP3: nudgePoints([4]) | |
| }, | |
| guards: { | |
| hitElement: (ctx, evt) => true, | |
| isVHS: (ctx) => ctx.mode === 'vhs', | |
| isAngle: (ctx) => ctx.mode === 'angle', | |
| isText: (ctx) => ctx.mode === 'text', | |
| isLabel: (ctx) => ctx.mode === 'label', | |
| isSimpleShape: (ctx) => new Set(['line', 'arrow', 'ellipse', 'label']).has(ctx.mode), | |
| emptyText: (ctx) => ctx.textValue === '', | |
| targetIsText: (ctx, evt) => false | |
| } | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment