All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hyperscala.fabricjs.StaticCanvas.scala Maven / Gradle / Ivy

The newest version!
package org.hyperscala.fabricjs

import org.hyperscala.Container
import org.hyperscala.fabricjs.event._
import org.hyperscala.fabricjs.paint.GradientPaint
import org.hyperscala.fabricjs.prop.{CanvasProperty, ObjectProperty}
import org.hyperscala.html._
import org.hyperscala.html.constraints.BodyChild
import org.hyperscala.javascript._
import org.hyperscala.javascript.dsl._
import org.hyperscala.web.Webpage
import org.powerscala.hierarchy.{ParentLike, MutableContainer}
import org.powerscala.hierarchy.event.Descendants
import org.powerscala.property.event.PropertyChangeEvent
import org.powerscala._

import scala.reflect.ManifestFactory

/**
 * @author Matt Hicks 
 */
class StaticCanvas(val canvas: tag.Canvas) extends MutableContainer[Object] {
  Storage.set(canvas, "fabricjs.StaticCanvas", this)

  canvas.handle[CanvasEvent] {
    case evt => _events.find(p => p.name == evt.eventType) match {
      case Some(p) => p.asInstanceOf[CanvasEventProcessor[CanvasEvent]].fire(evt)
      case None => throw new RuntimeException(s"Unable to find processor for type: ${evt.eventType}")
    }
  }
  canvas.handle[ObjectEvent] {
    case evt => evt.obj._events.find(p => p.name == evt.eventType) match {
      case Some(p) => p.asInstanceOf[ObjectEventProcessor[ObjectEvent]].fire(evt)
      case None => throw new RuntimeException(s"Unable to find processor for type: ${evt.eventType}")
    }
  }

  implicit val childManifest = ManifestFactory.classType[Object](classOf[Object])

  val id = Unique()
  protected def className = "StaticCanvas"

  private var _properties = List.empty[CanvasProperty[_]]
  private[fabricjs] var _events = List.empty[CanvasEventProcessor[_ <: CanvasEvent]]

  def properties = _properties

  lazy val allowTouchScrolling = prop("allowTouchScrolling", false)
  lazy val backgroundColor = prop[Color]("backgroundColor", null)
  lazy val backgroundImage = prop[String]("backgroundImage", null)
  lazy val clipTo = prop[JavaScriptContent]("clipTo", null)
  lazy val controlsAboveOverlay = prop("controlsAboveOverlay", false)
  lazy val imageSmoothingEnabled = prop("imageSmoothingEnabled", true)
  lazy val includeDefaultValues = prop("includeDefaultValues", true)
  lazy val overlayColor = prop[Color]("overlayColor", null)
  lazy val overlayImage = prop[String]("overlayImage", null)
  lazy val preserveObjectStacking = prop("preserveObjectStacking", false)
  lazy val renderOnAddRemove = prop("renderOnAddRemove", true)
  lazy val stateful = prop("stateful", true)
  lazy val svgViewportTransformation = prop("svgViewportTransformation", true)
  lazy val viewportTransform = prop[Array[Double]]("viewportTransform", null)

  lazy val beforeRenderEvent = new BeforeRenderEventProcessor(this)
  lazy val afterRenderEvent = new AfterRenderEventProcessor(this)
  lazy val canvasClearedEvent = new CanvasClearedEventProcessor(this)
  lazy val objectAddedEvent = new ObjectAddedEventProcessor(this)
  lazy val objectRemovedEvent = new ObjectRemovedEventProcessor(this)

  eval(JavaScriptString(s"FabricJS.init('$id', new fabric.$className('${canvas.identity}'));"))

  listen[PropertyChangeEvent[_], Unit, Unit]("change", Priority.Normal, Descendants) {
    case evt => evt.property match {
      case cp: CanvasProperty[_] => eval(s"FabricJS.set('$id', null, '${cp.name}', ${JavaScriptContent.toJS(evt.newValue)});")
      case op: ObjectProperty[_] => evt.newValue match {
        case gradient: GradientPaint => {
          eval(gradient.toJS(op.o, op.name))
          renderAll()
        }
        case value => eval(s"FabricJS.set('$id', '${op.o.id}', '${op.name}', ${op.o.toJS(op.name, value)});")
      }
      case cep: CanvasEventProperty[_] => {
        val handler =
          s"""function(options) {
             |  ${JavaScriptContent.toJS(cep.p.js())}
              |}""".stripMargin
        eval(s"FabricJS.canvasEvent('${cep.p.canvas.id}', '${cep.p.name}', $handler)")
      }
      case oep: ObjectEventProperty[_] => {
        val handler =
          s"""function(options) {
             |  ${oep.p.obj.toJS(oep.p.name, oep.p.js())}
              |}""".stripMargin
        eval(s"FabricJS.objectEvent('${oep.p.obj.id}', '${oep.p.name}', $handler);")
      }
    }
  }

  childAdded.on {
    case evt => add(evt.child.asInstanceOf[Object])
  }
  childRemoved.on {
    case evt => remove(evt.child.asInstanceOf[Object])
  }

  def renderAll() = eval(s"FabricJS.canvas['$id'].renderAll();")

  private def add(o: Object) = o.parent match {
    case group: Group => o.addToCanvas(this, Some(group))
    case _ => o.addToCanvas(this, None)
  }

  private def remove(o: Object) = {
    eval(s"FabricJS.remove('$id', '${o.id}');")
  }

  protected[fabricjs] def eval(js: JavaScriptContent) = canvas.connected[Webpage] {
    case webpage => webpage.eval(js)
  }

  protected def prop[T](name: String, default: T)(implicit manifest: Manifest[T]) = synchronized {
    val p = new CanvasProperty[T](name, this)(manifest)
    p := default
    _properties = p :: _properties
    p
  }

  def byId[T <: Object](id: String)(implicit manifest: Manifest[T]) = TypeFilteredIterator[T](ParentLike.descendants(this)).find {
    case obj: Object => obj.id == id
    case _ => false
  }

  def getById[T <: Object](id: String)(implicit manifest: Manifest[T]) = {
    byId[T](id)(manifest).getOrElse(throw new NullPointerException("Unable to find '%s' by id.".format(id)))
  }

  def byType[T](implicit manifest: Manifest[T]) = TypeFilteredIterator[T](ParentLike.descendants(this)).toStream
}

object StaticCanvas {
  def apply(container: Container[BodyChild], width: Int, height: Int, id: String = Unique()) = {
    val t = new tag.Canvas(id = id, width = width, height = height)
    container.contents += t

    new StaticCanvas(t)
  }

  def get(t: tag.Canvas) = Storage.get[String, StaticCanvas](t, "fabricjs.StaticCanvas")
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy