Last active
May 25, 2024 10:20
-
-
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/974732dadb102eb5aaee2cf56247d777c6cf2498
This file contains 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
// 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.4.2" | |
//> 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