Skip to content

Latest commit

 

History

History
167 lines (140 loc) · 3.58 KB

File metadata and controls

167 lines (140 loc) · 3.58 KB

Creating the PointerOver state machine

View the Visualization. See the index.test.tsx file for examples of use.

Here are the pointer tracking options:

type PointerTracking =
  | "client"
  | "coords"
  | "keys"
  | "layer"
  | "movement"
  | "offset"
  | "page"
  | "pen"
  | "screen"
  | "tilt"
  | "type"

Here is what they track:

type Pointer = {
  // client
  clientX?: number
  clientY?: number

  // coords
  x?: number
  y?: number

  // keys
  altKey?: boolean
  ctrlKey?: boolean
  metaKey?: boolean
  shiftKey?: boolean

  // layer
  layerX?: number
  layerY?: number

  // movement
  movementX?: number
  movementY?: number

  // offset
  offsetX?: number
  offsetY?: number

  // page
  pageX?: number
  pageY?: number

  // pen
  altitudeAngle?: number
  azimuthAngle?: number
  pressure?: number
  tangentialPressure?: number
  twist?: number

  // screen
  screenX?: number
  screenY?: number

  // tilt
  tiltX?: number
  tiltY?: number

  // type
  composed?: boolean
  pointerType?: "mouse" | "pen" | "touch"
}

These are set on transition (POINTER_OVER and POINTER_OUT).

You call createPointerOverMachineConfig like this:

createPointerOverMachineConfig({
  enabledEvents: [
    "POINTER_OUT",
    "POINTER_OVER",
  ],                            // will publish to event bus on these transitions
  id: "pointer-over-machine",   // defaults to generateShortId; should be unique
  initial: "pointerOver",       // defaults to pointerOut
  otherOption: "whatever",      // any other key-value pairs are simply passed to the context
  pointerTracking = [
    "pen",
    "screen",
  ],                            // defaults to ["keys", "client"]
  topic: "topicName",           // used by the publishPointerEvent action
})

Then returns this:

{
  machine: {
    context: {
      enabledEvents: ["POINTER_ENTER", "POINTER_LEAVE"],
      otherOption: "whatever",
      pointer: {
        altitudeAngle: undefined,
        azimuthAngle: undefined,
        pressure: undefined,
        screenX: undefined,
        screenY: undefined,
        tangentialPressure: undefined,
        twist: undefined,
      },
      pointerTracking: ["pen", "screen"],
      topic: "topicName",
    },
    id: "pointer-over-machine",
    initial: "pointerOver",
    states: {
      pointerOut: {
        on: {
          POINTER_OVER: {
            actions: ["setPointerContext", "publishPointerOverEvent"],
            target: "pointerOver",
          },
        },
      },
      pointerOver: {
        on: {
          POINTER_OUT: {
            actions: ["setPointerContext", "publishPointerOverEvent"],
            target: "pointerOut",
          },
        },
      },
    },
  },
  actions: {
    publishPointerEnterEvent: (context, event) => {
      const { enabledEvents = [], topic, ...rest } = context

      if (enabledEvents.includes(event.type)) {
        publish({ eventName: event.type, data: { ...rest } }, { topic })
      }
    },
    // updates the pointer context (screenX, etc.)
    setPointerContext: assign({
      pointer: (context, event) => setPointerContext(context.pointer, event)
    }),
  },
}

This can be passed to XState's createMachine function by separating the machine from the actions:

const { machine, actions } = createPointerMachineConfig()

const pointerStateMachine = createMachine(machine, { actions })

But see useMachines for how this is meant to be used with React and a configuration object.

Here is the machine as seen by the visualizer:

Pointer Machine Visualization