Material Motion Exploring solutions that will empower creators with the tools needed to describe and implement rich, interactive motion on any platform. Edit this page · History
MotionObservable Metadata MotionRuntime-toGraphViz · MotionRuntime-whenAllAtRest
Status Interface level Implementation level Library
Draft as of February 17, 2017 L3: Stream creator L4: Runtime engineering material-motion
UpdatesCurrent StatusInitiation dateCompletion date
Drafting graphviz output Draft February 17, 2017
platformsrctests
iOS (Swift) View

Metadata feature specification for MotionObservable

This is the engineering specification for the Metadata object.

Overview

In order provide introspection capabilities, each MotionObservable instance is expected to store a small amount of meta information about itself. This information is stored in an object called Metadata.

The metadata is currently being considered for use in visualizing the graph of connected streams in a runtime. Example code:

runtime.add(Draggable(), to: square)

timeline.timeOffset.value = CGFloat(slider.value * 0.4)
timeline.paused.value = true

let arcMove = ArcMove(duration: 0.4,
                      from: runtime.get(square.layer).position,
                      to: runtime.get(circle.layer).position,
                      system: coreAnimation)
arcMove.timeline = timeline
runtime.add(arcMove, to: square2)

Example output:

digraph G {
  node [shape=rect]
  {"translated(from:in:)(BF5FE183-A435-4FB2-9CA9-8082C3B97D14)" [label="translated(from:\nReactiveProperty<__C.CGPoint>::0x600000178c00,\nin:\nUIView::0x7f848a410900)", style=filled, fillcolor="#DB4437"]} -> {"CALayer::0x60000002d660.position" [label="CALayer::0x60000002d660.position", style=filled, fillcolor="#FFFFFF"]}
  {"CALayer::0x60000002d660.position" [label="CALayer::0x60000002d660.position", style=filled, fillcolor="#0F9D58"]} -> {"translated(from:in:)(BF5FE183-A435-4FB2-9CA9-8082C3B97D14)" [label="translated(from:\nReactiveProperty<__C.CGPoint>::0x600000178c00,\nin:\nUIView::0x7f848a410900)(BF5FE183-A435-4FB2-9CA9-8082C3B97D14)", style=filled, fillcolor="#FFFFFF"]}
  {"Gesture Recognizer(029F6C3D-A254-4CE9-B991-F3905AB262EE)" [label="Gesture Recognizer(:\nUIPanGestureRecognizer::0x7f848a513bc0)", style=filled, fillcolor="#FFFFFF"]} -> {"translated(from:in:)(BF5FE183-A435-4FB2-9CA9-8082C3B97D14)" [label="translated(from:\nReactiveProperty<__C.CGPoint>::0x600000178c00,\nin:\nUIView::0x7f848a410900)", style=filled, fillcolor="#DB4437"]}
  {"Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D)" [label="Core Animation Path Tween(:\nMotionObservable<CoreGraphics.CGFloat>::0x600000246c00)", style=filled, fillcolor="#FFFFFF"]} -> {"CALayer::0x60000002d5e0.position" [label="CALayer::0x60000002d5e0.position", style=filled, fillcolor="#FFFFFF"]}
  {"PathTween.duration(72BCFA57-F958-4519-A725-316C63792BC3)" [label="PathTween.duration", style=filled, fillcolor="#0F9D58"]} -> {"Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D)" [label="Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D):\nMotionObservable<CoreGraphics.CGFloat>::0x600000246c00", style=filled, fillcolor="#FFFFFF"]}
  {"arcMove(from:to:)" [label="arcMove(from:\nMotionObservable<__C.CGPoint>::0x6000002468d0,\nto:\nMotionObservable<__C.CGPoint>::0x6000002468a0)", style=filled, fillcolor="#FFFFFF"]} -> {"Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D)" [label="Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D):\nMotionObservable<CoreGraphics.CGFloat>::0x600000246c00", style=filled, fillcolor="#FFFFFF"]}
  {"CALayer::0x60000002d660.position" [label="CALayer::0x60000002d660.position", style=filled, fillcolor="#0F9D58"]} -> {"arcMove(from:to:)" [label="arcMove(from:\nMotionObservable<__C.CGPoint>::0x6000002468d0,\nto:\nMotionObservable<__C.CGPoint>::0x6000002468a0)", style=filled, fillcolor="#FFFFFF"]}
  {"CALayer::0x60000002d380.position" [label="CALayer::0x60000002d380.position", style=filled, fillcolor="#0F9D58"]} -> {"arcMove(from:to:)" [label="arcMove(from:\nMotionObservable<__C.CGPoint>::0x6000002468d0,\nto:\nMotionObservable<__C.CGPoint>::0x6000002468a0)", style=filled, fillcolor="#FFFFFF"]}
  {"PathTween.enabled(E1F7BB29-2A35-438C-A49A-4458161EA08E)" [label="PathTween.enabled", style=filled, fillcolor="#0F9D58"]} -> {"Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D)" [label="Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D):\nMotionObservable<CoreGraphics.CGFloat>::0x600000246c00", style=filled, fillcolor="#FFFFFF"]}
  {"PathTween.state(E1F7BB29-2A35-438C-A49A-4458161EA08E)" [label="PathTween.state", style=filled, fillcolor="#0F9D58"]} -> {"Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D)" [label="Core Animation Path Tween(F2DC1810-419F-4077-8642-584439BF9D0D):\nMotionObservable<CoreGraphics.CGFloat>::0x600000246c00", style=filled, fillcolor="#FFFFFF"]}
}

MVP

Expose a Metadata type

Expose a public class type named Metadata.

public class Metadata {
}

Store name, uuid, and args

class Metadata {
  public let identifier: String
  public let label: String
  public let args: [Any]?
  private var parent: OperatorMetadata?

  init(_ identifier: String, objectIdentifier: String? args: [Any]?, parent: Metadata?) {
    if let objectIdentifier = objectIdentifier {
      self.identifier = objectIdentifier + identifier
    } else {
      self.identifier = identifier
    }
    self.label = identifier
    self.args = args
    self.parent = parent
  }

Expose with API

Expose a with method that creates a new OperatorMetadata with self as its parent.

class Metadata {
  public func with(_ name: String, args: [Any]? = nil) -> Metadata {
    return .init(name, args: args, parent: self)
  }

Expose debug description API

Expose a debug description method. The output is expected to be a recursive representation of this metadata and all of its ancestral metadata.

class Metadata {
  public var debugDescription: String {
  }

View the issue tracking formalization of the debug description.

Store a constant metadata instance on each MotionObservable

class MotionObservable {
  public let metadata: Metadata
}