creativescala / doodle Goto Github PK
View Code? Open in Web Editor NEWCompositional vector graphics in Scala / Scala.JS
Home Page: https://creativescala.org/doodle/
License: Apache License 2.0
Compositional vector graphics in Scala / Scala.JS
Home Page: https://creativescala.org/doodle/
License: Apache License 2.0
Picture
needs a Monad
type class instances for the Size
algebra to be any use. This requires the underlying F
has a Monad
instance.
When running sbt I get the following error:
$ sbt
[info] Loading project definition from C:\Workspace\doodle\project
[info] Compiling 1 Scala source to C:\Workspace\doodle\project\target\scala-2.10\sbt-0.13\classes...
[error] error while loading , error in opening zip file
scala.reflect.internal.MissingRequirementError: object scala.runtime in compiler mirror not found.
at scala.reflect.internal.MissingRequirementError$.signal(MissingRequirementError.scala:16)
at scala.reflect.internal.MissingRequirementError$.notFound(MissingRequirementError.scala:17)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:48)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:40)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:61)
at scala.reflect.internal.Mirrors$RootsBase.getPackage(Mirrors.scala:172)
at scala.reflect.internal.Mirrors$RootsBase.getRequiredPackage(Mirrors.scala:175)
at scala.reflect.internal.Definitions$DefinitionsClass.RuntimePackage$lzycompute(Definitions.scala:183)
at scala.reflect.internal.Definitions$DefinitionsClass.RuntimePackage(Definitions.scala:183)
at scala.reflect.internal.Definitions$DefinitionsClass.RuntimePackageClass$lzycompute(Definitions.scala:184)
at scala.reflect.internal.Definitions$DefinitionsClass.RuntimePackageClass(Definitions.scala:184)
at scala.reflect.internal.Definitions$DefinitionsClass.AnnotationDefaultAttr$lzycompute(Definitions.scala:1024)
at scala.reflect.internal.Definitions$DefinitionsClass.AnnotationDefaultAttr(Definitions.scala:1023)
at scala.reflect.internal.Definitions$DefinitionsClass.syntheticCoreClasses$lzycompute(Definitions.scala:1153)
at scala.reflect.internal.Definitions$DefinitionsClass.syntheticCoreClasses(Definitions.scala:1152)
at scala.reflect.internal.Definitions$DefinitionsClass.symbolsNotPresentInBytecode$lzycompute(Definitions.scala:1196)
at scala.reflect.internal.Definitions$DefinitionsClass.symbolsNotPresentInBytecode(Definitions.scala:1196)
at scala.reflect.internal.Definitions$DefinitionsClass.init(Definitions.scala:1261)
at scala.tools.nsc.Global$Run.(Global.scala:1290)
at xsbt.CachedCompiler0$$anon$2.(CompilerInterface.scala:106)
at xsbt.CachedCompiler0.run(CompilerInterface.scala:106)
at xsbt.CachedCompiler0.run(CompilerInterface.scala:95)
at xsbt.CompilerInterface.run(CompilerInterface.scala:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sbt.compiler.AnalyzingCompiler.call(AnalyzingCompiler.scala:101)
at sbt.compiler.AnalyzingCompiler.compile(AnalyzingCompiler.scala:47)
at sbt.compiler.AnalyzingCompiler.compile(AnalyzingCompiler.scala:41)
at sbt.compiler.AggressiveCompile$$anonfun$3$$anonfun$compileScala$1$1.apply$mcV$sp(AggressiveCompile.scala:97)
at sbt.compiler.AggressiveCompile$$anonfun$3$$anonfun$compileScala$1$1.apply(AggressiveCompile.scala:97)
at sbt.compiler.AggressiveCompile$$anonfun$3$$anonfun$compileScala$1$1.apply(AggressiveCompile.scala:97)
at sbt.compiler.AggressiveCompile.sbt$compiler$AggressiveCompile$$timed(AggressiveCompile.scala:162)
at sbt.compiler.AggressiveCompile$$anonfun$3.compileScala$1(AggressiveCompile.scala:96)
at sbt.compiler.AggressiveCompile$$anonfun$3.apply(AggressiveCompile.scala:139)
at sbt.compiler.AggressiveCompile$$anonfun$3.apply(AggressiveCompile.scala:86)
at sbt.inc.IncrementalCompile$$anonfun$doCompile$1.apply(Compile.scala:38)
at sbt.inc.IncrementalCompile$$anonfun$doCompile$1.apply(Compile.scala:36)
at sbt.inc.IncrementalCommon.cycle(IncrementalCommon.scala:31)
at sbt.inc.Incremental$$anonfun$1.apply(Incremental.scala:39)
at sbt.inc.Incremental$$anonfun$1.apply(Incremental.scala:38)
at sbt.inc.Incremental$.manageClassfiles(Incremental.scala:66)
at sbt.inc.Incremental$.compile(Incremental.scala:38)
at sbt.inc.IncrementalCompile$.apply(Compile.scala:26)
at sbt.compiler.AggressiveCompile.compile2(AggressiveCompile.scala:153)
at sbt.compiler.AggressiveCompile.compile1(AggressiveCompile.scala:70)
at sbt.compiler.AggressiveCompile.apply(AggressiveCompile.scala:45)
at sbt.Compiler$.apply(Compiler.scala:74)
at sbt.Compiler$.apply(Compiler.scala:65)
at sbt.Defaults$.sbt$Defaults$$compileTaskImpl(Defaults.scala:789)
at sbt.Defaults$$anonfun$compileTask$1.apply(Defaults.scala:781)
at sbt.Defaults$$anonfun$compileTask$1.apply(Defaults.scala:781)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
at sbt.std.Transform$$anon$4.work(System.scala:63)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
at sbt.Execute.work(Execute.scala:235)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
error scala.reflect.internal.MissingRequirementError: object scala.runtime in compiler mirror not found.
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?
Scala and java versions:
PS C:\Workspace\doodle> scala -version
Scala code runner version 2.11.5 -- Copyright 2002-2013, LAMP/EPFL
PS C:\Workspace\doodle> java -version
java version "1.8.0_25"
Java(TM) SE Runtime Environment (build 1.8.0_25-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
I would like to show the coordinate edges so when I see the drawing I can have the context. What can I do?
Thanks
Reynaldo
Paths need to start with a move to the local origin (at least on AWT). Make sure this happens.
The Gif animation writer doesn't interpret the settings in the frame (such as background color). This limits its usefulness.
Hey man, I really like what you've done here and it's cool to see the project alive and kicking. As far as I'm aware this is the best tool for generating Svg out of Scala so I appreciate it!
I'm having an issue with some Svg output.
Given:
val rect = Image.rectangle(200, 200).strokeColor(Color.red)
val rect2 = ClosedPath(List(
MoveTo(Cartesian(0.0, 0.0)),
LineTo(Cartesian(200.0, 0.0)),
LineTo(Cartesian(200.0, 200.0)),
LineTo(Cartesian(0.0, 200.0)),
LineTo(Cartesian(0.0, 0.0))
))
val frame = doodle.svg.effect.Frame("svg").fitToPicture(10)
rect.write[Svg]((wd / "rect-200.svg").toString, frame)(svgWriter)
rect2.write[Svg]((wd / "rect2-200.svg").toString, frame)(svgWriter)
The first rect correctly yields a Rect(10, 10, 200, 200) where Rect(x,y,w,h) on a canvas of 220 by 220.
The latter path yields a path with:
d: M 0,0 M 0,0 L 200,0 L 200,200 L 0,200 L 0,0 Z
transform: matrix(1.0,0.0,0.0,-1.0,0.0,0.0)
In this case we get a Rect(10, 210, 200, 200). As soon as I remove the transformation the rectangle moves to be center in the viewbox but I suspect for the wrong reason (it'll be upside down). I suspect the y-mirror transformation fails because the transforms are applied around the 'origin' of the shape. In the case of a svg rect that's its centroid. In the case of a path it's the coordinates of the very first draw call.
Entire Svg output for rect2: https://gist.github.com/Pucilowski/ace2dce5f15872ebca173b345cbd6826?short_path=fde0c33
Thanks for the time you're putting into this!
Build Doodle 0.9 for Scala.js:
I would like to post images generated from doodle to Twitter. The required format is Base 64 string. Currently, doodle only allows writing to png, jpg, or gif. Can you please update to allow the user to write to a Base64 string to make this process easier? Thanks!
It looks like right now Doodle doesn't have the ability to draw multiple doodle.core.Image objects in the same context? Each draw()
call opens a new rendering window.
It also looks like Doodle doesn't support transitions? That is, moving something once it's been drawn on a canvas?
Does doodle plan to add these things? Is there any way I might do drawing with Doodle's high level API and then access the lower level Java2D objects to do more complicated things like transitions and adding other drawings to a canvas?
I cloned the repo from github, ran 'sbt' followed by 'console'. Things appeared all right. But then:
`scala> draw(Circle(10) fillColor Color.red)
<console>:26: error: not found: value draw
draw(Circle(10) fillColor Color.red)
^
`
What am I doing wrong? I am on Ubuntu 14.04 64-bit with OpenJDK 7.
Some images (e.g. large fractals) require so many points that representing them as an Image
data structure in-memory is infeasible. We have the Canvas
API that draws directly onto the screen (or file) without (much) memory allocation.
We need to make this available as an additional element in the Image
algebraic data type.
E.g.
final case class Render(width: Int, height: Int, f: Canvas => Unit) extends Image
Here is has a nominal width and height for layout purposes.
Then update backends to call f
with the Canvas
instances.
The semantics of at
when combined with our combinators such as beside
and above
are unclear. For example, this does not render what I expect:
(Circle(10).fillColor(Color.darkBlue) beside
(Circle(10).fillColor(Color.aliceBlue).at(10,10) on Circle(10).fillColor(Color.red)))
Specifically, I don't expect a gap between the darkBlue and red circles.
would you mind updating your monix dependency to 3.0.0-RC2? some source changes (maybe just one?) will be needed:
sbt:root> animate/compile
[warn] Credentials file /Users/tisue/.sbt/sonatype_credential does not exist
[warn] Credentials file /Users/tisue/.sbt/sonatype_credential does not exist, ignoring it
[warn] Credentials file /Users/tisue/.sbt/sonatype_credential does not exist, ignoring it
[info] Compiling 65 Scala sources to /Users/tisue/doodle/core/target/scala-2.12/classes ...
[info] Done compiling.
[info] Compiling 6 Scala sources to /Users/tisue/doodle/animate/target/scala-2.12/classes ...
[error] /Users/tisue/doodle/animate/src/main/scala/doodle/animate/java2d/Java2dAnimator.scala:47:31: type mismatch;
[error] found : cats.effect.IO[A]
[error] required: monix.eval.Task[?]
[error] .mapEval(img => e.render(canvas)(algebra => img(algebra)))
[error] ^
[error] one error found
[error] (animate / Compile / compileIncremental) Compilation failed
[error] Total time: 13 s, completed Jan 4, 2019 9:12:40 AM
context: this would allow me to keep Doodle in the Scala 2.12 community build. currently it is failing
P90Puma@P90PUMA-X58A ~/git/doodle (develop)
$ sbt.bat console
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=512m; sup
port was removed in 8.0
[info] Loading project definition from C:\Users\P90Puma\git\doodle\project
Missing bintray credentials C:\Users\P90Puma.bintray.credentials. Some bintray
features depend on this.
[info] Set current project to doodle (in build file:/C:/Users/P90Puma/git/doodle
/)
[error] Not a valid command: %*
[error] %*
[error] ^
P90Puma@P90PUMA-X58A ~/git/doodle (develop)
$ java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
P90Puma@P90PUMA-X58A ~/git/doodle (develop)
$ which java
/c/ProgramData/Oracle/Java/javapath/java
Doodle currently applies the inner most ContextTransform
. E.g.
circle(10).fillColor(Color.red).fillColor(Color.blue)
will produce a red circle. A more sensible semantics is to produce a blue circle.
for a getting-started library like this, I think it would be better to remove any possible road bump for newcomers. only having the library available via a custom resolver is a road bump; seen on Gitter today:
does anyone know where I can find the scala doodle lib ? can't find it on mvn central
Base64 support was added as a method to the Writer effect type class. It would be better factored into its own type class. Perform this refactoring.
Having a little site for Doodle to host documentation would be very nice. We could perhaps use the 47degrees sbt-microsite project to get this done easily.
Filling with gradients is supported by both SVG and Java2D (I think). It would be useful to expose this functionality within Doodle as it opens up more creative possibilities.
DrawingContext
to allow gradient fillsText layout on both Java2D and SVG seems wrong (see, e.g. BoxesAndArrows.flatMap.draw
). Investigate this and resolve if possible.
Memoising the calculation at the time of construction, which is stack-safe, should solve the issue.
Need to augment stack safety spec to check for Above / Beside which use bounding box calculations to ensure this is fixed.
In sbt:
> project doodleJS
> run
results in:
[info] Running Main
org.mozilla.javascript.EcmaError: TypeError: Cannot call method "getElementById" of undefined (Ldoodle_js_package$.sjsir#205)
at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3701)
at org.mozilla.javascript.ScriptRuntime.constructError(ScriptRuntime.java:3679)
at org.mozilla.javascript.ScriptRuntime.typeError(ScriptRuntime.java:3707)
at org.mozilla.javascript.ScriptRuntime.typeError2(ScriptRuntime.java:3726)
at org.mozilla.javascript.ScriptRuntime.undefCallError(ScriptRuntime.java:3743)
at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThisHelper(ScriptRuntime.java:2269)
at org.mozilla.javascript.ScriptRuntime.getPropFunctionAndThis(ScriptRuntime.java:2247)
at org.mozilla.javascript.ScriptRuntime.getElemFunctionAndThis(ScriptRuntime.java:2215)
at org.mozilla.javascript.gen.Ldoodle_js_package__sjsir_7._c_anonymous_12(Ldoodle_js_package$.sjsir:205)
at org.mozilla.javascript.gen.Ldoodle_js_package__sjsir_7.call(Ldoodle_js_package$.sjsir)
at org.mozilla.javascript.optimizer.OptRuntime.call1(OptRuntime.java:32)
at org.mozilla.javascript.gen.Ldoodle_js_package__sjsir_7._c_anonymous_3(Ldoodle_js_package$.sjsir:13)
at org.mozilla.javascript.gen.Ldoodle_js_package__sjsir_7.call(Ldoodle_js_package$.sjsir)
at org.mozilla.javascript.optimizer.OptRuntime.call2(OptRuntime.java:42)
at org.mozilla.javascript.gen.LMain__sjsir_4._c_anonymous_3(LMain$.sjsir:13)
at org.mozilla.javascript.gen.LMain__sjsir_4.call(LMain$.sjsir)
at org.mozilla.javascript.optimizer.OptRuntime.callProp0(OptRuntime.java:85)
at org.mozilla.javascript.gen.LMain__sjsir_4._c_anonymous_4(LMain$.sjsir:16)
at org.mozilla.javascript.gen.LMain__sjsir_4.call(LMain$.sjsir)
at org.mozilla.javascript.optimizer.OptRuntime.callProp0(OptRuntime.java:85)
at org.mozilla.javascript.gen.LMain__sjsir_4._c_anonymous_7(LMain$.sjsir:28)
at org.mozilla.javascript.gen.LMain__sjsir_4.call(LMain$.sjsir)
at org.mozilla.javascript.optimizer.OptRuntime.callProp0(OptRuntime.java:85)
at org.mozilla.javascript.gen._Users_psnively_Desktop_doodle_js_target_scala_2_11_doodle_launcher_js_5._c_script_0(/Users/psnively/Desktop/doodle/js/target/scala-2.11/doodle-launcher.js:1)
at org.mozilla.javascript.gen._Users_psnively_Desktop_doodle_js_target_scala_2_11_doodle_launcher_js_5.call(/Users/psnively/Desktop/doodle/js/target/scala-2.11/doodle-launcher.js)
at org.mozilla.javascript.ContextFactory.doTopCall(ContextFactory.java:394)
at org.mozilla.javascript.ScriptRuntime.doTopCall(ScriptRuntime.java:3102)
at org.mozilla.javascript.gen._Users_psnively_Desktop_doodle_js_target_scala_2_11_doodle_launcher_js_5.call(/Users/psnively/Desktop/doodle/js/target/scala-2.11/doodle-launcher.js)
at org.mozilla.javascript.gen._Users_psnively_Desktop_doodle_js_target_scala_2_11_doodle_launcher_js_5.exec(/Users/psnively/Desktop/doodle/js/target/scala-2.11/doodle-launcher.js)
at org.mozilla.javascript.Context.evaluateString(Context.java:1078)
at org.scalajs.jsenv.rhino.package$ContextOps$.evaluateFile$extension(package.scala:21)
at org.scalajs.jsenv.rhino.RhinoJSEnv.org$scalajs$jsenv$rhino$RhinoJSEnv$$internalRunJS(RhinoJSEnv.scala:152)
at org.scalajs.jsenv.rhino.RhinoJSEnv$Runner.run(RhinoJSEnv.scala:60)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$.org$scalajs$sbtplugin$ScalaJSPluginInternal$$jsRun(ScalaJSPluginInternal.scala:358)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$37$$anonfun$apply$23$$anonfun$apply$24.apply(ScalaJSPluginInternal.scala:418)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$37$$anonfun$apply$23$$anonfun$apply$24.apply(ScalaJSPluginInternal.scala:412)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
[trace] Stack trace suppressed: run last doodleJS/compile:run for the full output.
java.lang.RuntimeException: Exception while running JS code: TypeError: Cannot call method "getElementById" of undefined (Ldoodle_js_package$.sjsir#205)
at scala.sys.package$.error(package.scala:27)
at org.scalajs.jsenv.rhino.RhinoJSEnv.org$scalajs$jsenv$rhino$RhinoJSEnv$$internalRunJS(RhinoJSEnv.scala:168)
at org.scalajs.jsenv.rhino.RhinoJSEnv$Runner.run(RhinoJSEnv.scala:60)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$.org$scalajs$sbtplugin$ScalaJSPluginInternal$$jsRun(ScalaJSPluginInternal.scala:358)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$37$$anonfun$apply$23$$anonfun$apply$24.apply(ScalaJSPluginInternal.scala:418)
at org.scalajs.sbtplugin.ScalaJSPluginInternal$$anonfun$37$$anonfun$apply$23$$anonfun$apply$24.apply(ScalaJSPluginInternal.scala:412)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
[trace] Stack trace suppressed: run last doodleJS/compile:run for the full output.
[error] (doodleJS/compile:run) Exception while running JS code: TypeError: Cannot call method "getElementById" of undefined (Ldoodle_js_package$.sjsir#205)
[error] Total time: 9 s, completed Mar 15, 2015 12:06:05 PM
Realistically, this is unsurprising, because the default Javascript runtime is Rhino, and with Doodle you really want to fastOptJS
anyway, so you can see the output in the browser. But so as to have run
or test
not crash, it might be good to at least make the default Javascript runtime be PhantomJS, so at least there is a "proper" DOM to render into.
Write a small library of common parametric curves:
Parametric curve should be A => Point
, where A
is Normalized
/ Angle
/ etc. as appropriate.
Allow writing val a = 50.degrees; -a
.
We should be able to perform arbitrary affine transforms (scale, rotate, shear, reflection) on images, allowing greater expressiveness.
Hi,
I did a small try with your latest commit (Release 0.9.4-SNAPSHOT), built locally using sbt publishLocal
and then tried using an ammonite script based on your example named PulsingCircle. When I tried to start it I got a very small window frame, not a 600x600 one, with nothing inside it, when I resize it, I can only see a small white rectangle, and everything else is black.
import $ivy.`org.creativescala::doodle:0.9.4-SNAPSHOT`
import cats.instances.all._
import doodle.core._
import doodle.syntax._
import doodle.java2d.effect._
import doodle.java2d._
import doodle.java2d.algebra._
import doodle.interact.syntax._
import monix.reactive.Observable
val frame = Frame.size(600, 600)
def circle(diameter: Int): Picture[Unit] =
Picture{ implicit algebra =>
algebra.circle(diameter.toDouble).strokeColor(Color.crimson).strokeWidth(3.0)
}
val animation: Observable[Picture[Unit]] =
Observable
.repeat(1)
.scan((3, 10)){ (state, _) =>
val (inc, diameter) = state
if(diameter >= 500) (-3, diameter - 3)
else if(diameter <= 10) (1, diameter + 3)
else (inc, diameter + inc)
}
.map{ case (_, d) => circle(d) }
val r = for {
canvas <- frame.canvas
frames = animation
} yield frames.animateFrames(canvas)
r.unsafeRunAsync(println _)
scala.io.StdIn.readLine("Enter to exit...") // required when run as a script
You really did a great job with the doodle API, this is exactly the kind of vector graphics I was looking for :)
We should make the library part of Doodle available somewhere (possibly Bintray).
Doing so would require reorganising the codebase a little, splitting libraries from examples. Not sure what the implications are for JS either.
Because I've been unable to build doodle's master as a dependency in sbt (#16), I simply cloned the repo, sbt publish-local
, and then I'm executing my code with scala -classpath doodle_2.11.jar mycode.scala
When mycode.scala looks like this:
import doodle.core._
import doodle.syntax._
import doodle.jvm._
import doodle.examples._
object Test {
def main(args: Array[String]) {
Circle(10).draw
}
}
I get the error could not find implicit value for parameter interpreter: doodle.backend.Interpreter
. I noticed that I can add this import at the top:
import doodle.backend.StandardInterpreter._
and that no longer seems to be a problem. Instead, I get error: could not find implicit value for parameter canvas: doodle.backend.Canvas
.
Is scala -classpath
not the right way to be referencing the library or are there additional import statements I need since the 0.1 release? Or, perhaps I need to create a Canvas object and pass it to something?
The Bitmap
algebra provides some basic support for loading bitmaps but it is limited in the following ways:
Picture
(strictly speaking, it is loaded as the F
in the algebra but in the current implementation this basically means Picture
). This means we don't have a separate type representing bitmaps, which is a problem because bitmaps are distinct from the vector graphics model of the rest of Doodle and we can do interesting operations on them that don't make sense on vector images and vice versa.What it should do instead:
Bitmap
algebra should be parameterized by at least one type, the type of bitmaps, and possibly by an effect type. I don't think we've abstracted over effect types elsewhere in Doodle so the effect type can be ignored if it adds too much complexity.Bitmap
algebra so that the main method reflects the possibility of failure (e.g. returns an IO
, Either
, or a Try
. Either
is better as it doesn't fix the error to be an Exception
, and so works across different backends with different error handling strategies. Could abstract over error handling with the MonadError
type class but I'm not convinced it's warranted.)IO
is best as that is used in other parts of Doodle.Bitmap
to load a bitmap when you don't care about errors.ToPicture
to convert a particular bitmap type into the backend specific Picture
type.Concretely, we're looking at an interface like
trait LoadBitmap[Specifier, Bitmap] {
def load(specifier: Specifier): IO[Bitmap]
}
where Specifier
is the type of information that we used to specify where to find a bitmap (e.g. File
on the JVM, String
on the browser) and Bitmap
is the type of the resulting bitmap (BufferedImage
on the JVM.) Backend specific implementations could provide their own utility methods that augment the above.
Here are some links to relevant backend information:
MoveTo in paths doesn't seem to be working as expected for me - here is a quick example from sbt console
to show you what I mean:
val c = implicitly[doodle.backend.Canvas].asInstanceOf[doodle.jvm.Java2DCanvas]
val i = implicitly[doodle.backend.Interpreter].asInstanceOf[doodle.backend.StandardInterpreter]
def axes(xLen: Int, yLen: Int) = Path(List(
MoveTo(Vec(-xLen/2,0)),
LineTo(Vec(xLen/2,0)),
MoveTo(Vec(0,-yLen/2)),
LineTo(Vec(0,yLen/2))))
axes(100,100).draw(i,c)
val linePath = Path(List(
MoveTo(Vec(0,0)),
LineTo(Vec(10,10))
))
linePath.draw(i,c)
I'm trying to add support for rotating images and drawing circular arcs in paths, and ran into this while testing. If you can give me a pointer to what might be wrong, id be happy to take a crack at fixing it!
Golden testing is the technique we use for end-to-end testing. The essential idea is to compare output against known good output.
We have golden tests for the Java2D backend, comparing rendered PNGs. We should add tests for the SVG backend. It's not immediately clear how to implement this. We could compare textual output but this is a bit fragile to non-semantic changes. We also cannot easily visualize the output to make sure it's actually correct (or see where it is wrong). Ideally we'd find some Java package that can render SVG to a bitmap.
Shared mutable state strikes again. The fill color for the wee circle reappears as the stroke color for the large circle. Maria from ScalaBridge just found this.
circle(5).fillColor(Color.red) on circle(10) above circle(20)
I didn't look very closely but deleting this line fixes it.
Not submitting as a PR because I'm not convinced I understand what's going on.
Doodle currently builds for 2.11 only. It would be great to cross build to both 2.11 and 2.12
Text is not properly located on the y-axis on the SVG backend. Need to better understanding the coordinates used in the SVGRect
returned from getBBox
to understand how to get the correct layout.
Create a stable Java2D specific method to convert a Picture
to a BufferedImage
. This will allow fun pixel art in conjunction with #85. This should be a new kind of effect type class, I think.
We already have a ToPicture
type class. Perhaps FromPicture
is the natural counterpart here? Not sure they would be symmetric though---rendering a picture is an effect but converting to a picture is not.
From most recent run:
[error] bad option: '-Ypartial-unification'
[error] bad option: '-Ypartial-unification'
[error] (doodleJVM/compile:compileIncremental) Compilation failed
[error] (doodleJS/compile:compileIncremental) Compilation failed
[error] Total time: 31 s, completed Mar 9, 2017 8:17:38 PM
I'm not getting the following image when running the same snippet of code:
Here's what I see:
And when overlaid on a larger image ((image on Rectangle(200, 200)).draw
):
The only thing that draws as it should as per the example output is the decagon, which makes sense because it's symmetric. It might be related to issue #20.
It would be nice to build Doodle Scaladoc.
Text in SVG supports separate stroke and fill. They way we currently draw text on Java2D uses the stroke color as the fill. We can get more control over text rendering using the TextLayout
API, and in particular either the draw
or getOuline
methods on TextLayout
.
I'm attempting to configure my project's build.sbt so that it depends on doodle's master GitHub branch so that I can make use of your latest additions to animations:
lazy val doodleProject = RootProject(uri("https://github.com/underscoreio/doodle.git"))
//lazy val doodleProject = RootProject( uri("git://github.com/dragos/dupcheck.git") )
lazy val root = (project in file("."))
.settings(
name := "gridworld",
version := "1.0",
scalaVersion := "2.11.7",
//resolvers += "Underscore Training" at "https://dl.bintray.com/underscoreio/training",
//libraryDependencies += "underscoreio" %% "doodle" % "0.1.0",
initialCommands in console := """
|import doodle.core._
|import doodle.syntax._
|import doodle.jvm._
|import doodle.examples._
""".trim.stripMargin
)
.dependsOn(doodleProject)
With this configuration, running sbt
will give this error:
[info] Loading project definition from /Users/admin/.sbt/0.13/staging/bc969347ae8d770695a8/doodle/project
java.lang.AssertionError: assertion failed: Directory /local/dev/gridworld/js is not contained in build root /Users/admin/.sbt/0.13/staging/bc969347ae8d770695a8/doodle
at scala.Predef$.assert(Predef.scala:179)
at sbt.Load$.checkProjectBase(Load.scala:345)
at sbt.Load$.sbt$Load$$resolve$1(Load.scala:380)
at sbt.Load$$anonfun$resolveBase$1.apply(Load.scala:383)
at sbt.Load$$anonfun$resolveBase$1.apply(Load.scala:383)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.AbstractTraversable.map(Traversable.scala:105)
at sbt.Load$.projects(Load.scala:407)
at sbt.Load$.loaded(Load.scala:308)
at sbt.Load$.loadAll(Load.scala:334)
at sbt.Load$.loadURI(Load.scala:289)
at sbt.Load$.load(Load.scala:285)
at sbt.Load$.load(Load.scala:276)
at sbt.Load$.apply(Load.scala:130)
at sbt.Load$.defaultLoad(Load.scala:36)
at sbt.BuiltinCommands$.doLoadProject(Main.scala:481)
at sbt.BuiltinCommands$$anonfun$loadProjectImpl$2.apply(Main.scala:475)
at sbt.BuiltinCommands$$anonfun$loadProjectImpl$2.apply(Main.scala:475)
at sbt.Command$$anonfun$applyEffect$1$$anonfun$apply$2.apply(Command.scala:58)
at sbt.Command$$anonfun$applyEffect$1$$anonfun$apply$2.apply(Command.scala:58)
at sbt.Command$$anonfun$applyEffect$2$$anonfun$apply$3.apply(Command.scala:60)
at sbt.Command$$anonfun$applyEffect$2$$anonfun$apply$3.apply(Command.scala:60)
at sbt.Command$.process(Command.scala:92)
at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:98)
at sbt.MainLoop$$anonfun$1$$anonfun$apply$1.apply(MainLoop.scala:98)
at sbt.State$$anon$1.process(State.scala:184)
at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:98)
at sbt.MainLoop$$anonfun$1.apply(MainLoop.scala:98)
at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
at sbt.MainLoop$.next(MainLoop.scala:98)
at sbt.MainLoop$.run(MainLoop.scala:91)
at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:70)
at sbt.MainLoop$$anonfun$runWithNewLog$1.apply(MainLoop.scala:65)
at sbt.Using.apply(Using.scala:24)
at sbt.MainLoop$.runWithNewLog(MainLoop.scala:65)
at sbt.MainLoop$.runAndClearLast(MainLoop.scala:48)
at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:32)
at sbt.MainLoop$.runLogged(MainLoop.scala:24)
at sbt.StandardMain$.runManaged(Main.scala:53)
at sbt.xMain.run(Main.scala:28)
at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:109)
at xsbt.boot.Launch$.withContextLoader(Launch.scala:128)
at xsbt.boot.Launch$.run(Launch.scala:109)
at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:35)
at xsbt.boot.Launch$.launch(Launch.scala:117)
at xsbt.boot.Launch$.apply(Launch.scala:18)
at xsbt.boot.Boot$.runImpl(Boot.scala:41)
at xsbt.boot.Boot$.main(Boot.scala:17)
at xsbt.boot.Boot.main(Boot.scala)
[error] java.lang.AssertionError: assertion failed: Directory /local/dev/gridworld/js is not contained in build root /Users/admin/.sbt/0.13/staging/bc969347ae8d770695a8/doodle
[error] Use 'last' for the full log.
I'm new to sbt, so I could easily be doing something wrong. However, if I switch out the RootProject
with the example given in the sbt docs, then running sbt
works just fine:
lazy val doodleProject = RootProject( uri("git://github.com/dragos/dupcheck.git") )
Note that I'm a scala noob. It seems likely that I'm missing something that would be obvious if I was more familiar with the language and its packaging conventions. Anyway, updating my build.sbt and attempting the README commands results in:
[info] Loading project definition from C:\code\scratch\scala\scala-scratch\project
[info] Set current project to hello-world (in build file:/C:/code/scratch/scala/scala-scratch/)
> console
[info] Starting scala interpreter...
[info]
Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_144).
Type in expressions for evaluation. Or try :help.
scala> (circle(10) fillColor Color.red).draw
<console>:12: error: not found: value circle
(circle(10) fillColor Color.red).draw
^
<console>:12: error: not found: value Color
(circle(10) fillColor Color.red).draw
Which looks like unresolved symbols; I managed to fix that:
scala> import doodle.core._
import doodle.core._
scala> (circle(10) fillColor Color.red).draw
<console>:15: error: not found: value circle
(circle(10) fillColor Color.red).draw
Well, sort of. Looking at the example code it seems that circle
may have been moved to Image.circle
?
scala> (Image.circle(10) fillColor Color.red).draw
<console>:15: error: value draw is not a member of doodle.core.Image
(Image.circle(10) fillColor Color.red).draw
^
??? I managed to get a different error message following another import:
scala> import doodle.syntax._
import doodle.syntax._
scala> (Image.circle(10) fillColor Color.red).draw
<console>:18: error: could not find implicit value for parameter draw: doodle.backend.Interpreter.Draw
(Image.circle(10) fillColor Color.red).draw
^
I wonder if I need to import a backend, but none of doodle.backend._
, doodle.jvm
, nor doodle.jvm._
manage to get past this error.
I am very new to this library. I got a book "Creative Scala"; to follow this book, I need to install this library. I added the dependent library in my build.sbt file.
libraryDependencies += "creativescala.org" %% "doodle" % "0.9.0-SNAPSHOT"
But build does not work, it says the library is not available in MAVEN repository.
I tried it to create a JAR file from your source code, still I could not build it.
Is there any work *.jar file, so that I can directly use in my sample project.
Thanks alot !
Reinstate PDF rendering. There are several libraries that allow one to use a Graphics2D
object (the Java2D drawing interface) that will render to PDF:
Given the example solution code:
def star(sides: Int, skip: Int, radius: Double) = {
val centerAngle = 360.degrees * skip / sides
val elements = (0 to sides) map { index =>
LineTo(Vec.polar(centerAngle * index, radius))
}
Path(elements) lineWidth 2
}
produces the following star for me:
with the following code piece: draw(star(10, 3, 100))
Scala.js artifacts are not published due to some configuration error that results in the following:
java.lang.RuntimeException: error uploading to
https://api.bintray.com/maven/noelwelsh/maven/maven/underscoreio/doodle_sjs0.6_2.11
/a78e60eee4873ec2328fe748f49023226c98635d-SNAPSHOT/doodle_sjs0.6_2.11-
a78e60eee4873ec2328fe748f49023226c98635d-SNAPSHOT.pom:
{"message":"Provided artifact path does not comply with Maven's convention"}
(Manual line breaks added for readability above.)
Somebody with too much time on their hands needs to dig into the build to work out what is going wrong.
Basic support for charts exists on feature/plotting
. This currently supports only scatter plots, and 2D numeric data. I'd like to implement bar charts as the next chart type. This requires supporting categorical data.
Longer term we'll need more complex data types. Part of the work here is exploring different representations. A non-goal, at this point, is to support multiple plots / series per chart.
Here are some of the tasks:
Series
to support categorical dataSince we want to allow direct access to the Canvas
API it could do with being a bit more featureful. Being able to draw a circle would be a very useful method. SVG can draw a circle directly. Java2D cannot but there is code showing how to convert a circle to a Bezier curve in the backend already.
Other methods might be useful. We can open separate issues for them.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.