Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active August 18, 2023 07:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dacr/0efc7b25c979d14111698e1708b57cf5 to your computer and use it in GitHub Desktop.
Save dacr/0efc7b25c979d14111698e1708b57cf5 to your computer and use it in GitHub Desktop.
Drawing interactions / published by https://github.com/dacr/code-examples-manager #8d3870b9-83fc-49f7-b535-0364796259b8/87341813c93d056f5e4f206584cc7e85d0124736
// summary : Drawing interactions
// keywords : scala, vector-graphics, doodle, examples
// publish : gist
// authors : Noel Welsh, David Crosson
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : 8d3870b9-83fc-49f7-b535-0364796259b8
// created-on : 2019-08-12T16:28:07Z
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// ---------------------
//> using scala "3.3.0"
//> using dep "org.creativescala::doodle:0.20.0"
// ---------------------
//doodle.java2d.examples.Ripples.go
// https://github.com/creativescala/doodle/blob/master/java2d/src/main/scala/doodle/java2d/examples/Ripples.scala
// Copy paste of this example code with minor changes :
object Ripples {
import cats.effect.IO
import doodle.core.*
import doodle.syntax.*
import doodle.syntax.all.*
import doodle.interact.*
import doodle.interact.syntax.*
import doodle.interact.syntax.all.*
import doodle.java2d.*
import doodle.java2d.effect.*
import fs2.Stream
import cats.effect.unsafe.implicits.global
import scala.concurrent.duration.{FiniteDuration, MILLISECONDS}
import cats.instances.all._
import cats.syntax.all._
val frame = Frame(
size = Size.fixedSize(600, 600),
title = "Photos",
center = Center.atOrigin,
background = Some(Color.midnightBlue),
redraw = Redraw.clearToBackground
)
final case class Ripple(age: Int, x: Double, y: Double) {
val maxAge = 400
def alive: Boolean = age <= maxAge
def older: Ripple =
this.copy(age = age + 1)
def picture =
circle(age.toDouble)
.strokeColor(
Color.hotpink.alpha(((maxAge - age) / (maxAge.toDouble)).normalized)
)
.at(x, y)
}
def ripples(canvas: Canvas): IO[Stream[IO, Picture[Unit]]] = {
import cats.effect.std.Queue
Queue
.bounded[IO, Option[Ripple]](5)
.flatMap { queue =>
val redraw = canvas.redraw
.map(_ => none[Ripple])
.evalMap(r => queue.offer(r))
.compile
.drain
val mouseMove = canvas.mouseMove
.debounce(
FiniteDuration(100, MILLISECONDS)
) // Stop spamming with too many mouse events
.map(pt => Ripple(0, pt.x, pt.y).some)
.evalMap(r => queue.offer(r))
.compile
.drain
val ripples: Stream[IO, Picture[Unit]] = Stream
.fromQueueUnterminated(queue)
.scan(List.empty[Ripple]) { (ripples, ripple) =>
ripple match {
case Some(r) => r :: ripples
case None => ripples.filter(_.alive).map(_.older)
}
}
.map(ripples => ripples.map(_.picture).allOn)
(redraw.start >> mouseMove.start).as(ripples)
}
}
def go(): Unit = {
// frame.canvas.flatMap(canvas => ripples(canvas.mouseMove).map(_.animateToCanvas(canvas))).unsafeRunSync()
(for {
canvas <- frame.canvas()
frames <- ripples(canvas)
a <- frames.animateWithCanvasToIO(canvas)
} yield a).unsafeRunAsync(println _)
}
}
Ripples.go()
scala.io.StdIn.readLine("Enter to exit...") // required when run as a script
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment