From 1713bdd3b2184a73e025198a98acf983c6b7c1db Mon Sep 17 00:00:00 2001 From: Siddharth Banga <91724657+VOSID8@users.noreply.github.com> Date: Mon, 1 Apr 2024 04:50:53 +0530 Subject: [PATCH 1/4] Integrated Doodle SVG Documentation --- .vscode/settings.json | 5 ++ build.sbt | 4 +- circle.png | Bin 0 -> 2732 bytes docs/src/pages/algebra/basic-with-text.png | Bin 2866 -> 2747 bytes docs/src/pages/directory.conf | 3 +- docs/src/pages/svg/README.md | 63 ++++++++++++++++++ .../doodle/examples/ConcentricCircles.scala | 39 +++++++++++ .../scala/doodle/examples/DoodleLogo.scala | 46 +++++++++++++ .../doodle/examples/ParametricSpiral.scala | 45 +++++++++++++ .../scala/doodle/examples/PulsingCircle.scala | 43 ++++++++++++ .../doodle/examples/TextPositioning.scala | 43 ++++++++++++ package-lock.json | 13 ++++ package.json | 16 +++++ 13 files changed, 317 insertions(+), 3 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 circle.png create mode 100644 docs/src/pages/svg/README.md create mode 100644 examples/js/src/main/scala/doodle/examples/ConcentricCircles.scala create mode 100644 examples/js/src/main/scala/doodle/examples/DoodleLogo.scala create mode 100644 examples/js/src/main/scala/doodle/examples/ParametricSpiral.scala create mode 100644 examples/js/src/main/scala/doodle/examples/PulsingCircle.scala create mode 100644 examples/js/src/main/scala/doodle/examples/TextPositioning.scala create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..32cfc61d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.watcherExclude": { + "**/target": true + } +} \ No newline at end of file diff --git a/build.sbt b/build.sbt index b5aa6f68..345d2588 100644 --- a/build.sbt +++ b/build.sbt @@ -150,9 +150,9 @@ lazy val docs = val dest1 = mdocOut.value val dest2 = (laikaSite / target).value val cmd1 = - s"npx tailwindcss -i ${src.toString}/creative-scala.css -o ${dest1.toString}/creative-scala.css" + s"cmd /c npx tailwindcss -i ${src.toString}/creative-scala.css -o ${dest1.toString}/creative-scala.css" val cmd2 = - s"npx tailwindcss -i ${src.toString}/creative-scala.css -o ${dest2.toString}/creative-scala.css" + s"cmd /c npx tailwindcss -i ${src.toString}/creative-scala.css -o ${dest2.toString}/creative-scala.css" cmd1 ! cmd2 ! diff --git a/circle.png b/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..a7e359d8d75c4d5ade1a175713f55cf541b087e5 GIT binary patch literal 2732 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 CTS|-o literal 0 HcmV?d00001 diff --git a/docs/src/pages/algebra/basic-with-text.png b/docs/src/pages/algebra/basic-with-text.png index 4968ed7291ff13324bfa8c18dad9635590a92c6e..a86ec174f33d965e20e577031e970759969d0e99 100644 GIT binary patch literal 2747 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 L#0FMrx4{Bob#8hef3!A z^f7{20)9$#*4S7nGTrSgCHTDYrqq4`u{=_87lZ7eK zTyGBYoQs-gr>AIosSK>Mv1Fo7rk6SLY`8f|^8AM+F&%FEv>P%1OD;3vwQtL-id}h|4ZSnpt6cH(FYh!l6o}K_3{HG7?^yYyyx5*kLddGVA2OPEO z`?A_5>mu|^jYatOU}Lev+moMXcd4;@)WoRY73+Zp5ej~zz#k0dsO|iX2`puzk=8`# z1efzRmJ5O_wDV6}A-`B0q1L?KSS+Rt70~q3xi?)EH{I&S7>al#fjw+xJx``QI!hs5 zpiz+VP1KaV?X*+rvTM(9<}$eRQLBb?sJe%3(dD?a5G!d!p=i1UohM zHe@b0aI_MJr7sTCD0ChiQ}RGAx-QjnX2~118~l=VYnK%efC9A!uoVT`<$%wHiL~bx z?u7&TN(=f^*IIG(%eug&nhUCHxnRmv8|6794Ss`=cu7c*ZWPJyZin2rMk7D)1rWIL zN15u8rrDxIt)z3PuSNj`c}co)4u9>Cr%4egOI>bwlX|Wp8ZU?jI^T8kxH2( z0L;1SY5caxyl$5h@+7k{M2Y0^IFW}bPYxql&#GvM_Bd#{sSBbNXgcZHUBNG^0#7Z9 zPTuFH!$?6=tzB1Y=Ytn2 zHdGW#mw7k^JlHPyR*-s>Zpr2nxrMY_-D6i_U(561!AwCjwKQT|>pd2)AW8nonNy5* zgQ?_f7hncBzQWQXQV19P+hw&hXu6RA;P0yYu5snDUsVh)Z4n&xy=k>-#XioEJtTV> zQHx7cb?ON&b)fS~558C2hj{ua6Z+0G;{`ZBfmq@@%VjB7_iO+0k6({@+E%+?dB59P zNd3tbzTMu^b$xvTL6K<(k$+N=dY zM*o%|aAl~s_Otdv%t?Kwss_&F}Q<=MvHT8!Kv#Vu3mV5*jb&I#^{qB?Hcr|Mo|dJP(R(R!Msx4W1kCUuEwEnUYFx z)-8>^hJ&z-9Jz%L_r;f$BX&1lfg9+&&yH)CoYB>&xmVcww6YEb$ETLDHP0@LNuDzDTjFPer@4SKqRJh82|%;PedtsMYrQFW*^sX`1agl0B18~*am zxH+Rf!`$3liqrC$eyKkU-0#L1uXk(;4{7pHw92!AR}Oos-yZx^+eANP=~06kbWan1 z<<9b}o(cEc=3nXpzJEMH-PWQWv=c;W{WVgcV6y_}EzOo*=gH%Z8OGijP69IeD>e?T zPR3$c{XLJBYC@Ux@ZQaDV_R1oocz}E^ddg~bzQEQ=MFAQ)5p&1ajw$`xt_P^=^V$Y z)>y7Qy$j_Bxh4GiAGLfwm7pW%K)QEQrF1A~BMvuE|D-U#6Z}mqtSyc^OUo~79o*K} zJnTZw(Q$0V_%(Tq8&)TdUIRox^rP8t-Q#7J!tLMRozujUn!eAnb<;zutehG# z{W}Nydn_MF^v|iA!MU9gfwf)ikut}cp8ESJcq}Hf)t5#ZtrsQd=`D|Q!^@mY>sGom z6ql$K1sLWihsT$&IEEN8DEK?g>1M4jn%pKR=oa$zWYBDn*hFX({ort4GS{b4khexz zS2auSO7b1w>8OacneH0kzpRR|A{TV_Mp?}n-goJLs&1UATX06#a2Uhf7;C}dq;*3F z;S$)z7*4JngDm0&FOX&e9JwW>n_nfPwTiqc&QLdfa57~7Ew!bj1SYBNzrk3V65Bca z3*?MT`IetQ(S{(VusG_M0!qwM}^G3kmK=8^0)RghbE7q3>G=f(D{ zo1(r?ZmqXx$&33o`&69#H)Z@uUFB?A)x!n^)^E(JTJPt$J&K& z9ms`yX#=g+L*b6U|H(Q2$u^ZCJb$&$aIwYg>|#{YyPr_x8FNt`BJkVX=zRk9@K{_{ zYeTR*4)EEfw;>o;KfgxI;^L7HR%}3d(IpsNSYn|;5_EA`0#Q-`-%iABO9a9_gy^CY z3khD;iLRO*R`)&VoWDqpj|bEXm365kXKP$0!|*-k0Vvnlz3o^7*%aP+3k?&D>nn?S zGO^nyQS0cjhzd!T@zY9Cg>Dgvr_~+lLV?#R<5U+#w<`{#hj`<9POw+p3}M9x+>sDy zC-5*Tl|#WJO&a4Oh;fy{bc{1TnFc~IUvtwnFQ4B$r`)ewnqI5+oc7%D?}#JD1P7>` zM$Gu0G*EC4^&I_8i9u8_767CdCgeWGucMvG10lbfuU|g)q-%7L7slXEfAJ7d49$Se z*^3aBozD4vdDLy#Jnn7SCXIDD+r8=28Nxug0y&Y(}1KE7nh_baUf} +``` + +then you can create a `Frame` referring to it with + +``` scala mdoc:silent +val frame = Frame("svg-root") +``` + +Now suppose you have a picture called `thePicture`. You can draw it using the frame you just created like so + +``` scala +thePicture.drawWithFrame(frame) +``` + +The rendered SVG will appear where the element is positioned on your web page. + + +## Running on the JVM + +On the JVM you can't draw SVG to the screen. Use the `java2d` backend for that instead. However you can write SVG output in the usual way. + + +## Examples + +The source for these examples is [in the repository](https://github.com/creativescala/doodle-svg/tree/main/examples/src/main/scala). + +### Concentric Circles +@:doodle("concentric-circles", "ConcentricCircles.draw") + +### Text Positioning +@:doodle("text-positioning", "TextPositioning.draw") + +### Doodle Logo +@:doodle("doodle-logo", "DoodleLogo.draw") + +### Pulsing Circle +@:doodle("pulsing-circle", "PulsingCircle.draw") + +### Parametric Spiral +@:doodle("parametric-spiral", "ParametricSpiral.draw") diff --git a/examples/js/src/main/scala/doodle/examples/ConcentricCircles.scala b/examples/js/src/main/scala/doodle/examples/ConcentricCircles.scala new file mode 100644 index 00000000..1f4d0b5a --- /dev/null +++ b/examples/js/src/main/scala/doodle/examples/ConcentricCircles.scala @@ -0,0 +1,39 @@ +/* + * Copyright 2015 Creative Scala + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package doodle +package svg + +import doodle.core._ +import doodle.svg._ +import doodle.syntax.all._ +import scala.scalajs.js.annotation._ +import cats.effect.unsafe.implicits.global + +@JSExportTopLevel("ConcentricCircles") +object ConcentricCircles { + def circles(count: Int): Picture[Unit] = + if (count == 0) Picture.circle(20).fillColor(Color.hsl(0.degrees, 0.7, 0.6)) + else + Picture + .circle(count.toDouble * 20.0) + .fillColor(Color.hsl((count * 15).degrees, 0.7, 0.6)) + .under(circles(count - 1)) + + @JSExport + def draw(mount: String) = + circles(7).drawWithFrame(Frame(mount)) +} diff --git a/examples/js/src/main/scala/doodle/examples/DoodleLogo.scala b/examples/js/src/main/scala/doodle/examples/DoodleLogo.scala new file mode 100644 index 00000000..3215e26d --- /dev/null +++ b/examples/js/src/main/scala/doodle/examples/DoodleLogo.scala @@ -0,0 +1,46 @@ +/* + * Copyright 2015 Creative Scala + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package doodle +package svg + +import doodle.core._ +import doodle.core.font._ +import doodle.svg._ +import doodle.syntax.all._ +import scala.scalajs.js.annotation._ +import cats.effect.unsafe.implicits.global + +@JSExportTopLevel("DoodleLogo") +object DoodleLogo { + val font = + Font.defaultSansSerif.size(FontSize.points(22)).weight(FontWeight.bold) + val logo: Picture[Unit] = + (0.to(10)) + .map(i => + Picture + .text("Doodle SVG") + .font(font) + .fillColor(Color.hotpink.spin(10.degrees * i.toDouble)) + .at(i * 3.0, i * -3.0) + ) + .toList + .allOn + + @JSExport + def draw(mount: String) = + logo.drawWithFrame(Frame(mount)) +} diff --git a/examples/js/src/main/scala/doodle/examples/ParametricSpiral.scala b/examples/js/src/main/scala/doodle/examples/ParametricSpiral.scala new file mode 100644 index 00000000..67b8d252 --- /dev/null +++ b/examples/js/src/main/scala/doodle/examples/ParametricSpiral.scala @@ -0,0 +1,45 @@ + +import doodle.core._ +import doodle.svg._ +import doodle.syntax.all._ +import scala.scalajs.js.annotation._ +import cats.effect.unsafe.implicits.global + +@JSExportTopLevel("ParametricSpiral") +object ParametricSpiral { + + def parametricSpiral(angle: Angle): Point = + Point((Math.exp(angle.toTurns) - 1) * 200, angle) + + def drawCurve( + points: Int, + marker: Point => Picture[Unit], + curve: Angle => Point + ): Picture[Unit] = { + // Angle.one is one complete turn. I.e. 360 degrees + val turn = Angle.one / points.toDouble + def loop(count: Int): Picture[Unit] = { + count match { + case 0 => + val pt = curve(Angle.zero) + marker(pt).at(pt) + case n => + val pt = curve(turn * count.toDouble) + marker(pt).at(pt).on(loop(n - 1)) + } + } + + loop(points) + } + + @JSExport + def draw(id: String): Unit = { + val marker = (point: Point) => + Picture + .circle(point.r * 0.125 + 7) + .fillColor(Color.red.spin(point.angle / 4.0)) + .noStroke + + drawCurve(20, marker, parametricSpiral _).drawWithFrame(Frame(id)) + } +} diff --git a/examples/js/src/main/scala/doodle/examples/PulsingCircle.scala b/examples/js/src/main/scala/doodle/examples/PulsingCircle.scala new file mode 100644 index 00000000..58e486f0 --- /dev/null +++ b/examples/js/src/main/scala/doodle/examples/PulsingCircle.scala @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Creative Scala + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package doodle +package svg + +import doodle.core._ +import doodle.svg._ +import doodle.syntax.all._ +import doodle.interact.syntax.all._ +import scala.scalajs.js.annotation._ +import cats.effect.unsafe.implicits.global + +@JSExportTopLevel("PulsingCircle") +object PulsingCircle { + def circle(count: Double): Picture[Unit] = + Picture + .circle(2 * count + 10) + .fillColor(Color.hsl((count * 5).degrees, 0.7, 0.6)) + + @JSExport + def draw(mount: String) = + 0.0 + .upToIncluding(72.0) + .map(c => circle(c)) + .forSteps(120) + .andThen(_ => 72.0.upToIncluding(0.0).map(c => circle(c)).forSteps(120)) + .repeatForever + .animate(Frame(mount).withSize(72 * 2 + 10, 72 * 2 + 10)) +} diff --git a/examples/js/src/main/scala/doodle/examples/TextPositioning.scala b/examples/js/src/main/scala/doodle/examples/TextPositioning.scala new file mode 100644 index 00000000..044f2036 --- /dev/null +++ b/examples/js/src/main/scala/doodle/examples/TextPositioning.scala @@ -0,0 +1,43 @@ +/* + * Copyright 2015 Creative Scala + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package doodle +package svg + +import doodle.core._ +import doodle.core.font._ +import doodle.svg._ +import doodle.syntax.all._ +import scala.scalajs.js.annotation._ +import cats.effect.unsafe.implicits.global + +@JSExportTopLevel("TextPositioning") +object TextPositioning { + val font = Font.defaultSansSerif.size(FontSize.points(18)) + def text(string: String): Picture[Unit] = + Picture.text(string).font(font).fillColor(Color.hotpink) + + val textPositioning: Picture[Unit] = + text("Above") + .above( + text("Center").on(Picture.circle(100).strokeWidth(3.0)) + ) + .above(text("Below")) + + @JSExport + def draw(mount: String) = + textPositioning.drawWithFrame(Frame(mount)) +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..497f1bef --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "doodle", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "doodle", + "version": "1.0.0", + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..cb24432a --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "doodle", + "version": "1.0.0", + "description": "Copyright [Noel Welsh](http://noelwelsh.com).", + "main": "tailwind.config.js", + "directories": { + "doc": "docs", + "example": "examples" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} From 567d9bdb2d15f4869b9458db621b993b2724b0e6 Mon Sep 17 00:00:00 2001 From: Siddharth Banga <91724657+VOSID8@users.noreply.github.com> Date: Mon, 1 Apr 2024 04:59:28 +0530 Subject: [PATCH 2/4] Removed cmd /c --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 345d2588..b5aa6f68 100644 --- a/build.sbt +++ b/build.sbt @@ -150,9 +150,9 @@ lazy val docs = val dest1 = mdocOut.value val dest2 = (laikaSite / target).value val cmd1 = - s"cmd /c npx tailwindcss -i ${src.toString}/creative-scala.css -o ${dest1.toString}/creative-scala.css" + s"npx tailwindcss -i ${src.toString}/creative-scala.css -o ${dest1.toString}/creative-scala.css" val cmd2 = - s"cmd /c npx tailwindcss -i ${src.toString}/creative-scala.css -o ${dest2.toString}/creative-scala.css" + s"npx tailwindcss -i ${src.toString}/creative-scala.css -o ${dest2.toString}/creative-scala.css" cmd1 ! cmd2 ! From c7da78d1537ea140ac81980c3a83a05bc22a8569 Mon Sep 17 00:00:00 2001 From: Siddharth Banga <91724657+VOSID8@users.noreply.github.com> Date: Mon, 1 Apr 2024 05:16:45 +0530 Subject: [PATCH 3/4] Minor change with SVG Documentation --- .vscode/settings.json | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 32cfc61d..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "files.watcherExclude": { - "**/target": true - } -} \ No newline at end of file From b2696c3b7fa52dfe954ca72fda8682888b30b618 Mon Sep 17 00:00:00 2001 From: Siddharth Banga <91724657+VOSID8@users.noreply.github.com> Date: Tue, 2 Apr 2024 19:42:11 +0530 Subject: [PATCH 4/4] formatted the code --- .gitignore | 2 ++ .../js/src/main/scala/doodle/examples/ParametricSpiral.scala | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f3043b21..2c5c2f37 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,7 @@ docs/src/main/mdoc/api docs/src/pages/**/*.png + ### SublimeText ### doodle.sublime-project # cache files for sublime text @@ -141,5 +142,6 @@ local.properties .metals .bloop project/metals.sbt +.vscode .sbt-hydra-history diff --git a/examples/js/src/main/scala/doodle/examples/ParametricSpiral.scala b/examples/js/src/main/scala/doodle/examples/ParametricSpiral.scala index 67b8d252..8f8d394e 100644 --- a/examples/js/src/main/scala/doodle/examples/ParametricSpiral.scala +++ b/examples/js/src/main/scala/doodle/examples/ParametricSpiral.scala @@ -1,4 +1,3 @@ - import doodle.core._ import doodle.svg._ import doodle.syntax.all._