Last active
September 28, 2024 08:58
-
-
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/70361737d3a577178a1fd452c32e34ccf057c01a
This file contains hidden or 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.5.1" | |
//> using dep "org.creativescala::doodle:0.26.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 = 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() | |
.use(canvas => | |
for { | |
frames <- ripples(canvas) | |
a <- frames.animateWithCanvasToIO(canvas) | |
} yield a | |
) | |
.unsafeRunAsync(x => println(x)) | |
} | |
} | |
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