How to build a 2d density chart with React and D3.
2d density chart
A 2D density chart is a graphical representation of data that uses color to show the concentration of data points in a given area. It shows the combined distribution of two quantitative variables. 2D density charts are often used in statistical analysis and data mining to identify trends, patterns, and correlations in the data.
In this tutorial, we will use the d3.js and React libraries to build a 2D density chart. It starts by describing how the data should be organized and how to initialize the Density2d component. It then explains how to prepare the data and compute bins. Once this is done, it shows how to render the shapes and suggests a few variations. 🙇♂️.
A 2d density chart is basically a variation of the scatterplot, useful when the amount of data points is huge. As a result, it shares the same data structure.
The data is an array of object. For each object, at least 2 properties are required: x and y. The value of x is the position of the datapoint on the horizontal axis. The value of y is linked with the vertical axis.
const data = [
+How to build a 2d density chart with React and D3.
2d density chart
A 2D density chart is a graphical representation of data that uses color to show the concentration of data points in a given area. It shows the combined distribution of two quantitative variables. 2D density charts are often used in statistical analysis and data mining to identify trends, patterns, and correlations in the data.
In this tutorial, we will use the d3.js and React libraries to build a 2D density chart. It starts by describing how the data should be organized and how to initialize the Density2d component. It then explains how to prepare the data and compute bins. Once this is done, it shows how to render the shapes and suggests a few variations. 🙇♂️.
A 2d density chart is basically a variation of the scatterplot, useful when the amount of data points is huge. As a result, it shares the same data structure.
The data is an array of object. For each object, at least 2 properties are required: x and y. The value of x is the position of the datapoint on the horizontal axis. The value of y is linked with the vertical axis.
const data = [
{
x: 2,
y: 4
@@ -78,4 +78,4 @@
}
I'm in the process of writing a complete blog post on the topic. Subscribe to the project to know when it's ready.
2D Density inspiration
If you're looking for inspiration to create your next 2D Density, note that dataviz-inspiration.com showcases many examples. Definitely the best place to get ... inspiration!
dataviz-inspiration.com showcases hundreds of stunning dataviz projects. Have a look to get some ideas on how to make your 2D Density looks good!
The hexbin representation above is just one member of a family of graphics allowing to study the combined distribution of two quantitative variables. You can read more about the existing variations in the data to viz project.
To put it in a nutshell, 2d histogram, Gaussian KDE, 2d density and Contour charts are the most common variations. It is of course possible to build them all using react and d3.js.
Here is an example with a contounr chart based on the same dataset than the previous example.
Contour chart made with React and D3.js.
ToDomake the contour chart above looks better
ToDoadd examples for 2d histograms and other variations
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/404.html b/404.html
index 46020f2d..7ba9bea7 100644
--- a/404.html
+++ b/404.html
@@ -1,4 +1,4 @@
-How to build a scatter plot with React and D3.
Oh No! (404)
It looks like the place you are looking for does not exist 🙈
The countries with the highest vulnerability to climate change have the lowest CO2 emissions
All countries sorted by their vulnerability and readiness to climate change. The size shows the CO2 emission per person in that country.
Reproduction of a chart originally published by Data Wrapper using react and d3.js.
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
+How to build a scatter plot with React and D3.
Oh No! (404)
It looks like the place you are looking for does not exist 🙈
The countries with the highest vulnerability to climate change have the lowest CO2 emissions
All countries sorted by their vulnerability and readiness to climate change. The size shows the CO2 emission per person in that country.
Reproduction of a chart originally published by Data Wrapper using react and d3.js.
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data with gmail.com. You can also subscribe to the newsletter to know when I publish more content!
\ No newline at end of file
diff --git a/_next/static/Qn9JDBrmHpswodUUyZzEd/_buildManifest.js b/_next/static/Qn9JDBrmHpswodUUyZzEd/_buildManifest.js
new file mode 100644
index 00000000..021862b5
--- /dev/null
+++ b/_next/static/Qn9JDBrmHpswodUUyZzEd/_buildManifest.js
@@ -0,0 +1 @@
+self.__BUILD_MANIFEST=function(s,a,c,e,t,i,o,r,n,p,u,d,l,h,b,g,f,m,k,j,v,x,w,z,y,_,I,B,F,A,D){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,"static/chunks/2718-c1b4ae8aebf23716.js",a,o,"static/chunks/pages/index-d41f25467ee6dcf3.js"],"/2d-density-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/2d-density-plot-8a8df282839cbf77.js"],"/404":[s,c,t,a,e,o,m,"static/css/8a734e64c19c3976.css","static/chunks/pages/404-083d849d0ce45b06.js"],"/_error":["static/chunks/pages/_error-82b79221b9ed784b.js"],"/about":[s,c,t,a,e,o,b,"static/chunks/pages/about-8505a607369c3630.js"],"/all":[s,c,a,e,o,u,k,"static/chunks/pages/all-c5ea439386fed3d0.js"],"/animation":[s,c,a,e,o,u,k,"static/chunks/pages/animation-fa9dfe1d4e131eb9.js"],"/arc-diagram":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/arc-diagram-8c80fd0c10cfac1b.js"],"/area-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/area-plot-850e2af7f558eaea.js"],"/articles":[s,c,a,e,o,b,"static/chunks/pages/articles-4f71b8e4bef1386a.js"],"/barplot":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/barplot-00f75722a80a9adb.js"],"/boxplot":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/boxplot-27510a56d1e5db92.js"],"/bubble-map":[s,c,t,i,p,a,e,o,n,u,j,h,"static/chunks/pages/bubble-map-623301ff0f5c7875.js"],"/bubble-plot":[s,c,t,i,p,a,e,o,u,m,w,z,"static/css/ec7558f4d3e32e69.css","static/chunks/pages/bubble-plot-b5d354230244be84.js"],"/build-axis-with-react":[s,c,t,i,a,e,o,r,"static/chunks/pages/build-axis-with-react-38ba08684038bf02.js"],"/cartogram":[s,c,a,e,o,b,"static/chunks/pages/cartogram-3909805a96300cc2.js"],"/chord-diagram":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/chord-diagram-157be7aad86575fb.js"],"/choropleth-map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/choropleth-map-07055d4a58480514.js"],"/circular-barplot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/circular-barplot-dba2b21bfe0f2586.js"],"/circular-packing":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/circular-packing-c42dfa9a290456fc.js"],"/connected-scatter-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/connected-scatter-plot-8d9a8ddc1c0f3a7b.js"],"/connection-map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/connection-map-68a98e8e6bd1aa65.js"],"/correlogram":[s,c,t,i,a,e,o,"static/css/d54486714a313ae1.css","static/chunks/pages/correlogram-2094d57c1eb2fa41.js"],"/course/animation/dealing-with-path":[s,c,t,p,f,a,e,"static/css/56c7a0691f59768b.css","static/chunks/pages/course/animation/dealing-with-path-ef89d156bc300c89.js"],"/course/animation/enter-update-exit":[s,c,p,a,e,g,"static/chunks/pages/course/animation/enter-update-exit-59c9c6f667ced3e4.js"],"/course/animation/introduction":[s,c,t,p,a,e,v,g,"static/chunks/pages/course/animation/introduction-b6604c2146389f42.js"],"/course/animation/project":[s,c,t,p,a,e,v,g,"static/chunks/pages/course/animation/project-63faeae783f2c633.js"],"/course/animation/react-spring-for-dataviz":[s,c,i,p,l,a,e,d,"static/chunks/pages/course/animation/react-spring-for-dataviz-e01b8eea46ee56f4.js"],"/course/animation/scatterplot":[s,c,t,i,p,a,e,w,d,"static/chunks/pages/course/animation/scatterplot-5735416f3e48abb1.js"],"/course/axis/axis-variations":[s,c,a,e,g,"static/chunks/pages/course/axis/axis-variations-e8cf5bd8282a7c5f.js"],"/course/axis/axis-with-d3":[s,c,t,i,a,e,d,"static/chunks/pages/course/axis/axis-with-d3-f644056be4487108.js"],"/course/axis/bottom-axis":[s,c,t,i,l,a,e,d,"static/chunks/pages/course/axis/bottom-axis-bb532bb0bbba2e40.js"],"/course/axis/introduction":[s,c,t,a,e,g,"static/chunks/pages/course/axis/introduction-66ef24957a309b5d.js"],"/course/axis/margin-and-translation":[s,c,i,l,a,e,d,"static/chunks/pages/course/axis/margin-and-translation-e481dc8c6abf9ce8.js"],"/course/axis/project":[s,c,t,i,a,e,z,d,"static/chunks/pages/course/axis/project-3f188a1165fc56c7.js"],"/course/canvas/combining-svg-and-canvas":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/combining-svg-and-canvas-7dfb1617ad30a20c.js"],"/course/canvas/drawing-shapes-with-canvas":[s,c,i,l,a,e,d,"static/chunks/pages/course/canvas/drawing-shapes-with-canvas-b987979bb2ffc953.js"],"/course/canvas/introduction":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/introduction-9b7446a49771d4ce.js"],"/course/canvas/svg-path-in-canvas":[s,c,t,i,a,e,d,"static/chunks/pages/course/canvas/svg-path-in-canvas-ba361ca4364f5d2f.js"],"/course/hover-effect/css-descendant-selector":[s,c,t,i,l,a,e,u,"static/css/8666b20defb3e011.css","static/chunks/pages/course/hover-effect/css-descendant-selector-36ad6543af1f2621.js"],"/course/hover-effect/css-pseudo-class":[s,c,t,i,l,a,e,u,y,"static/css/69b5bd49186db9de.css","static/chunks/pages/course/hover-effect/css-pseudo-class-802774492109f763.js"],"/course/hover-effect/internal-state":[s,c,t,i,a,e,u,"static/css/f1e5f65ddf99e8f6.css","static/chunks/pages/course/hover-effect/internal-state-ff7118d79b1cc3cd.js"],"/course/hover-effect/introduction":[s,c,t,p,a,e,y,"static/css/0ec73f568dde8513.css","static/chunks/pages/course/hover-effect/introduction-d91fdd943b95d1ff.js"],"/course/hover-effect/link-two-graphs":[s,c,t,i,a,e,o,u,_,"static/css/c76003f718a0f9be.css","static/chunks/pages/course/hover-effect/link-two-graphs-fc8be979befb85d3.js"],"/course/hover-effect/toggle-class-in-js":[s,c,t,i,l,a,e,"static/css/f5258d81ed13d0d5.css","static/chunks/pages/course/hover-effect/toggle-class-in-js-fb21fb5b810c4b56.js"],"/course/introduction/initial-setup":[s,c,t,i,a,e,d,"static/chunks/pages/course/introduction/initial-setup-1a01dca02cbea214.js"],"/course/introduction/introduction-to-d3":[s,c,t,a,e,g,"static/chunks/pages/course/introduction/introduction-to-d3-6ded1ce234ed1b2c.js"],"/course/introduction/introduction-to-react":[s,c,a,e,g,"static/chunks/pages/course/introduction/introduction-to-react-a392c14cf58076cf.js"],"/course/introduction/js-dataviz-libraries":[s,c,i,a,e,d,"static/chunks/pages/course/introduction/js-dataviz-libraries-f7f28061427db698.js"],"/course/responsiveness/code-organization":[s,c,i,a,e,d,"static/chunks/pages/course/responsiveness/code-organization-4dee38ef916f6e9b.js"],"/course/responsiveness/common-pitfalls":[s,c,a,e,g,"static/chunks/pages/course/responsiveness/common-pitfalls-b052d1cc732e6cb4.js"],"/course/responsiveness/introduction":[s,c,t,i,a,e,d,"static/chunks/pages/course/responsiveness/introduction-638287c3a0c0f3e3.js"],"/course/responsiveness/use-dimension-hook":[s,c,i,a,e,d,"static/chunks/pages/course/responsiveness/use-dimension-hook-035fc5d826f40d64.js"],"/course/responsiveness/using-the-hook":[s,c,i,l,a,e,d,"static/chunks/pages/course/responsiveness/using-the-hook-bdd2dfdbaf2e4479.js"],"/course/scales/introduction":[s,c,i,a,e,I,d,"static/chunks/pages/course/scales/introduction-4801b90c32a802e0.js"],"/course/scales/linear-scale":[s,c,i,l,a,e,I,d,"static/chunks/pages/course/scales/linear-scale-744385fc0fee6ab5.js"],"/course/scales/other-scale-types":[s,c,t,i,l,a,e,d,"static/chunks/pages/course/scales/other-scale-types-6d076272a1d64e97.js"],"/course/scales/project":[s,c,t,i,a,e,d,"static/chunks/pages/course/scales/project-d5bc6bbb2a6c117b.js"],"/course/svg/d3-shape":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/d3-shape-6855634224ffd05f.js"],"/course/svg/introduction":[s,c,t,l,a,e,g,"static/chunks/pages/course/svg/introduction-cbc6f0c36a1a42ec.js"],"/course/svg/main-svg-elements":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/main-svg-elements-b67e94f54df7d5ea.js"],"/course/svg/path-element":[s,c,i,l,a,e,d,"static/chunks/pages/course/svg/path-element-ddeafb47c2680043.js"],"/course/svg/tips-and-tricks":[s,c,i,"static/chunks/2860-d038ef2b7795bb05.js",a,e,d,"static/chunks/pages/course/svg/tips-and-tricks-9a34a92abbedcff1.js"],"/course/tooltip/display-on-hover":[s,c,t,i,l,a,e,x,"static/css/530b699660279b3e.css","static/chunks/pages/course/tooltip/display-on-hover-e5794d0da9958032.js"],"/course/tooltip/introduction":[s,c,t,a,e,m,"static/css/b23f3515152ab10c.css","static/chunks/pages/course/tooltip/introduction-dd57bbe658e25a2e.js"],"/course/tooltip/project":[s,c,t,i,a,e,B,"static/css/e6721a776c502451.css","static/chunks/pages/course/tooltip/project-2f4d2ec670a5c6ec.js"],"/course/tooltip/templates":[s,c,t,a,e,m,x,"static/css/ec6f9e7260a78fe2.css","static/chunks/pages/course/tooltip/templates-e08fba51c8c643ca.js"],"/course/tooltip/tooltip-component":[s,c,i,l,a,e,d,"static/chunks/pages/course/tooltip/tooltip-component-be4ee12236b179e2.js"],"/cross-graph-highlight-interaction":[s,c,t,i,"static/chunks/8446-4892663fdb75b8e1.js",a,e,o,"static/css/507114ea18f6728e.css","static/chunks/pages/cross-graph-highlight-interaction-f4981236e3ce062b.js"],"/dataset-transition":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/dataset-transition-04f3ac5287b70e46.js"],"/dendrogram":[s,c,t,i,a,e,o,F,r,"static/chunks/pages/dendrogram-437272f9020c7aab.js"],"/density-plot":[s,c,t,i,a,e,o,n,A,r,"static/chunks/pages/density-plot-a9c9eae2588b0c6c.js"],"/donut":[s,c,t,i,p,f,a,e,o,n,"static/css/306a1a30c14677d4.css","static/chunks/pages/donut-f6c4704c8df5ae55.js"],"/example/arc-diagram-vertical":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/arc-diagram-vertical-ee4b8759645617e3.js"],"/example/barplot-data-transition-animation":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/example/barplot-data-transition-animation-3b43c38cc63954f8.js"],"/example/barplot-stacked-horizontal":[s,c,t,i,a,e,o,u,h,"static/chunks/pages/example/barplot-stacked-horizontal-88e863909d739272.js"],"/example/barplot-stacked-vertical":[s,c,t,a,e,o,u,k,"static/chunks/pages/example/barplot-stacked-vertical-1383a75f05139115.js"],"/example/boxplot-horizontal":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/boxplot-horizontal-ba359fa226e9e306.js"],"/example/boxplot-jitter":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/boxplot-jitter-c3aa852f6add3126.js"],"/example/circle-packing-with-d3-force":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/circle-packing-with-d3-force-91029646511643dc.js"],"/example/histogram-mirror":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-mirror-00743c0fa7e95ca8.js"],"/example/histogram-slider-bin-size":[s,c,t,a,e,o,D,"static/css/f7129d2d0aac0f23.css","static/chunks/pages/example/histogram-slider-bin-size-4dea62a699539ada.js"],"/example/histogram-small-multiple":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-small-multiple-794625c2d9f73b4e.js"],"/example/histogram-with-several-groups":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/histogram-with-several-groups-df434001b3f202b7.js"],"/example/line-chart-synchronized-cursors":[s,c,t,i,p,a,e,o,r,"static/chunks/pages/example/line-chart-synchronized-cursors-4533bf55dbbfc249.js"],"/example/network-diagram-with-colored-groups":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/network-diagram-with-colored-groups-87e8c79c8205e6f4.js"],"/example/population-pyramid":[t,p,"static/css/d71181803328322d.css","static/chunks/pages/example/population-pyramid-7f97eae907059157.js"],"/example/radar-chart-animation":[s,c,t,i,p,a,e,o,v,r,"static/chunks/pages/example/radar-chart-animation-43847f64fedbca97.js"],"/example/sankey-bump-chart":[s,c,t,a,e,o,b,"static/chunks/pages/example/sankey-bump-chart-e9c76dcf9dc5b58e.js"],"/example/scatterplot-basic-canvas":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/scatterplot-basic-canvas-4bc535863d92c309.js"],"/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection":[s,c,t,i,a,e,o,r,"static/chunks/pages/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection-ca83c451932a3cb2.js"],"/example/timeseries-moving-average":[s,c,t,i,a,e,o,u,"static/css/0051346e12b181a2.css","static/chunks/pages/example/timeseries-moving-average-09c989c1f87b1ea6.js"],"/fix-canvas-blurry-dataviz":[s,c,i,a,e,o,r,"static/chunks/pages/fix-canvas-blurry-dataviz-4dec33a6dd3d0b86.js"],"/heatmap":[s,c,t,i,a,e,o,n,B,"static/css/efd490e62b6b40d6.css","static/chunks/pages/heatmap-7fae042d715abd6d.js"],"/hexbin-map":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/hexbin-map-a930630d43a80673.js"],"/hierarchical-edge-bundling":[s,c,t,i,a,e,o,F,r,"static/chunks/pages/hierarchical-edge-bundling-13f282ff59e73fb9.js"],"/histogram":[s,c,t,i,p,a,e,o,n,u,D,"static/css/516fbb6bc1065354.css","static/chunks/pages/histogram-205eb50e1cb77334.js"],"/interactivity":[s,c,a,e,o,u,k,"static/chunks/pages/interactivity-54e994fb8fdc812d.js"],"/line-chart":[s,c,t,i,p,a,e,o,n,u,h,"static/chunks/pages/line-chart-c4caf24c6849ce57.js"],"/lollipop-plot":[s,c,t,i,p,a,e,o,n,u,"static/css/64f55f4f67c1b792.css","static/chunks/pages/lollipop-plot-790d82a18314bc66.js"],"/map":[s,c,t,i,a,e,o,n,j,r,"static/chunks/pages/map-62403d2e3e8e93d8.js"],"/network-chart":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/network-chart-00db4310eaf287bd.js"],"/parallel-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/parallel-plot-fc5eb664e86a8c8a.js"],"/pie-plot":[s,c,t,i,p,f,a,e,o,n,"static/css/7b5f8c9d016b3f7c.css","static/chunks/pages/pie-plot-a1b092b9d7149b8b.js"],"/radar-chart":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/radar-chart-d9c6a5e9d64ddec6.js"],"/react-d3-dataviz-course":[s,c,a,e,o,b,"static/chunks/pages/react-d3-dataviz-course-f771d9fed9984c64.js"],"/react-dataviz-animation-with-react-spring":[s,c,t,p,a,e,o,b,"static/chunks/pages/react-dataviz-animation-with-react-spring-241bf24a4a74f8f0.js"],"/ridgeline":[s,c,t,i,a,e,o,n,u,A,h,"static/chunks/pages/ridgeline-11cba4c161729478.js"],"/sandbox":["static/chunks/pages/sandbox-1ce071da1e108df4.js"],"/sankey-diagram":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/sankey-diagram-6d10b62979b8ba19.js"],"/scatter-plot":[s,c,t,i,a,e,o,n,u,m,x,_,"static/css/1973cdfb43563a59.css","static/chunks/pages/scatter-plot-fdef5fee6c505ccb.js"],"/shape-morphism-for-dataviz-with-react":[s,c,t,i,p,f,a,e,o,r,"static/chunks/pages/shape-morphism-for-dataviz-with-react-e737e8b242667de2.js"],"/stacked-area-plot":[s,c,t,i,p,f,a,e,o,n,"static/css/c79e5809ea8fe7eb.css","static/chunks/pages/stacked-area-plot-0f8f8a283b797557.js"],"/stacked-barplot-with-negative-values":[s,c,t,a,e,o,b,"static/chunks/pages/stacked-barplot-with-negative-values-01f393a6847a4218.js"],"/streamchart":[s,c,t,i,p,f,a,e,o,n,"static/css/003d5c48b04543ca.css","static/chunks/pages/streamchart-f7a9d802105a768e.js"],"/subscribe":[s,c,a,e,o,b,"static/chunks/pages/subscribe-cd6b3b49e0189ed1.js"],"/timeseries":[s,c,t,i,p,a,e,o,u,h,"static/chunks/pages/timeseries-0ec0a86b7c04bf8f.js"],"/treemap":[s,c,t,i,a,e,o,"static/css/25919ae4f53719a0.css","static/chunks/pages/treemap-68194c557d023a94.js"],"/typescript-d3-axis":[s,c,t,i,a,e,o,r,"static/chunks/pages/typescript-d3-axis-4533d45cdd503e53.js"],"/violin-plot":[s,c,t,i,a,e,o,n,r,"static/chunks/pages/violin-plot-1f925576e0efd35f.js"],"/viz-from-the-future":[s,c,a,e,o,"static/css/8d4c0e152872e92c.css","static/chunks/pages/viz-from-the-future-7590f2db599d31cf.js"],"/voronoi":[s,c,t,i,a,e,o,n,u,h,"static/chunks/pages/voronoi-0969554f6c933799.js"],"/what-is-a-color":[s,c,a,e,o,b,"static/chunks/pages/what-is-a-color-2ceba4025243af3a.js"],"/wordcloud":[s,c,t,i,a,e,o,r,"static/chunks/pages/wordcloud-eca0caf76708bed1.js"],sortedPages:["/","/2d-density-plot","/404","/_app","/_error","/about","/all","/animation","/arc-diagram","/area-plot","/articles","/barplot","/boxplot","/bubble-map","/bubble-plot","/build-axis-with-react","/cartogram","/chord-diagram","/choropleth-map","/circular-barplot","/circular-packing","/connected-scatter-plot","/connection-map","/correlogram","/course/animation/dealing-with-path","/course/animation/enter-update-exit","/course/animation/introduction","/course/animation/project","/course/animation/react-spring-for-dataviz","/course/animation/scatterplot","/course/axis/axis-variations","/course/axis/axis-with-d3","/course/axis/bottom-axis","/course/axis/introduction","/course/axis/margin-and-translation","/course/axis/project","/course/canvas/combining-svg-and-canvas","/course/canvas/drawing-shapes-with-canvas","/course/canvas/introduction","/course/canvas/svg-path-in-canvas","/course/hover-effect/css-descendant-selector","/course/hover-effect/css-pseudo-class","/course/hover-effect/internal-state","/course/hover-effect/introduction","/course/hover-effect/link-two-graphs","/course/hover-effect/toggle-class-in-js","/course/introduction/initial-setup","/course/introduction/introduction-to-d3","/course/introduction/introduction-to-react","/course/introduction/js-dataviz-libraries","/course/responsiveness/code-organization","/course/responsiveness/common-pitfalls","/course/responsiveness/introduction","/course/responsiveness/use-dimension-hook","/course/responsiveness/using-the-hook","/course/scales/introduction","/course/scales/linear-scale","/course/scales/other-scale-types","/course/scales/project","/course/svg/d3-shape","/course/svg/introduction","/course/svg/main-svg-elements","/course/svg/path-element","/course/svg/tips-and-tricks","/course/tooltip/display-on-hover","/course/tooltip/introduction","/course/tooltip/project","/course/tooltip/templates","/course/tooltip/tooltip-component","/cross-graph-highlight-interaction","/dataset-transition","/dendrogram","/density-plot","/donut","/example/arc-diagram-vertical","/example/barplot-data-transition-animation","/example/barplot-stacked-horizontal","/example/barplot-stacked-vertical","/example/boxplot-horizontal","/example/boxplot-jitter","/example/circle-packing-with-d3-force","/example/histogram-mirror","/example/histogram-slider-bin-size","/example/histogram-small-multiple","/example/histogram-with-several-groups","/example/line-chart-synchronized-cursors","/example/network-diagram-with-colored-groups","/example/population-pyramid","/example/radar-chart-animation","/example/sankey-bump-chart","/example/scatterplot-basic-canvas","/example/scatterplot-tooltip-with-voronoi-for-closest-point-detection","/example/timeseries-moving-average","/fix-canvas-blurry-dataviz","/heatmap","/hexbin-map","/hierarchical-edge-bundling","/histogram","/interactivity","/line-chart","/lollipop-plot","/map","/network-chart","/parallel-plot","/pie-plot","/radar-chart","/react-d3-dataviz-course","/react-dataviz-animation-with-react-spring","/ridgeline","/sandbox","/sankey-diagram","/scatter-plot","/shape-morphism-for-dataviz-with-react","/stacked-area-plot","/stacked-barplot-with-negative-values","/streamchart","/subscribe","/timeseries","/treemap","/typescript-d3-axis","/violin-plot","/viz-from-the-future","/voronoi","/what-is-a-color","/wordcloud"]}}("static/chunks/2343-fd77427f6d276a64.js","static/chunks/8190-bc54b059aeb5396b.js","static/chunks/7754-86d7d1d8f1f2cbb4.js","static/chunks/3710-40e32244f56e9b7c.js","static/chunks/3950-38f2f386edd33f86.js","static/chunks/7823-7fe55b50301cbfb1.js","static/chunks/2594-166023395f0e3eec.js","static/css/3f9dc76f65000636.css","static/chunks/6588-a2783089ca9aec45.js","static/chunks/2719-ff70805b79da7e6d.js","static/chunks/693-fc37b082b568d0e9.js","static/css/0fa95a85e3c094ce.css","static/chunks/9484-bdf662975f6102ab.js","static/css/bf3bc3250ab9e729.css","static/css/2247407c30b587b7.css","static/css/4aaaca05e34861fe.css","static/chunks/7303-d19d970f114fd8c4.js","static/chunks/2428-70208576adca3a60.js","static/css/537902226fc25775.css","static/chunks/5450-70ab90718653e6b6.js","static/chunks/7620-4f0bd3369dc66a11.js","static/chunks/2-07cbe458739247a7.js","static/chunks/2411-ba1de7774cf99f17.js","static/chunks/4741-05bce33428fd0105.js","static/chunks/7934-43612e1419e096cd.js","static/chunks/9381-73035a3d64711aef.js","static/chunks/4969-a489b2c1a112f705.js","static/chunks/1751-b103fc296c796353.js","static/chunks/9041-4aa84b93adf8b1ac.js","static/chunks/5796-06dd83477ed03c0b.js","static/chunks/8469-8c55bcc40455636a.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
\ No newline at end of file
diff --git a/_next/static/yhQmaUA2CupVP4aP-kQFY/_ssgManifest.js b/_next/static/Qn9JDBrmHpswodUUyZzEd/_ssgManifest.js
similarity index 100%
rename from _next/static/yhQmaUA2CupVP4aP-kQFY/_ssgManifest.js
rename to _next/static/Qn9JDBrmHpswodUUyZzEd/_ssgManifest.js
diff --git a/_next/static/chunks/pages/course/animation/react-spring-for-dataviz-698baeeb98f0570f.js b/_next/static/chunks/pages/course/animation/react-spring-for-dataviz-698baeeb98f0570f.js
deleted file mode 100644
index 3b9f2929..00000000
--- a/_next/static/chunks/pages/course/animation/react-spring-for-dataviz-698baeeb98f0570f.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7206],{3460:function(e,i,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/animation/react-spring-for-dataviz",function(){return t(62404)}])},81122:function(e,i,t){"use strict";t.d(i,{$:function(){return a}});var n=t(85893),s=t(67294),r=t(59973),o=t(80615),l=t(88578),c=t(5);let a=e=>{let{VizComponent:i,vizName:t,height:a=400,maxWidth:d=800,caption:h,fileToOpen:x}=e,[p,u]=(0,s.useState)(!1),j=(0,s.useRef)(null),m=(0,r.B)(j);return(0,n.jsx)("div",{style:{marginLeft:"-50vw",left:"50%"},className:"my-4 py-4 w-screen relative",children:p?(0,n.jsxs)("div",{className:"flex flex-col items-center justify-center w-full",children:[(0,n.jsx)("div",{style:{maxWidth:2e3},className:"w-full z-50",children:(0,n.jsx)(l.X,{vizName:t,fileToOpen:x})}),(0,n.jsx)("div",{className:"flex justify-center mt-2",children:(0,n.jsx)(c.z,{size:"sm",onClick:()=>u(!p),children:"Hide Sandbox"})})]}):(0,n.jsxs)("div",{className:"flex flex-col items-center justify-center",children:[(0,n.jsx)("div",{className:"bg-gray-100 bg-opacity-50 w-screen flex justify-center z-50 pointer-events-none",children:(0,n.jsx)("div",{style:{height:a,width:"100%",maxWidth:d},ref:j,className:"pointer-events-auto",children:(0,n.jsx)(i,{height:a,width:m.width})})}),(0,n.jsx)(o.Y,{children:h}),(0,n.jsx)("div",{className:"flex justify-center",children:(0,n.jsx)(c.z,{size:"sm",onClick:()=>u(!p),children:"Show code"})})]})})}},88578:function(e,i,t){"use strict";t.d(i,{X:function(){return s}});var n=t(85893);t(67294);let s=e=>{let{vizName:i,height:t="500px",fileToOpen:s}=e;return console.log("rerendeeeerrrrr"),(0,n.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+i+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(s?"&module=/".concat(s):""),style:{width:"100%",height:t,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},47498:function(e,i,t){"use strict";t.d(i,{v:function(){return d}});var n=t(85893),s=t(7826),r=t(13742),o=t(61108),l=t(67294),c=t(5),a=t(77522);let d=e=>{let{exercises:i,localStorageId:t}=e,[d,h]=(0,l.useState)([]),[x,p]=(0,l.useState)("");return(0,l.useEffect)(()=>{let e=localStorage.getItem(t),n=e?JSON.parse(e):Array(i.length).fill("todo");h(n)},[]),(0,n.jsx)(s.UQ,{value:x,onValueChange:p,type:"single",collapsible:!0,className:"w-full",children:i.map((e,i)=>(0,n.jsxs)(s.Qd,{value:"item-"+i,children:[(0,n.jsx)(s.o4,{className:"no-decoration hover:bg-gray-50",children:(0,n.jsxs)("div",{className:"text-sm flex justify-start gap-2 items-center",children:[(0,n.jsx)("div",{className:(0,a.cn)("text-xs h-6 w-6 flex justify-center items-center rounded-full text-center leading-none","todo"===d[i]?"bg-gray-200":"failed"===d[i]?"bg-red-300":"bg-green-300"),children:(0,n.jsx)("span",{style:{transform:"translateX(1px)"},children:i+1})}),(0,n.jsx)("span",{children:e.title}),"ok"===d[i]&&(0,n.jsx)(r.Z,{size:16,className:"text-green-500"}),"failed"===d[i]&&(0,n.jsx)(o.Z,{size:16,className:"text-red-500"}),"todo"===d[i]&&(0,n.jsx)("span",{className:"text-gray-400 font-thin",children:"ToDo"})]})}),(0,n.jsxs)(s.vF,{children:[e.content,(0,n.jsxs)("div",{className:"flex justify-center gap-4",children:[(0,n.jsx)(c.z,{variant:"outline",onClick:()=>{let e=[...d];e[i]="failed",h(e),localStorage.setItem(t,JSON.stringify(e)),p("")},children:"Failed"}),(0,n.jsxs)(c.z,{onClick:()=>{let e=[...d];e[i]="ok",h(e),localStorage.setItem(t,JSON.stringify(e)),p("")},children:["Done",(0,n.jsx)("span",{className:"ml-2",children:"\uD83C\uDF89"})]})]})]})]}))})}},13400:function(e,i,t){"use strict";t.d(i,{q:function(){return a}});var n=t(85893),s=t(22725),r=t(67294),o=t(88578),l=t(8117),c=t(5);let a=e=>{let{exercise:i}=e,[t,a]=(0,r.useState)(!1);(0,r.useEffect)(()=>{let e=e=>{"Escape"===e.key&&a(!1)};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[]);let h=(0,n.jsx)(o.X,{vizName:i.practiceSandbox,height:t?"100%":"500px",fileToOpen:i.fileToOpen}),x=(0,n.jsx)(o.X,{vizName:i.solutionSandbox,height:t?"100%":"500px",fileToOpen:i.fileToOpen});return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)(l.C,{children:"To Do"}),(0,n.jsx)("div",{className:"mt-4",children:i.toDo})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)(l.C,{children:"Why it matters"}),(0,n.jsx)("div",{className:"mt-4 pl-4",children:i.whyItMatters})]})]}),(0,n.jsxs)(s.mQ,{defaultValue:"practice",className:"relative",children:[(0,n.jsxs)("div",{className:"flex justify-center items-center",children:[(0,n.jsxs)(s.dr,{children:[(0,n.jsx)(s.SP,{value:"practice",children:"Practice"}),(0,n.jsx)(s.SP,{value:"solution",children:"Solution"})]}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c.z,{size:"sm",variant:"outline",onClick:()=>a(!0),children:"Show full screen"})})]}),(0,n.jsx)(s.nU,{value:"practice",children:t?(0,n.jsx)(d,{setIsFullScreen:a,sandbox:h}):(0,n.jsx)("div",{className:"my-4",children:h})}),(0,n.jsx)(s.nU,{value:"solution",children:t?(0,n.jsx)(d,{setIsFullScreen:a,sandbox:x}):(0,n.jsx)("div",{className:"my-4",children:x})})]})]})},d=e=>{let{sandbox:i,setIsFullScreen:t}=e;return(0,n.jsxs)("div",{className:"fixed h-screen inset-0 flex justify-center items-center",children:[(0,n.jsx)("div",{className:"absolute inset-0 w-full h-full bg-white/80"}),(0,n.jsxs)("div",{className:"relative w-11/12 h-4/5",children:[i,(0,n.jsx)("div",{className:"w-full mt-2 flex justify-center items-center gap-2",children:(0,n.jsxs)("div",{className:"relative",children:[(0,n.jsx)(c.z,{onClick:()=>t(!1),variant:"destructive",children:"Leave Fullscreen mode"}),(0,n.jsxs)("span",{className:"absolute w-96 ml-2 text-gray-500 text-xs mt-3",children:["You can also press ",(0,n.jsx)("code",{children:"Esc"})]})]})})]})]})}},41843:function(e,i,t){"use strict";t.d(i,{p:function(){return a}});var n=t(85893),s=t(49700),r=t(63476),o=t(17414),l=t(41664),c=t.n(l);let a=e=>{let{children:i,title:t,seoDescription:l,previousTocItem:a,nextTocItem:d}=e;return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(o.A,{title:t,seoDescription:l}),(0,n.jsx)(s.Z,{}),(0,n.jsx)("div",{className:"wrapper",children:i}),(0,n.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[a?(0,n.jsxs)(c(),{href:a.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,n.jsx)("p",{children:a.name})]}):(0,n.jsx)("div",{className:"w-96"}),d&&(0,n.jsxs)(c(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,n.jsx)("p",{children:d.name})]})]}),(0,n.jsx)("div",{className:"wrapper",children:(0,n.jsx)(r.Z,{})})]})}},80615:function(e,i,t){"use strict";t.d(i,{Y:function(){return s}});var n=t(85893);let s=e=>{let{children:i}=e;return(0,n.jsx)("p",{className:"text-sm text-gray-500 max-w-xs italic text-center mt-4 font-light",children:i})}},3572:function(e,i,t){"use strict";t.d(i,{d:function(){return d}});var n=t(85893),s=t(32581),r=t(15660),o=t.n(r),l=t(67294),c=t(45993),a=t.n(c);let d=e=>{let{code:i}=e,[t,r]=(0,l.useState)(!1),c=(0,l.useRef)(null);(0,l.useEffect)(()=>{c.current&&o().highlightElement(c.current)},[c,i]);let d=(0,n.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(i),r(!0)},className:a().codeChunckCopyButton,children:t?"Copied":(0,n.jsx)(s.Z,{size:14,style:{padding:0}})});return(0,n.jsxs)("div",{className:"mb-6 relative",children:[(0,n.jsx)("pre",{className:"rounded-md line-numbers",children:(0,n.jsx)("code",{ref:c,className:"language-javascript",children:i})}),(0,n.jsx)("div",{className:a().copyButtonContainer,children:d})]})}},7826:function(e,i,t){"use strict";t.d(i,{Qd:function(){return a},UQ:function(){return c},o4:function(){return d},vF:function(){return h}});var n=t(85893),s=t(67294),r=t(47398),o=t(8971),l=t(77522);let c=r.fC,a=s.forwardRef((e,i)=>{let{className:t,...s}=e;return(0,n.jsx)(r.ck,{ref:i,className:(0,l.cn)("border-b",t),...s})});a.displayName="AccordionItem";let d=s.forwardRef((e,i)=>{let{className:t,children:s,...c}=e;return(0,n.jsx)(r.h4,{className:"flex mt-0 pb-0 font-normal",children:(0,n.jsxs)(r.xz,{ref:i,className:(0,l.cn)("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",t),...c,children:[s,(0,n.jsx)(o.Z,{className:"h-4 w-4 shrink-0 transition-transform duration-200"})]})})});d.displayName=r.xz.displayName;let h=s.forwardRef((e,i)=>{let{className:t,children:s,...o}=e;return(0,n.jsx)(r.VY,{ref:i,className:"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",...o,children:(0,n.jsx)("div",{className:(0,l.cn)("pb-4 pt-0",t),children:s})})});h.displayName=r.VY.displayName},22725:function(e,i,t){"use strict";t.d(i,{SP:function(){return a},dr:function(){return c},mQ:function(){return l},nU:function(){return d}});var n=t(85893),s=t(67294),r=t(60434),o=t(77522);let l=r.fC,c=s.forwardRef((e,i)=>{let{className:t,...s}=e;return(0,n.jsx)(r.aV,{ref:i,className:(0,o.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",t),...s})});c.displayName=r.aV.displayName;let a=s.forwardRef((e,i)=>{let{className:t,...s}=e;return(0,n.jsx)(r.xz,{ref:i,className:(0,o.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",t),...s})});a.displayName=r.xz.displayName;let d=s.forwardRef((e,i)=>{let{className:t,...s}=e;return(0,n.jsx)(r.VY,{ref:i,className:(0,o.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",t),...s})});d.displayName=r.VY.displayName},59973:function(e,i,t){"use strict";t.d(i,{B:function(){return s}});var n=t(67294);let s=e=>{let i=()=>({width:e.current?e.current.offsetWidth:0,height:e.current?e.current.offsetHeight:0}),[t,s]=(0,n.useState)(i),r=()=>{s(i())};return(0,n.useEffect)(()=>(window.addEventListener("resize",r),()=>window.removeEventListener("resize",r)),[]),(0,n.useEffect)(()=>{r()},[e]),t}},62404:function(e,i,t){"use strict";t.r(i),t.d(i,{default:function(){return T}});var n=t(85893),s=t(67294),r=t(43710),o=t(41843),l=t(11236),c=t(18496),a=t(81122),d=t(67208),h=t(86824);let x=e=>{let{position:i,color:t,preset:s}=e,r=(0,h.q_)({to:{position:i,color:t},config:h.vc[s]});return(0,n.jsx)(h.q.circle,{strokeWidth:2,fillOpacity:.4,r:38,cy:50,cx:r.position,stroke:r.color,fill:r.color})},p={border:"1px solid #9a6fb0",borderRadius:"3px",padding:"4px 8px",margin:"10px 2px",fontSize:14,color:"#9a6fb0",opacity:.7},u=e=>{let{width:i,height:t}=e,[r,o]=(0,s.useState)(40),[l,c]=(0,s.useState)("default");return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("button",{style:p,onClick:()=>o(40),children:"Left"}),(0,n.jsx)("button",{style:p,onClick:()=>o(i-40),children:"Right"}),(0,n.jsx)("select",{value:l,onChange:e=>{c(e.target.value)},style:{padding:"8px",fontSize:"16px"},children:["default","gentle","wobbly","stiff","slow","molasses"].map(e=>(0,n.jsx)("option",{value:e,children:e}))})]}),(0,n.jsx)("svg",{width:i,height:t,style:{overflow:"visible"},children:(0,n.jsx)(x,{position:r,color:40===r?"#9a6fb0":"#69b3a2",preset:l})})]})},j=e=>{let{width:i=700,height:t=400}=e;return(0,n.jsx)(u,{width:i,height:t})},m=e=>{let{position:i,color:t}=e,s=(0,h.q_)({to:{position:i,color:t},config:h.vc.molasses});return(0,n.jsx)(h.q.circle,{strokeWidth:2,fillOpacity:.4,r:s.position.to(e=>e/10),cy:50,cx:s.position,stroke:s.color,fill:s.color})},f={border:"1px solid #9a6fb0",borderRadius:"3px",padding:"4px 8px",margin:"10px 2px",fontSize:14,color:"#9a6fb0",opacity:.7},g=e=>{let{width:i,height:t}=e,[r,o]=(0,s.useState)(40);return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("button",{style:f,onClick:()=>o(40),children:"Left"}),(0,n.jsx)("button",{style:f,onClick:()=>o(i-40),children:"Right"})]}),(0,n.jsx)("svg",{width:i,height:t,style:{overflow:"visible"},children:(0,n.jsx)(m,{position:r,color:40===r?"#9a6fb0":"#69b3a2"})})]})},v=e=>{let{width:i=700,height:t=400}=e;return(0,n.jsx)(g,{width:i,height:t})},y=e=>{let{position:i,color:t}=e,s=(0,h.q_)({to:{position:i,color:t},config:h.vc.molasses});return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(h.q.circle,{strokeWidth:2,fillOpacity:.4,r:s.position.to(e=>e/10+10),cy:50,cx:s.position,stroke:s.color,fill:s.color}),(0,n.jsx)(h.q.text,{x:s.position,y:50,textAnchor:"middle",alignmentBaseline:"central",children:s.position.to(e=>Math.floor(e))})]})},b={border:"1px solid #9a6fb0",borderRadius:"3px",padding:"4px 8px",margin:"10px 2px",fontSize:14,color:"#9a6fb0",opacity:.7},w=e=>{let{width:i,height:t}=e,[r,o]=(0,s.useState)(40);return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("button",{style:b,onClick:()=>o(40),children:"Left"}),(0,n.jsx)("button",{style:b,onClick:()=>o(i-40),children:"Right"})]}),(0,n.jsx)("svg",{width:i,height:t,style:{overflow:"visible"},children:(0,n.jsx)(y,{position:r,color:40===r?"#9a6fb0":"#69b3a2"})})]})},k=e=>{let{width:i=700,height:t=400}=e;return(0,n.jsx)(w,{width:i,height:t})};var S=t(80615),N=t(3572),C=t(7826),D=t(13400),z=t(47498);function T(){let e=l.Y.find(e=>"/course/animation/react-spring-for-dataviz"===e.link);return e?(0,n.jsxs)(o.p,{title:e.name,seoDescription:"",nextTocItem:l.Y.find(e=>"/course/animation/scatterplot"===e.link),previousTocItem:l.Y.find(e=>"/course/animation/introduction"===e.link),children:[(0,n.jsx)(r.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["Web animations fall into two main categories: ",(0,n.jsx)("b",{children:"CSS"})," and"," ",(0,n.jsx)("b",{children:"spring-based"})," animations."]}),(0,n.jsxs)("p",{children:["In this lesson, we’ll explore ",(0,n.jsx)("b",{children:"react-spring"}),", a popular library for creating spring-based animations in React. Let’s see how to use it to bring our ",(0,n.jsx)("b",{children:"graph elements to life"}),"."]})]})}),(0,n.jsx)("h2",{children:"Animating a Circle"}),(0,n.jsxs)("p",{children:["Let’s start with something ",(0,n.jsx)("strong",{children:"simple"})," for this first lesson."]}),(0,n.jsx)("p",{children:"Our goal is to animate a circle moving smoothly from one position to another. Here’s what the final effect will look like:"}),(0,n.jsx)("div",{className:"border p-4 my-4",children:(0,n.jsx)(c.x,{width:650,height:100})}),(0,n.jsx)("p",{children:(0,n.jsx)("br",{})}),(0,n.jsx)("p",{children:"Pretty cool, right? \uD83D\uDE43"}),(0,n.jsxs)("p",{children:["To achieve this, we’ll use"," ",(0,n.jsx)("a",{href:"https://www.react-spring.dev",children:"react-spring"}),", the most popular JavaScript library for spring-based animations."]}),(0,n.jsx)("p",{children:(0,n.jsx)("br",{})}),(0,n.jsxs)("center",{children:[(0,n.jsx)("img",{src:"/img/react-spring-homepage.png",width:600}),(0,n.jsxs)(S.Y,{children:[(0,n.jsx)("code",{children:"react-spring"})," homepage. The most famous lib for javascript animation (28k stars on github)"]})]}),(0,n.jsx)("p",{children:(0,n.jsx)("br",{})}),(0,n.jsx)("h2",{children:"Full code"}),(0,n.jsxs)("p",{children:[(0,n.jsx)("code",{children:"react-spring"})," is incredibly powerful, but it can be a bit tricky to grasp, and I personally find its documentation a little unclear. \uD83D\uDE1E"]}),(0,n.jsxs)("p",{children:["For now, the two key features we need are the ",(0,n.jsx)("code",{children:"useSpring"})," ","hook and the ",(0,n.jsx)("code",{children:"animated"})," component."]}),(0,n.jsxs)("p",{children:["With these two tools, we can create a ",(0,n.jsx)("code",{children:"Circle"})," component that accepts a ",(0,n.jsx)("code",{children:"position"})," prop. Whenever a new"," ",(0,n.jsx)("code",{children:"position"})," value is passed, the circle smoothly transitions to its new location."]}),(0,n.jsxs)("p",{children:["Here’s how the ",(0,n.jsx)("code",{children:"Circle"})," component looks:"]}),(0,n.jsx)(N.d,{code:"\nimport { animated, useSpring } from 'react-spring';\n\nexport const Circle = ({ position }) => {\n\n const springProps = useSpring({\n to: {\n position: position\n },\n });\n\n return (\n \n );\n};\n\n "}),(0,n.jsx)("h2",{children:"Explanation"}),(0,n.jsxs)("p",{children:["In this code, we’re creating a simple ",(0,n.jsx)("code",{children:"Circle"})," component that renders ",(0,n.jsx)("strong",{children:"one circle"}),". The component takes a"," ",(0,n.jsx)("code",{children:"position"})," property, which controls the circle’s X position."]}),(0,n.jsxs)("p",{children:["Whenever this prop updates, the circle’s position will change, but it will happen ",(0,n.jsx)("strong",{children:"smoothly"}),"!"]}),(0,n.jsx)("p",{children:"Here’s a breakdown of what’s happening:"}),(0,n.jsx)("h3",{children:"\uD83D\uDE9A Import"}),(0,n.jsxs)("p",{children:["Once installed with a classic ",(0,n.jsx)("code",{children:"npm install react-spring"}),", we need to import:"]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"useSpring"}),": a hook that helps us create animated values."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"animated"}),":a special version of elements (like"," ",(0,n.jsx)("code",{children:""}),") that can be animated."]})]}),(0,n.jsxs)("h3",{children:["\uD83C\uDF38 Using ",(0,n.jsx)("code",{children:"useSpring"})]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["The ",(0,n.jsx)("code",{children:"useSpring"})," hook is used to define an animation. It accepts an object where we specify the properties to animate and how to animate them. In this case, we're animating the"," ",(0,n.jsx)("code",{children:"position"}),"."]}),(0,n.jsxs)("li",{children:["We now have access to ",(0,n.jsx)("code",{children:"springProps.position"}),". If the position changes from ",(0,n.jsx)("code",{children:"0"})," to ",(0,n.jsx)("code",{children:"100"}),","," ",(0,n.jsx)("code",{children:"springProps.position"})," will smoothly transition through values like 1, 3, 10, 15, and so on, until it reaches 100."," ",(0,n.jsx)("code",{children:"react-spring"})," handles the calculation of these intermediate values for us!"]})]}),(0,n.jsx)("h3",{children:"\uD83D\uDD17 Binding the Animation to the Circle"}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Instead of using a regular ",(0,n.jsx)("code",{children:"circle"})," SVG element, we use"," ",(0,n.jsx)("code",{children:"animated.circle"}),". React-spring provides its own animated version of all HTML and SVG elements!"]}),(0,n.jsxs)("li",{children:["Instead of passing ",(0,n.jsx)("code",{children:"position"})," directly to the"," ",(0,n.jsx)("code",{children:"cx"})," property, we pass ",(0,n.jsx)("code",{children:"springProps.position"}),", which contains all the intermediate values, ensuring the circle moves smoothly."]})]}),(0,n.jsx)(a.$,{vizName:"ReactSpringMostBasic",VizComponent:d.U,maxWidth:800,height:200,caption:"A very basic animation using react and react-spring.",fileToOpen:"Circle.tsx"}),(0,n.jsx)(C.UQ,{type:"single",collapsible:!0,children:(0,n.jsxs)(C.Qd,{value:"item-1",children:[(0,n.jsx)(C.o4,{children:"⚠️ Config object or function?"}),(0,n.jsxs)(C.vF,{children:[(0,n.jsxs)("p",{children:["There is something I find very confusing about useSpring hook. It can be used with a config object (like in my explanation), or"," ",(0,n.jsx)("b",{children:"with a function"}),"."]}),(0,n.jsxs)("p",{children:["You will see both in the"," ",(0,n.jsx)("a",{href:"https://www.react-spring.dev/docs/components/use-spring#usage",children:"documentation"}),", what might you feel... confused."]})]})]})}),(0,n.jsx)("h2",{children:"\uD83D\uDD25 Spring Config"}),(0,n.jsxs)("p",{children:["Spring animations follow physics laws to make the animation feel natural. There are three key properties you can control to adjust the feel of the animation: ",(0,n.jsx)("code",{children:"mass"}),", ",(0,n.jsx)("code",{children:"friction"}),", and"," ",(0,n.jsx)("code",{children:"tension"}),"."]}),(0,n.jsxs)("p",{children:["You can customize these properties in the ",(0,n.jsx)("code",{children:"useSpring"})," hook like this:"]}),(0,n.jsx)(N.d,{code:"\nconst springProps = useSpring({\n to: { position, color },\n config: {\n mass: 5,\n friction: 120,\n tension: 120,\n }\n});\n "}),(0,n.jsxs)("p",{children:["But honestly, I strongly advise using one of the"," ",(0,n.jsx)("strong",{children:"presets"})," provided by the library, as they offer great results right out of the box."]}),(0,n.jsx)("p",{children:"Check out the preset effects in the example below:"}),(0,n.jsx)(a.$,{vizName:"ReactSpringPresetValues",VizComponent:j,maxWidth:800,height:200,caption:(0,n.jsxs)("p",{children:[(0,n.jsx)("code",{children:"react-spring"})," offers a few presets for the animation feel. Try them in this sandbox!"]}),fileToOpen:"Circle.tsx"}),(0,n.jsx)("p",{children:"To use one of the presets, you can do something like this:"}),(0,n.jsx)(N.d,{code:"\nconst springProps = useSpring({\n position: 100,\n config: config.default\n});\n "}),(0,n.jsx)("h2",{children:"Deriving Values"}),(0,n.jsxs)("p",{children:["Animating a value directly using ",(0,n.jsx)("b",{children:"react-spring"}),", like we did for the position property, is straightforward."]}),(0,n.jsxs)("p",{children:["However, in data visualization, we often need to"," ",(0,n.jsx)("b",{children:"derive one value from another"}),"."]}),(0,n.jsxs)("p",{children:["For example, suppose we want the size of the circle to be proportional to the X position. You might think that we could simply use the"," ",(0,n.jsx)("code",{children:"springProps.position"})," value as a regular number, like this:"]}),(0,n.jsx)(N.d,{code:"\nreturn (\n \n);\n "}),(0,n.jsxs)("p",{children:["Instead, to achieve this, we need to use the ",(0,n.jsx)("code",{children:"to()"})," method of the ",(0,n.jsx)("code",{children:"springProps.position"})," property, like so:"]}),(0,n.jsx)(N.d,{code:"\nreturn (\n pos / 10)}\n />\n);\n "}),(0,n.jsxs)("p",{children:["This is called ",(0,n.jsx)("b",{children:"interpolation"})," in ",(0,n.jsx)("code",{children:"react-spring"})," ","terminology. You can learn more about it in the full documentation"," ",(0,n.jsx)("a",{href:"https://www.react-spring.dev/docs/advanced/interpolation",target:"_blank",rel:"noopener noreferrer",children:"here"}),"."]}),(0,n.jsx)("p",{children:"Let’s take a look at the result!"}),(0,n.jsx)(a.$,{vizName:"ReactSpringDerivingValue",VizComponent:v,maxWidth:800,height:200,caption:"Smooth animation where circle size is derived from X position.",fileToOpen:"Circle.tsx"}),(0,n.jsx)("h2",{children:"Animating Text"}),(0,n.jsxs)("p",{children:["So far, we’ve only animated numerical values—like smoothly transitioning the position from ",(0,n.jsx)("code",{children:"1"})," to ",(0,n.jsx)("code",{children:"100"}),"."]}),(0,n.jsxs)("p",{children:["But ",(0,n.jsx)("code",{children:"react-spring"})," is much more powerful than that! It can animate almost anything, including ",(0,n.jsx)("b",{children:"text"})," and ",(0,n.jsx)("b",{children:"colors"}),"!"]}),(0,n.jsx)("p",{children:"In the example below, watch how the number evolves progressively:"}),(0,n.jsx)(a.$,{vizName:"ReactSpringText",VizComponent:k,maxWidth:800,height:200,caption:"Demo: react-spring can also animate text, colors and so much more!",fileToOpen:"Circle.tsx"}),(0,n.jsx)("h2",{children:"Exercises"}),(0,n.jsx)(z.v,{localStorageId:e.link,exercises:[{title:(0,n.jsx)("span",{children:"Your first animated circle!"}),content:(0,n.jsx)(D.q,{exercise:I[0]})},{title:(0,n.jsx)("span",{children:"Opacity? \uD83D\uDC7B"}),content:(0,n.jsx)(D.q,{exercise:I[1]})},{title:(0,n.jsxs)("span",{children:["Let's make this ",(0,n.jsx)("code",{children:"div"})," moves"]}),content:(0,n.jsx)(D.q,{exercise:I[2]})},{title:(0,n.jsx)("span",{children:"Rotate this rect"}),content:(0,n.jsx)(D.q,{exercise:I[3]})},{title:(0,n.jsx)("span",{children:"Is it to heavy?"}),content:(0,n.jsx)(D.q,{exercise:I[4]})},{title:(0,n.jsx)("span",{children:"Three elements"}),content:(0,n.jsx)(D.q,{exercise:I[5]})}]})]}):null}let I=[{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Just applying the very basic usage we just learned"})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Create a ",(0,n.jsx)("code",{children:"Circle.tsx"})," file that makes a"," ",(0,n.jsx)("code",{children:"Circle"})," component"]}),(0,n.jsxs)("li",{children:["Create a ",(0,n.jsx)("code",{children:"position"})," state in ",(0,n.jsx)("code",{children:"Graph.tsx"}),". Each time the user click on the SVG area, this position must toggle between ",(0,n.jsx)("code",{children:"40"})," and ",(0,n.jsx)("code",{children:"width - 40"})]}),(0,n.jsxs)("li",{children:["Provide the position to the ",(0,n.jsx)("code",{children:"Circle"})," component. Render a circle at this ",(0,n.jsx)("code",{children:"x"})," position, animate its movement with"," ",(0,n.jsx)("code",{children:"react-spring"}),"."]})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleCircleSolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"react-spring can animate many sorts of values. Opacity is one of them, but text, and colors work too!"})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Same as previous exercise, but add a property for the"," ",(0,n.jsx)("code",{children:"opacity"}),"."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"opacity"})," must toggle between ",(0,n.jsx)("code",{children:"0.2"})," and"," ",(0,n.jsx)("code",{children:"1"})," depending on if the circle is on the left or on the right."]})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleCircleOpacitySolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:[(0,n.jsx)("code",{children:"react-spring"})," does not only work with SVG! HTML elements can be animated too!"]}),(0,n.jsxs)("p",{children:["note also that the spring can be made directly in the"," ",(0,n.jsx)("code",{children:"Graph"})," component. Making a separate component to organise your work is nice IMO, but not required."]})]}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["In ",(0,n.jsx)("code",{children:"Graph.tsx"}),", render a parent ",(0,n.jsx)("code",{children:"div"})," using the ",(0,n.jsx)("code",{children:"width"})," and ",(0,n.jsx)("code",{children:"height"})," provided at the top of the component instead of the usual SVG area."]}),(0,n.jsxs)("li",{children:["In this ",(0,n.jsx)("code",{children:"div"}),", render another ",(0,n.jsx)("code",{children:"div"}),". It must be square, have a ",(0,n.jsx)("code",{children:"backgroundColor"})," of ",(0,n.jsx)("code",{children:"red"})," ","and be absolutely positioned."]}),(0,n.jsxs)("li",{children:["Now make the red ",(0,n.jsx)("code",{children:"div"})," moves from right to left when user clicks on the parent div."]})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleDivSolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Just a bit of fun!"})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("ul",{children:(0,n.jsxs)("li",{children:["Use the ",(0,n.jsx)("code",{children:"rotate"})," property of a div to make the rectangle spin when it goes from one side to another!"]})})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleDivRotateSolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Spring physics matters!"})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Apply a mass of ",(0,n.jsx)("code",{children:"120"})," to the moving ",(0,n.jsx)("code",{children:"div"})]}),(0,n.jsx)("li",{children:"What happens? Why?"}),(0,n.jsxs)("li",{children:["Try to play with ",(0,n.jsx)("code",{children:"friction"})," and ",(0,n.jsx)("code",{children:"tension"})," too to get an intuition on how physics work."]})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleDivHeavySolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("p",{children:[(0,n.jsx)("code",{children:"delay"})," can give some cool effects to dataviz projects. But use it with care, you do not want to waste people time!"]})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Instead of 1 circle (exercise 1), render 3 animated circles."}),(0,n.jsx)("li",{children:"Use y positions of 50, 100, 150 respectively (you need to create a y prop in the Circle componetn)"}),(0,n.jsx)("li",{children:"Add a new property called delay to the Circle component. Give values of 10, 100 and 1000 to the 3 circles respectively."}),(0,n.jsx)("li",{children:"Use this delay value to delay the start of the animation: you can just pass it to the useSpring hook!"})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationMultiCircleDelaySolution",fileToOpen:"Graph.tsx"}]},18496:function(e,i,t){"use strict";t.d(i,{x:function(){return c}});var n=t(85893),s=t(67294),r=t(86824);let o=e=>{let{position:i,color:t}=e,s=(0,r.q_)({to:{position:i,color:t}});return(0,n.jsx)(r.q.circle,{strokeWidth:2,fillOpacity:.4,r:38,cy:50,cx:s.position,stroke:s.color,fill:s.color})},l={border:"1px solid #9a6fb0",borderRadius:"3px",padding:"4px 8px",margin:"10px 2px",fontSize:14,color:"#9a6fb0",opacity:.7},c=e=>{let{width:i,height:t}=e,[r,c]=(0,s.useState)(40);return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("button",{style:l,onClick:()=>c(40),children:"Left"}),(0,n.jsx)("button",{style:l,onClick:()=>c(i-40),children:"Right"})]}),(0,n.jsx)("svg",{width:i,height:t,children:(0,n.jsx)(o,{position:r,color:40===r?"#9a6fb0":"#69b3a2"})})]})}},67208:function(e,i,t){"use strict";t.d(i,{U:function(){return r}});var n=t(85893),s=t(18496);let r=e=>{let{width:i=700,height:t=400}=e;return(0,n.jsx)(s.x,{width:i,height:t})}},45993:function(e){e.exports={codeChunckCopyButton:"code-block_codeChunckCopyButton__yPrL_",copyButtonContainer:"code-block_copyButtonContainer__BrX9E"}},86824:function(e,i,t){"use strict";t.d(i,{q:function(){return n.q},q_:function(){return n.q_},to:function(){return n.to},vc:function(){return n.vc}});var n=t(2719)}},function(e){e.O(0,[2343,7754,7823,2719,9484,8190,3710,9774,2888,179],function(){return e(e.s=3460)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/_next/static/chunks/pages/course/animation/react-spring-for-dataviz-e01b8eea46ee56f4.js b/_next/static/chunks/pages/course/animation/react-spring-for-dataviz-e01b8eea46ee56f4.js
new file mode 100644
index 00000000..0c805c5e
--- /dev/null
+++ b/_next/static/chunks/pages/course/animation/react-spring-for-dataviz-e01b8eea46ee56f4.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[7206],{3460:function(e,i,t){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/animation/react-spring-for-dataviz",function(){return t(62404)}])},81122:function(e,i,t){"use strict";t.d(i,{$:function(){return a}});var n=t(85893),s=t(67294),r=t(59973),o=t(80615),c=t(88578),l=t(5);let a=e=>{let{VizComponent:i,vizName:t,height:a=400,maxWidth:d=800,caption:h,fileToOpen:x}=e,[p,u]=(0,s.useState)(!1),j=(0,s.useRef)(null),m=(0,r.B)(j);return(0,n.jsx)("div",{style:{marginLeft:"-50vw",left:"50%"},className:"my-4 py-4 w-screen relative",children:p?(0,n.jsxs)("div",{className:"flex flex-col items-center justify-center w-full",children:[(0,n.jsx)("div",{style:{maxWidth:2e3},className:"w-full z-50",children:(0,n.jsx)(c.X,{vizName:t,fileToOpen:x})}),(0,n.jsx)("div",{className:"flex justify-center mt-2",children:(0,n.jsx)(l.z,{size:"sm",onClick:()=>u(!p),children:"Hide Sandbox"})})]}):(0,n.jsxs)("div",{className:"flex flex-col items-center justify-center",children:[(0,n.jsx)("div",{className:"bg-gray-100 bg-opacity-50 w-screen flex justify-center z-50 pointer-events-none",children:(0,n.jsx)("div",{style:{height:a,width:"100%",maxWidth:d},ref:j,className:"pointer-events-auto",children:(0,n.jsx)(i,{height:a,width:m.width})})}),(0,n.jsx)(o.Y,{children:h}),(0,n.jsx)("div",{className:"flex justify-center",children:(0,n.jsx)(l.z,{size:"sm",onClick:()=>u(!p),children:"Show code"})})]})})}},88578:function(e,i,t){"use strict";t.d(i,{X:function(){return s}});var n=t(85893);t(67294);let s=e=>{let{vizName:i,height:t="500px",fileToOpen:s}=e;return console.log("rerendeeeerrrrr"),(0,n.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+i+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(s?"&module=/".concat(s):""),style:{width:"100%",height:t,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},47498:function(e,i,t){"use strict";t.d(i,{v:function(){return d}});var n=t(85893),s=t(7826),r=t(13742),o=t(61108),c=t(67294),l=t(5),a=t(77522);let d=e=>{let{exercises:i,localStorageId:t}=e,[d,h]=(0,c.useState)([]),[x,p]=(0,c.useState)("");return(0,c.useEffect)(()=>{let e=localStorage.getItem(t),n=e?JSON.parse(e):Array(i.length).fill("todo");h(n)},[]),(0,n.jsx)(s.UQ,{value:x,onValueChange:p,type:"single",collapsible:!0,className:"w-full",children:i.map((e,i)=>(0,n.jsxs)(s.Qd,{value:"item-"+i,children:[(0,n.jsx)(s.o4,{className:"no-decoration hover:bg-gray-50",children:(0,n.jsxs)("div",{className:"text-sm flex justify-start gap-2 items-center",children:[(0,n.jsx)("div",{className:(0,a.cn)("text-xs h-6 w-6 flex justify-center items-center rounded-full text-center leading-none","todo"===d[i]?"bg-gray-200":"failed"===d[i]?"bg-red-300":"bg-green-300"),children:(0,n.jsx)("span",{style:{transform:"translateX(1px)"},children:i+1})}),(0,n.jsx)("span",{children:e.title}),"ok"===d[i]&&(0,n.jsx)(r.Z,{size:16,className:"text-green-500"}),"failed"===d[i]&&(0,n.jsx)(o.Z,{size:16,className:"text-red-500"}),"todo"===d[i]&&(0,n.jsx)("span",{className:"text-gray-400 font-thin",children:"ToDo"})]})}),(0,n.jsxs)(s.vF,{children:[e.content,(0,n.jsxs)("div",{className:"flex justify-center gap-4",children:[(0,n.jsx)(l.z,{variant:"outline",onClick:()=>{let e=[...d];e[i]="failed",h(e),localStorage.setItem(t,JSON.stringify(e)),p("")},children:"Failed"}),(0,n.jsxs)(l.z,{onClick:()=>{let e=[...d];e[i]="ok",h(e),localStorage.setItem(t,JSON.stringify(e)),p("")},children:["Done",(0,n.jsx)("span",{className:"ml-2",children:"\uD83C\uDF89"})]})]})]})]}))})}},13400:function(e,i,t){"use strict";t.d(i,{q:function(){return h}});var n=t(85893),s=t(22725),r=t(88578),o=t(8117),c=t(5),l=t(41664),a=t.n(l),d=t(77522);let h=e=>{let{exercise:i}=e,t=(0,n.jsx)(r.X,{vizName:i.practiceSandbox,height:"500px",fileToOpen:i.fileToOpen}),l=(0,n.jsx)(r.X,{vizName:i.solutionSandbox,height:"500px",fileToOpen:i.fileToOpen});return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)(o.C,{children:"To Do"}),(0,n.jsx)("div",{className:"mt-4",children:i.toDo})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)(o.C,{children:"Why it matters"}),(0,n.jsx)("div",{className:"mt-4 pl-4",children:i.whyItMatters})]})]}),(0,n.jsxs)(s.mQ,{defaultValue:"practice",className:"relative",children:[(0,n.jsx)("div",{className:"flex justify-center items-center",children:(0,n.jsxs)(s.dr,{children:[(0,n.jsx)(s.SP,{value:"practice",children:"Practice"}),(0,n.jsx)(s.SP,{value:"solution",children:"Solution"})]})}),(0,n.jsxs)(s.nU,{value:"practice",children:[(0,n.jsx)("div",{className:"my-4",children:t}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(a(),{className:(0,c.d)({size:"sm",variant:"destructive"}),href:"/sandbox?vizName="+i.practiceSandbox,target:"_blank",children:"Show full screen"})})]}),(0,n.jsxs)(s.nU,{value:"solution",children:[(0,n.jsx)("div",{className:"my-4",children:l}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(a(),{className:(0,d.cn)((0,c.d)({size:"sm",variant:"destructive"}),"no-underline"),href:"/sandbox?vizName="+i.solutionSandbox,target:"_blank",children:"Show full screen"})})]})]})]})}},41843:function(e,i,t){"use strict";t.d(i,{p:function(){return a}});var n=t(85893),s=t(49700),r=t(63476),o=t(17414),c=t(41664),l=t.n(c);let a=e=>{let{children:i,title:t,seoDescription:c,previousTocItem:a,nextTocItem:d}=e;return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(o.A,{title:t,seoDescription:c}),(0,n.jsx)(s.Z,{}),(0,n.jsx)("div",{className:"wrapper",children:i}),(0,n.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[a?(0,n.jsxs)(l(),{href:a.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,n.jsx)("p",{children:a.name})]}):(0,n.jsx)("div",{className:"w-96"}),d&&(0,n.jsxs)(l(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,n.jsx)("p",{children:d.name})]})]}),(0,n.jsx)("div",{className:"wrapper",children:(0,n.jsx)(r.Z,{})})]})}},80615:function(e,i,t){"use strict";t.d(i,{Y:function(){return s}});var n=t(85893);let s=e=>{let{children:i}=e;return(0,n.jsx)("p",{className:"text-sm text-gray-500 max-w-xs italic text-center mt-4 font-light",children:i})}},3572:function(e,i,t){"use strict";t.d(i,{d:function(){return d}});var n=t(85893),s=t(32581),r=t(15660),o=t.n(r),c=t(67294),l=t(45993),a=t.n(l);let d=e=>{let{code:i}=e,[t,r]=(0,c.useState)(!1),l=(0,c.useRef)(null);(0,c.useEffect)(()=>{l.current&&o().highlightElement(l.current)},[l,i]);let d=(0,n.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(i),r(!0)},className:a().codeChunckCopyButton,children:t?"Copied":(0,n.jsx)(s.Z,{size:14,style:{padding:0}})});return(0,n.jsxs)("div",{className:"mb-6 relative",children:[(0,n.jsx)("pre",{className:"rounded-md line-numbers",children:(0,n.jsx)("code",{ref:l,className:"language-javascript",children:i})}),(0,n.jsx)("div",{className:a().copyButtonContainer,children:d})]})}},7826:function(e,i,t){"use strict";t.d(i,{Qd:function(){return a},UQ:function(){return l},o4:function(){return d},vF:function(){return h}});var n=t(85893),s=t(67294),r=t(47398),o=t(8971),c=t(77522);let l=r.fC,a=s.forwardRef((e,i)=>{let{className:t,...s}=e;return(0,n.jsx)(r.ck,{ref:i,className:(0,c.cn)("border-b",t),...s})});a.displayName="AccordionItem";let d=s.forwardRef((e,i)=>{let{className:t,children:s,...l}=e;return(0,n.jsx)(r.h4,{className:"flex mt-0 pb-0 font-normal",children:(0,n.jsxs)(r.xz,{ref:i,className:(0,c.cn)("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",t),...l,children:[s,(0,n.jsx)(o.Z,{className:"h-4 w-4 shrink-0 transition-transform duration-200"})]})})});d.displayName=r.xz.displayName;let h=s.forwardRef((e,i)=>{let{className:t,children:s,...o}=e;return(0,n.jsx)(r.VY,{ref:i,className:"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",...o,children:(0,n.jsx)("div",{className:(0,c.cn)("pb-4 pt-0",t),children:s})})});h.displayName=r.VY.displayName},22725:function(e,i,t){"use strict";t.d(i,{SP:function(){return a},dr:function(){return l},mQ:function(){return c},nU:function(){return d}});var n=t(85893),s=t(67294),r=t(60434),o=t(77522);let c=r.fC,l=s.forwardRef((e,i)=>{let{className:t,...s}=e;return(0,n.jsx)(r.aV,{ref:i,className:(0,o.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",t),...s})});l.displayName=r.aV.displayName;let a=s.forwardRef((e,i)=>{let{className:t,...s}=e;return(0,n.jsx)(r.xz,{ref:i,className:(0,o.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",t),...s})});a.displayName=r.xz.displayName;let d=s.forwardRef((e,i)=>{let{className:t,...s}=e;return(0,n.jsx)(r.VY,{ref:i,className:(0,o.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",t),...s})});d.displayName=r.VY.displayName},59973:function(e,i,t){"use strict";t.d(i,{B:function(){return s}});var n=t(67294);let s=e=>{let i=()=>({width:e.current?e.current.offsetWidth:0,height:e.current?e.current.offsetHeight:0}),[t,s]=(0,n.useState)(i),r=()=>{s(i())};return(0,n.useEffect)(()=>(window.addEventListener("resize",r),()=>window.removeEventListener("resize",r)),[]),(0,n.useEffect)(()=>{r()},[e]),t}},62404:function(e,i,t){"use strict";t.r(i),t.d(i,{default:function(){return T}});var n=t(85893),s=t(67294),r=t(43710),o=t(41843),c=t(11236),l=t(18496),a=t(81122),d=t(67208),h=t(86824);let x=e=>{let{position:i,color:t,preset:s}=e,r=(0,h.q_)({to:{position:i,color:t},config:h.vc[s]});return(0,n.jsx)(h.q.circle,{strokeWidth:2,fillOpacity:.4,r:38,cy:50,cx:r.position,stroke:r.color,fill:r.color})},p={border:"1px solid #9a6fb0",borderRadius:"3px",padding:"4px 8px",margin:"10px 2px",fontSize:14,color:"#9a6fb0",opacity:.7},u=e=>{let{width:i,height:t}=e,[r,o]=(0,s.useState)(40),[c,l]=(0,s.useState)("default");return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("button",{style:p,onClick:()=>o(40),children:"Left"}),(0,n.jsx)("button",{style:p,onClick:()=>o(i-40),children:"Right"}),(0,n.jsx)("select",{value:c,onChange:e=>{l(e.target.value)},style:{padding:"8px",fontSize:"16px"},children:["default","gentle","wobbly","stiff","slow","molasses"].map(e=>(0,n.jsx)("option",{value:e,children:e}))})]}),(0,n.jsx)("svg",{width:i,height:t,style:{overflow:"visible"},children:(0,n.jsx)(x,{position:r,color:40===r?"#9a6fb0":"#69b3a2",preset:c})})]})},j=e=>{let{width:i=700,height:t=400}=e;return(0,n.jsx)(u,{width:i,height:t})},m=e=>{let{position:i,color:t}=e,s=(0,h.q_)({to:{position:i,color:t},config:h.vc.molasses});return(0,n.jsx)(h.q.circle,{strokeWidth:2,fillOpacity:.4,r:s.position.to(e=>e/10),cy:50,cx:s.position,stroke:s.color,fill:s.color})},f={border:"1px solid #9a6fb0",borderRadius:"3px",padding:"4px 8px",margin:"10px 2px",fontSize:14,color:"#9a6fb0",opacity:.7},g=e=>{let{width:i,height:t}=e,[r,o]=(0,s.useState)(40);return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("button",{style:f,onClick:()=>o(40),children:"Left"}),(0,n.jsx)("button",{style:f,onClick:()=>o(i-40),children:"Right"})]}),(0,n.jsx)("svg",{width:i,height:t,style:{overflow:"visible"},children:(0,n.jsx)(m,{position:r,color:40===r?"#9a6fb0":"#69b3a2"})})]})},v=e=>{let{width:i=700,height:t=400}=e;return(0,n.jsx)(g,{width:i,height:t})},b=e=>{let{position:i,color:t}=e,s=(0,h.q_)({to:{position:i,color:t},config:h.vc.molasses});return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(h.q.circle,{strokeWidth:2,fillOpacity:.4,r:s.position.to(e=>e/10+10),cy:50,cx:s.position,stroke:s.color,fill:s.color}),(0,n.jsx)(h.q.text,{x:s.position,y:50,textAnchor:"middle",alignmentBaseline:"central",children:s.position.to(e=>Math.floor(e))})]})},y={border:"1px solid #9a6fb0",borderRadius:"3px",padding:"4px 8px",margin:"10px 2px",fontSize:14,color:"#9a6fb0",opacity:.7},w=e=>{let{width:i,height:t}=e,[r,o]=(0,s.useState)(40);return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("button",{style:y,onClick:()=>o(40),children:"Left"}),(0,n.jsx)("button",{style:y,onClick:()=>o(i-40),children:"Right"})]}),(0,n.jsx)("svg",{width:i,height:t,style:{overflow:"visible"},children:(0,n.jsx)(b,{position:r,color:40===r?"#9a6fb0":"#69b3a2"})})]})},k=e=>{let{width:i=700,height:t=400}=e;return(0,n.jsx)(w,{width:i,height:t})};var S=t(80615),N=t(3572),C=t(7826),D=t(13400),z=t(47498);function T(){let e=c.Y.find(e=>"/course/animation/react-spring-for-dataviz"===e.link);return e?(0,n.jsxs)(o.p,{title:e.name,seoDescription:"",nextTocItem:c.Y.find(e=>"/course/animation/scatterplot"===e.link),previousTocItem:c.Y.find(e=>"/course/animation/introduction"===e.link),children:[(0,n.jsx)(r.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["Web animations fall into two main categories: ",(0,n.jsx)("b",{children:"CSS"})," and"," ",(0,n.jsx)("b",{children:"spring-based"})," animations."]}),(0,n.jsxs)("p",{children:["In this lesson, we’ll explore ",(0,n.jsx)("b",{children:"react-spring"}),", a popular library for creating spring-based animations in React. Let’s see how to use it to bring our ",(0,n.jsx)("b",{children:"graph elements to life"}),"."]})]})}),(0,n.jsx)("h2",{children:"Animating a Circle"}),(0,n.jsxs)("p",{children:["Let’s start with something ",(0,n.jsx)("strong",{children:"simple"})," for this first lesson."]}),(0,n.jsx)("p",{children:"Our goal is to animate a circle moving smoothly from one position to another. Here’s what the final effect will look like:"}),(0,n.jsx)("div",{className:"border p-4 my-4",children:(0,n.jsx)(l.x,{width:650,height:100})}),(0,n.jsx)("p",{children:(0,n.jsx)("br",{})}),(0,n.jsx)("p",{children:"Pretty cool, right? \uD83D\uDE43"}),(0,n.jsxs)("p",{children:["To achieve this, we’ll use"," ",(0,n.jsx)("a",{href:"https://www.react-spring.dev",children:"react-spring"}),", the most popular JavaScript library for spring-based animations."]}),(0,n.jsx)("p",{children:(0,n.jsx)("br",{})}),(0,n.jsxs)("center",{children:[(0,n.jsx)("img",{src:"/img/react-spring-homepage.png",width:600}),(0,n.jsxs)(S.Y,{children:[(0,n.jsx)("code",{children:"react-spring"})," homepage. The most famous lib for javascript animation (28k stars on github)"]})]}),(0,n.jsx)("p",{children:(0,n.jsx)("br",{})}),(0,n.jsx)("h2",{children:"Full code"}),(0,n.jsxs)("p",{children:[(0,n.jsx)("code",{children:"react-spring"})," is incredibly powerful, but it can be a bit tricky to grasp, and I personally find its documentation a little unclear. \uD83D\uDE1E"]}),(0,n.jsxs)("p",{children:["For now, the two key features we need are the ",(0,n.jsx)("code",{children:"useSpring"})," ","hook and the ",(0,n.jsx)("code",{children:"animated"})," component."]}),(0,n.jsxs)("p",{children:["With these two tools, we can create a ",(0,n.jsx)("code",{children:"Circle"})," component that accepts a ",(0,n.jsx)("code",{children:"position"})," prop. Whenever a new"," ",(0,n.jsx)("code",{children:"position"})," value is passed, the circle smoothly transitions to its new location."]}),(0,n.jsxs)("p",{children:["Here’s how the ",(0,n.jsx)("code",{children:"Circle"})," component looks:"]}),(0,n.jsx)(N.d,{code:"\nimport { animated, useSpring } from 'react-spring';\n\nexport const Circle = ({ position }) => {\n\n const springProps = useSpring({\n to: {\n position: position\n },\n });\n\n return (\n \n );\n};\n\n "}),(0,n.jsx)("h2",{children:"Explanation"}),(0,n.jsxs)("p",{children:["In this code, we’re creating a simple ",(0,n.jsx)("code",{children:"Circle"})," component that renders ",(0,n.jsx)("strong",{children:"one circle"}),". The component takes a"," ",(0,n.jsx)("code",{children:"position"})," property, which controls the circle’s X position."]}),(0,n.jsxs)("p",{children:["Whenever this prop updates, the circle’s position will change, but it will happen ",(0,n.jsx)("strong",{children:"smoothly"}),"!"]}),(0,n.jsx)("p",{children:"Here’s a breakdown of what’s happening:"}),(0,n.jsx)("h3",{children:"\uD83D\uDE9A Import"}),(0,n.jsxs)("p",{children:["Once installed with a classic ",(0,n.jsx)("code",{children:"npm install react-spring"}),", we need to import:"]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"useSpring"}),": a hook that helps us create animated values."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"animated"}),":a special version of elements (like"," ",(0,n.jsx)("code",{children:""}),") that can be animated."]})]}),(0,n.jsxs)("h3",{children:["\uD83C\uDF38 Using ",(0,n.jsx)("code",{children:"useSpring"})]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["The ",(0,n.jsx)("code",{children:"useSpring"})," hook is used to define an animation. It accepts an object where we specify the properties to animate and how to animate them. In this case, we're animating the"," ",(0,n.jsx)("code",{children:"position"}),"."]}),(0,n.jsxs)("li",{children:["We now have access to ",(0,n.jsx)("code",{children:"springProps.position"}),". If the position changes from ",(0,n.jsx)("code",{children:"0"})," to ",(0,n.jsx)("code",{children:"100"}),","," ",(0,n.jsx)("code",{children:"springProps.position"})," will smoothly transition through values like 1, 3, 10, 15, and so on, until it reaches 100."," ",(0,n.jsx)("code",{children:"react-spring"})," handles the calculation of these intermediate values for us!"]})]}),(0,n.jsx)("h3",{children:"\uD83D\uDD17 Binding the Animation to the Circle"}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Instead of using a regular ",(0,n.jsx)("code",{children:"circle"})," SVG element, we use"," ",(0,n.jsx)("code",{children:"animated.circle"}),". React-spring provides its own animated version of all HTML and SVG elements!"]}),(0,n.jsxs)("li",{children:["Instead of passing ",(0,n.jsx)("code",{children:"position"})," directly to the"," ",(0,n.jsx)("code",{children:"cx"})," property, we pass ",(0,n.jsx)("code",{children:"springProps.position"}),", which contains all the intermediate values, ensuring the circle moves smoothly."]})]}),(0,n.jsx)(a.$,{vizName:"ReactSpringMostBasic",VizComponent:d.U,maxWidth:800,height:200,caption:"A very basic animation using react and react-spring.",fileToOpen:"Circle.tsx"}),(0,n.jsx)(C.UQ,{type:"single",collapsible:!0,children:(0,n.jsxs)(C.Qd,{value:"item-1",children:[(0,n.jsx)(C.o4,{children:"⚠️ Config object or function?"}),(0,n.jsxs)(C.vF,{children:[(0,n.jsxs)("p",{children:["There is something I find very confusing about useSpring hook. It can be used with a config object (like in my explanation), or"," ",(0,n.jsx)("b",{children:"with a function"}),"."]}),(0,n.jsxs)("p",{children:["You will see both in the"," ",(0,n.jsx)("a",{href:"https://www.react-spring.dev/docs/components/use-spring#usage",children:"documentation"}),", what might you feel... confused."]})]})]})}),(0,n.jsx)("h2",{children:"\uD83D\uDD25 Spring Config"}),(0,n.jsxs)("p",{children:["Spring animations follow physics laws to make the animation feel natural. There are three key properties you can control to adjust the feel of the animation: ",(0,n.jsx)("code",{children:"mass"}),", ",(0,n.jsx)("code",{children:"friction"}),", and"," ",(0,n.jsx)("code",{children:"tension"}),"."]}),(0,n.jsxs)("p",{children:["You can customize these properties in the ",(0,n.jsx)("code",{children:"useSpring"})," hook like this:"]}),(0,n.jsx)(N.d,{code:"\nconst springProps = useSpring({\n to: { position, color },\n config: {\n mass: 5,\n friction: 120,\n tension: 120,\n }\n});\n "}),(0,n.jsxs)("p",{children:["But honestly, I strongly advise using one of the"," ",(0,n.jsx)("strong",{children:"presets"})," provided by the library, as they offer great results right out of the box."]}),(0,n.jsx)("p",{children:"Check out the preset effects in the example below:"}),(0,n.jsx)(a.$,{vizName:"ReactSpringPresetValues",VizComponent:j,maxWidth:800,height:200,caption:(0,n.jsxs)("p",{children:[(0,n.jsx)("code",{children:"react-spring"})," offers a few presets for the animation feel. Try them in this sandbox!"]}),fileToOpen:"Circle.tsx"}),(0,n.jsx)("p",{children:"To use one of the presets, you can do something like this:"}),(0,n.jsx)(N.d,{code:"\nconst springProps = useSpring({\n position: 100,\n config: config.default\n});\n "}),(0,n.jsx)("h2",{children:"Deriving Values"}),(0,n.jsxs)("p",{children:["Animating a value directly using ",(0,n.jsx)("b",{children:"react-spring"}),", like we did for the position property, is straightforward."]}),(0,n.jsxs)("p",{children:["However, in data visualization, we often need to"," ",(0,n.jsx)("b",{children:"derive one value from another"}),"."]}),(0,n.jsxs)("p",{children:["For example, suppose we want the size of the circle to be proportional to the X position. You might think that we could simply use the"," ",(0,n.jsx)("code",{children:"springProps.position"})," value as a regular number, like this:"]}),(0,n.jsx)(N.d,{code:"\nreturn (\n \n);\n "}),(0,n.jsxs)("p",{children:["Instead, to achieve this, we need to use the ",(0,n.jsx)("code",{children:"to()"})," method of the ",(0,n.jsx)("code",{children:"springProps.position"})," property, like so:"]}),(0,n.jsx)(N.d,{code:"\nreturn (\n pos / 10)}\n />\n);\n "}),(0,n.jsxs)("p",{children:["This is called ",(0,n.jsx)("b",{children:"interpolation"})," in ",(0,n.jsx)("code",{children:"react-spring"})," ","terminology. You can learn more about it in the full documentation"," ",(0,n.jsx)("a",{href:"https://www.react-spring.dev/docs/advanced/interpolation",target:"_blank",rel:"noopener noreferrer",children:"here"}),"."]}),(0,n.jsx)("p",{children:"Let’s take a look at the result!"}),(0,n.jsx)(a.$,{vizName:"ReactSpringDerivingValue",VizComponent:v,maxWidth:800,height:200,caption:"Smooth animation where circle size is derived from X position.",fileToOpen:"Circle.tsx"}),(0,n.jsx)("h2",{children:"Animating Text"}),(0,n.jsxs)("p",{children:["So far, we’ve only animated numerical values—like smoothly transitioning the position from ",(0,n.jsx)("code",{children:"1"})," to ",(0,n.jsx)("code",{children:"100"}),"."]}),(0,n.jsxs)("p",{children:["But ",(0,n.jsx)("code",{children:"react-spring"})," is much more powerful than that! It can animate almost anything, including ",(0,n.jsx)("b",{children:"text"})," and ",(0,n.jsx)("b",{children:"colors"}),"!"]}),(0,n.jsx)("p",{children:"In the example below, watch how the number evolves progressively:"}),(0,n.jsx)(a.$,{vizName:"ReactSpringText",VizComponent:k,maxWidth:800,height:200,caption:"Demo: react-spring can also animate text, colors and so much more!",fileToOpen:"Circle.tsx"}),(0,n.jsx)("h2",{children:"Exercises"}),(0,n.jsx)(z.v,{localStorageId:e.link,exercises:[{title:(0,n.jsx)("span",{children:"Your first animated circle!"}),content:(0,n.jsx)(D.q,{exercise:I[0]})},{title:(0,n.jsx)("span",{children:"Opacity? \uD83D\uDC7B"}),content:(0,n.jsx)(D.q,{exercise:I[1]})},{title:(0,n.jsxs)("span",{children:["Let's make this ",(0,n.jsx)("code",{children:"div"})," moves"]}),content:(0,n.jsx)(D.q,{exercise:I[2]})},{title:(0,n.jsx)("span",{children:"Rotate this rect"}),content:(0,n.jsx)(D.q,{exercise:I[3]})},{title:(0,n.jsx)("span",{children:"Is it to heavy?"}),content:(0,n.jsx)(D.q,{exercise:I[4]})},{title:(0,n.jsx)("span",{children:"Three elements"}),content:(0,n.jsx)(D.q,{exercise:I[5]})}]})]}):null}let I=[{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Just applying the very basic usage we just learned"})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Create a ",(0,n.jsx)("code",{children:"Circle.tsx"})," file that makes a"," ",(0,n.jsx)("code",{children:"Circle"})," component"]}),(0,n.jsxs)("li",{children:["Create a ",(0,n.jsx)("code",{children:"position"})," state in ",(0,n.jsx)("code",{children:"Graph.tsx"}),". Each time the user click on the SVG area, this position must toggle between ",(0,n.jsx)("code",{children:"40"})," and ",(0,n.jsx)("code",{children:"width - 40"})]}),(0,n.jsxs)("li",{children:["Provide the position to the ",(0,n.jsx)("code",{children:"Circle"})," component. Render a circle at this ",(0,n.jsx)("code",{children:"x"})," position, animate its movement with"," ",(0,n.jsx)("code",{children:"react-spring"}),"."]})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleCircleSolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"react-spring can animate many sorts of values. Opacity is one of them, but text, and colors work too!"})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Same as previous exercise, but add a property for the"," ",(0,n.jsx)("code",{children:"opacity"}),"."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"opacity"})," must toggle between ",(0,n.jsx)("code",{children:"0.2"})," and"," ",(0,n.jsx)("code",{children:"1"})," depending on if the circle is on the left or on the right."]})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleCircleOpacitySolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:[(0,n.jsx)("code",{children:"react-spring"})," does not only work with SVG! HTML elements can be animated too!"]}),(0,n.jsxs)("p",{children:["note also that the spring can be made directly in the"," ",(0,n.jsx)("code",{children:"Graph"})," component. Making a separate component to organise your work is nice IMO, but not required."]})]}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["In ",(0,n.jsx)("code",{children:"Graph.tsx"}),", render a parent ",(0,n.jsx)("code",{children:"div"})," using the ",(0,n.jsx)("code",{children:"width"})," and ",(0,n.jsx)("code",{children:"height"})," provided at the top of the component instead of the usual SVG area."]}),(0,n.jsxs)("li",{children:["In this ",(0,n.jsx)("code",{children:"div"}),", render another ",(0,n.jsx)("code",{children:"div"}),". It must be square, have a ",(0,n.jsx)("code",{children:"backgroundColor"})," of ",(0,n.jsx)("code",{children:"red"})," ","and be absolutely positioned."]}),(0,n.jsxs)("li",{children:["Now make the red ",(0,n.jsx)("code",{children:"div"})," moves from right to left when user clicks on the parent div."]})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleDivSolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Just a bit of fun!"})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("ul",{children:(0,n.jsxs)("li",{children:["Use the ",(0,n.jsx)("code",{children:"rotate"})," property of a div to make the rectangle spin when it goes from one side to another!"]})})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleDivRotateSolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Spring physics matters!"})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["Apply a mass of ",(0,n.jsx)("code",{children:"120"})," to the moving ",(0,n.jsx)("code",{children:"div"})]}),(0,n.jsx)("li",{children:"What happens? Why?"}),(0,n.jsxs)("li",{children:["Try to play with ",(0,n.jsx)("code",{children:"friction"})," and ",(0,n.jsx)("code",{children:"tension"})," too to get an intuition on how physics work."]})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationSimpleDivHeavySolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("p",{children:[(0,n.jsx)("code",{children:"delay"})," can give some cool effects to dataviz projects. But use it with care, you do not want to waste people time!"]})}),toDo:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Instead of 1 circle (exercise 1), render 3 animated circles."}),(0,n.jsx)("li",{children:"Use y positions of 50, 100, 150 respectively (you need to create a y prop in the Circle componetn)"}),(0,n.jsx)("li",{children:"Add a new property called delay to the Circle component. Give values of 10, 100 and 1000 to the 3 circles respectively."}),(0,n.jsx)("li",{children:"Use this delay value to delay the start of the animation: you can just pass it to the useSpring hook!"})]})}),practiceSandbox:"exercise/AnimationDefaultPractice",solutionSandbox:"exercise/AnimationMultiCircleDelaySolution",fileToOpen:"Graph.tsx"}]},18496:function(e,i,t){"use strict";t.d(i,{x:function(){return l}});var n=t(85893),s=t(67294),r=t(86824);let o=e=>{let{position:i,color:t}=e,s=(0,r.q_)({to:{position:i,color:t}});return(0,n.jsx)(r.q.circle,{strokeWidth:2,fillOpacity:.4,r:38,cy:50,cx:s.position,stroke:s.color,fill:s.color})},c={border:"1px solid #9a6fb0",borderRadius:"3px",padding:"4px 8px",margin:"10px 2px",fontSize:14,color:"#9a6fb0",opacity:.7},l=e=>{let{width:i,height:t}=e,[r,l]=(0,s.useState)(40);return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("button",{style:c,onClick:()=>l(40),children:"Left"}),(0,n.jsx)("button",{style:c,onClick:()=>l(i-40),children:"Right"})]}),(0,n.jsx)("svg",{width:i,height:t,children:(0,n.jsx)(o,{position:r,color:40===r?"#9a6fb0":"#69b3a2"})})]})}},67208:function(e,i,t){"use strict";t.d(i,{U:function(){return r}});var n=t(85893),s=t(18496);let r=e=>{let{width:i=700,height:t=400}=e;return(0,n.jsx)(s.x,{width:i,height:t})}},45993:function(e){e.exports={codeChunckCopyButton:"code-block_codeChunckCopyButton__yPrL_",copyButtonContainer:"code-block_copyButtonContainer__BrX9E"}},86824:function(e,i,t){"use strict";t.d(i,{q:function(){return n.q},q_:function(){return n.q_},to:function(){return n.to},vc:function(){return n.vc}});var n=t(2719)}},function(e){e.O(0,[2343,7754,7823,2719,9484,8190,3710,9774,2888,179],function(){return e(e.s=3460)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/_next/static/chunks/pages/course/axis/bottom-axis-07f8aaabf63dbd76.js b/_next/static/chunks/pages/course/axis/bottom-axis-07f8aaabf63dbd76.js
deleted file mode 100644
index 8b4a509c..00000000
--- a/_next/static/chunks/pages/course/axis/bottom-axis-07f8aaabf63dbd76.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[4445],{487:function(e,t,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/axis/bottom-axis",function(){return s(24008)}])},81122:function(e,t,s){"use strict";s.d(t,{$:function(){return c}});var n=s(85893),i=s(67294),r=s(59973),l=s(80615),a=s(88578),o=s(5);let c=e=>{let{VizComponent:t,vizName:s,height:c=400,maxWidth:d=800,caption:x,fileToOpen:h}=e,[u,m]=(0,i.useState)(!1),f=(0,i.useRef)(null),p=(0,r.B)(f);return(0,n.jsx)("div",{style:{marginLeft:"-50vw",left:"50%"},className:"my-4 py-4 w-screen relative",children:u?(0,n.jsxs)("div",{className:"flex flex-col items-center justify-center w-full",children:[(0,n.jsx)("div",{style:{maxWidth:2e3},className:"w-full z-50",children:(0,n.jsx)(a.X,{vizName:s,fileToOpen:h})}),(0,n.jsx)("div",{className:"flex justify-center mt-2",children:(0,n.jsx)(o.z,{size:"sm",onClick:()=>m(!u),children:"Hide Sandbox"})})]}):(0,n.jsxs)("div",{className:"flex flex-col items-center justify-center",children:[(0,n.jsx)("div",{className:"bg-gray-100 bg-opacity-50 w-screen flex justify-center z-50 pointer-events-none",children:(0,n.jsx)("div",{style:{height:c,width:"100%",maxWidth:d},ref:f,className:"pointer-events-auto",children:(0,n.jsx)(t,{height:c,width:p.width})})}),(0,n.jsx)(l.Y,{children:x}),(0,n.jsx)("div",{className:"flex justify-center",children:(0,n.jsx)(o.z,{size:"sm",onClick:()=>m(!u),children:"Show code"})})]})})}},88578:function(e,t,s){"use strict";s.d(t,{X:function(){return i}});var n=s(85893);s(67294);let i=e=>{let{vizName:t,height:s="500px",fileToOpen:i}=e;return console.log("rerendeeeerrrrr"),(0,n.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+t+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(i?"&module=/".concat(i):""),style:{width:"100%",height:s,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},47498:function(e,t,s){"use strict";s.d(t,{v:function(){return d}});var n=s(85893),i=s(7826),r=s(13742),l=s(61108),a=s(67294),o=s(5),c=s(77522);let d=e=>{let{exercises:t,localStorageId:s}=e,[d,x]=(0,a.useState)([]),[h,u]=(0,a.useState)("");return(0,a.useEffect)(()=>{let e=localStorage.getItem(s),n=e?JSON.parse(e):Array(t.length).fill("todo");x(n)},[]),(0,n.jsx)(i.UQ,{value:h,onValueChange:u,type:"single",collapsible:!0,className:"w-full",children:t.map((e,t)=>(0,n.jsxs)(i.Qd,{value:"item-"+t,children:[(0,n.jsx)(i.o4,{className:"no-decoration hover:bg-gray-50",children:(0,n.jsxs)("div",{className:"text-sm flex justify-start gap-2 items-center",children:[(0,n.jsx)("div",{className:(0,c.cn)("text-xs h-6 w-6 flex justify-center items-center rounded-full text-center leading-none","todo"===d[t]?"bg-gray-200":"failed"===d[t]?"bg-red-300":"bg-green-300"),children:(0,n.jsx)("span",{style:{transform:"translateX(1px)"},children:t+1})}),(0,n.jsx)("span",{children:e.title}),"ok"===d[t]&&(0,n.jsx)(r.Z,{size:16,className:"text-green-500"}),"failed"===d[t]&&(0,n.jsx)(l.Z,{size:16,className:"text-red-500"}),"todo"===d[t]&&(0,n.jsx)("span",{className:"text-gray-400 font-thin",children:"ToDo"})]})}),(0,n.jsxs)(i.vF,{children:[e.content,(0,n.jsxs)("div",{className:"flex justify-center gap-4",children:[(0,n.jsx)(o.z,{variant:"outline",onClick:()=>{let e=[...d];e[t]="failed",x(e),localStorage.setItem(s,JSON.stringify(e)),u("")},children:"Failed"}),(0,n.jsxs)(o.z,{onClick:()=>{let e=[...d];e[t]="ok",x(e),localStorage.setItem(s,JSON.stringify(e)),u("")},children:["Done",(0,n.jsx)("span",{className:"ml-2",children:"\uD83C\uDF89"})]})]})]})]}))})}},13400:function(e,t,s){"use strict";s.d(t,{q:function(){return c}});var n=s(85893),i=s(22725),r=s(67294),l=s(88578),a=s(8117),o=s(5);let c=e=>{let{exercise:t}=e,[s,c]=(0,r.useState)(!1);(0,r.useEffect)(()=>{let e=e=>{"Escape"===e.key&&c(!1)};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[]);let x=(0,n.jsx)(l.X,{vizName:t.practiceSandbox,height:s?"100%":"500px",fileToOpen:t.fileToOpen}),h=(0,n.jsx)(l.X,{vizName:t.solutionSandbox,height:s?"100%":"500px",fileToOpen:t.fileToOpen});return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)(a.C,{children:"To Do"}),(0,n.jsx)("div",{className:"mt-4",children:t.toDo})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)(a.C,{children:"Why it matters"}),(0,n.jsx)("div",{className:"mt-4 pl-4",children:t.whyItMatters})]})]}),(0,n.jsxs)(i.mQ,{defaultValue:"practice",className:"relative",children:[(0,n.jsxs)("div",{className:"flex justify-center items-center",children:[(0,n.jsxs)(i.dr,{children:[(0,n.jsx)(i.SP,{value:"practice",children:"Practice"}),(0,n.jsx)(i.SP,{value:"solution",children:"Solution"})]}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(o.z,{size:"sm",variant:"outline",onClick:()=>c(!0),children:"Show full screen"})})]}),(0,n.jsx)(i.nU,{value:"practice",children:s?(0,n.jsx)(d,{setIsFullScreen:c,sandbox:x}):(0,n.jsx)("div",{className:"my-4",children:x})}),(0,n.jsx)(i.nU,{value:"solution",children:s?(0,n.jsx)(d,{setIsFullScreen:c,sandbox:h}):(0,n.jsx)("div",{className:"my-4",children:h})})]})]})},d=e=>{let{sandbox:t,setIsFullScreen:s}=e;return(0,n.jsxs)("div",{className:"fixed h-screen inset-0 flex justify-center items-center",children:[(0,n.jsx)("div",{className:"absolute inset-0 w-full h-full bg-white/80"}),(0,n.jsxs)("div",{className:"relative w-11/12 h-4/5",children:[t,(0,n.jsx)("div",{className:"w-full mt-2 flex justify-center items-center gap-2",children:(0,n.jsxs)("div",{className:"relative",children:[(0,n.jsx)(o.z,{onClick:()=>s(!1),variant:"destructive",children:"Leave Fullscreen mode"}),(0,n.jsxs)("span",{className:"absolute w-96 ml-2 text-gray-500 text-xs mt-3",children:["You can also press ",(0,n.jsx)("code",{children:"Esc"})]})]})})]})]})}},41843:function(e,t,s){"use strict";s.d(t,{p:function(){return c}});var n=s(85893),i=s(49700),r=s(63476),l=s(17414),a=s(41664),o=s.n(a);let c=e=>{let{children:t,title:s,seoDescription:a,previousTocItem:c,nextTocItem:d}=e;return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(l.A,{title:s,seoDescription:a}),(0,n.jsx)(i.Z,{}),(0,n.jsx)("div",{className:"wrapper",children:t}),(0,n.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[c?(0,n.jsxs)(o(),{href:c.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,n.jsx)("p",{children:c.name})]}):(0,n.jsx)("div",{className:"w-96"}),d&&(0,n.jsxs)(o(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,n.jsx)("p",{children:d.name})]})]}),(0,n.jsx)("div",{className:"wrapper",children:(0,n.jsx)(r.Z,{})})]})}},63265:function(e,t,s){"use strict";s.d(t,{D:function(){return i}});var n=s(85893);let i=e=>{let{text:t}=e;return(0,n.jsxs)("div",{className:"hidden absolute w-60 top-1/2 -right-10 border-l text-card-foreground border-card-foreground h-28 translate-x-full -translate-y-1/2 xl:flex items-center ",children:[(0,n.jsx)("span",{className:"",children:"→"}),(0,n.jsx)("span",{className:"text-sm ml-2 opacity-70",children:t})]})}},80615:function(e,t,s){"use strict";s.d(t,{Y:function(){return i}});var n=s(85893);let i=e=>{let{children:t}=e;return(0,n.jsx)("p",{className:"text-sm text-gray-500 max-w-xs italic text-center mt-4 font-light",children:t})}},3572:function(e,t,s){"use strict";s.d(t,{d:function(){return d}});var n=s(85893),i=s(32581),r=s(15660),l=s.n(r),a=s(67294),o=s(45993),c=s.n(o);let d=e=>{let{code:t}=e,[s,r]=(0,a.useState)(!1),o=(0,a.useRef)(null);(0,a.useEffect)(()=>{o.current&&l().highlightElement(o.current)},[o,t]);let d=(0,n.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(t),r(!0)},className:c().codeChunckCopyButton,children:s?"Copied":(0,n.jsx)(i.Z,{size:14,style:{padding:0}})});return(0,n.jsxs)("div",{className:"mb-6 relative",children:[(0,n.jsx)("pre",{className:"rounded-md line-numbers",children:(0,n.jsx)("code",{ref:o,className:"language-javascript",children:t})}),(0,n.jsx)("div",{className:c().copyButtonContainer,children:d})]})}},7826:function(e,t,s){"use strict";s.d(t,{Qd:function(){return c},UQ:function(){return o},o4:function(){return d},vF:function(){return x}});var n=s(85893),i=s(67294),r=s(47398),l=s(8971),a=s(77522);let o=r.fC,c=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.ck,{ref:t,className:(0,a.cn)("border-b",s),...i})});c.displayName="AccordionItem";let d=i.forwardRef((e,t)=>{let{className:s,children:i,...o}=e;return(0,n.jsx)(r.h4,{className:"flex mt-0 pb-0 font-normal",children:(0,n.jsxs)(r.xz,{ref:t,className:(0,a.cn)("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",s),...o,children:[i,(0,n.jsx)(l.Z,{className:"h-4 w-4 shrink-0 transition-transform duration-200"})]})})});d.displayName=r.xz.displayName;let x=i.forwardRef((e,t)=>{let{className:s,children:i,...l}=e;return(0,n.jsx)(r.VY,{ref:t,className:"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",...l,children:(0,n.jsx)("div",{className:(0,a.cn)("pb-4 pt-0",s),children:i})})});x.displayName=r.VY.displayName},22725:function(e,t,s){"use strict";s.d(t,{SP:function(){return c},dr:function(){return o},mQ:function(){return a},nU:function(){return d}});var n=s(85893),i=s(67294),r=s(60434),l=s(77522);let a=r.fC,o=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.aV,{ref:t,className:(0,l.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",s),...i})});o.displayName=r.aV.displayName;let c=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.xz,{ref:t,className:(0,l.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",s),...i})});c.displayName=r.xz.displayName;let d=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.VY,{ref:t,className:(0,l.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",s),...i})});d.displayName=r.VY.displayName},59973:function(e,t,s){"use strict";s.d(t,{B:function(){return i}});var n=s(67294);let i=e=>{let t=()=>({width:e.current?e.current.offsetWidth:0,height:e.current?e.current.offsetHeight:0}),[s,i]=(0,n.useState)(t),r=()=>{i(t())};return(0,n.useEffect)(()=>(window.addEventListener("resize",r),()=>window.removeEventListener("resize",r)),[]),(0,n.useEffect)(()=>{r()},[e]),s}},24008:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return j}});var n=s(85893);s(67294);var i=s(43710),r=s(41843),l=s(11236),a=s(88578),o=s(3572),c=s(47498),d=s(41664),x=s.n(d),h=s(81122),u=s(81341),m=s(43950),f=s(63265),p=s(13400);function j(){let e=l.Y.find(e=>"/course/axis/bottom-axis"===e.link),t=(0,m.BYU)().domain([0,100]).range([0,500]);return(console.log(t.ticks(2)),console.log(t.ticks(5)),console.log(t.ticks(9)),console.log(t.ticks(10)),e)?(0,n.jsxs)(r.p,{title:e.name,seoDescription:"",nextTocItem:l.Y.find(e=>"/course/axis/axis-variations"===e.link),previousTocItem:l.Y.find(e=>"/course/axis/margin-and-translation"===e.link),children:[(0,n.jsx)(i.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("p",{children:["In the previous lesson, we learned how to manage ",(0,n.jsx)("b",{children:"margins"})," ","effectively in our chart. Now, let's explore how to create a"," ",(0,n.jsx)("code",{children:"AxisBottom"})," react component that draws a bottom axis!"]})})}),(0,n.jsxs)("h2",{children:["\uD83D\uDD0D More about ",(0,n.jsx)("code",{children:"scaleLinear()"})]}),(0,n.jsxs)("p",{children:["In the previous lessons we talked a lot about the ",(0,n.jsx)("b",{children:"scaleLinear()"})," ","function of d3.js."]}),(0,n.jsxs)("p",{children:["You should perfectly understand the code below. If not, go back to the"," ",(0,n.jsx)(x(),{href:"/course/scales/linear-scale",children:"scale module"})," of this course!"]}),(0,n.jsx)(o.d,{code:"\nconst xScale = d3.scaleLinear()\n .domain([0, 100])\n .range([0, 500]);\n\nconsole.log(xScale(0)) // 0\nconsole.log(xScale(100)) // 500\n".trim()}),(0,n.jsxs)("p",{children:["What I haven't mentioned yet is that the ",(0,n.jsx)("code",{children:"xScale"})," function includes a few additional methods that are quite useful:"]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale.range()"})," returns the range of the scale, which is"," ",(0,n.jsx)("code",{children:"[0, 500]"})," in this case."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale.ticks(10)"})," generates an array of"," ",(0,n.jsx)("b",{children:"approximately"})," 10 evenly spaced values along the axis. This function is quite intelligent, producing ",(0,n.jsx)("b",{children:"nicely rounded numbers"}),", which can be a lifesaver."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale.domain()"})," provides the input domain of the scale (",(0,n.jsx)("code",{children:"[0, 100]"}),")"]})]}),(0,n.jsx)("h3",{children:"Example \uD83E\uDDD0"}),(0,n.jsxs)("div",{className:"relative",children:[(0,n.jsx)(f.D,{text:"⚠️ Take some time to fully understand this code snippet; it's important!"}),(0,n.jsx)(o.d,{code:"\nxScale.ticks(2) // [0, 50, 100]\nxScale.ticks(5) // [0, 20, 40, 60, 80]\nxScale.ticks(9) // [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]\nxScale.ticks(10) // [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]\n".trim()})]}),(0,n.jsx)("p",{children:"See?"}),(0,n.jsxs)("p",{children:["The ",(0,n.jsx)("code",{children:".ticks()"})," method doesn't always return the ",(0,n.jsx)("b",{children:"exact"})," ","number of ticks you specify. Instead, it identifies the"," ",(0,n.jsx)("b",{children:"most suitable value"})," close to your target to ensure your axis looks polished and visually appealing!"]}),(0,n.jsx)("h2",{children:"Let's draw! ✏️"}),(0,n.jsxs)("p",{children:["Now that we know ",(0,n.jsx)("b",{children:"where the ticks are going to be"}),", we just need to draw a long horizontal line, and a multitude of small ticks with their labels at those positions!"]}),(0,n.jsx)("p",{children:"Here is a sandbox with a very minimal example. Take a bit of time to read the code carefully!"}),(0,n.jsx)(a.X,{vizName:"AxisBottomMinimal"}),(0,n.jsxs)("p",{children:[(0,n.jsx)("br",{}),(0,n.jsx)("br",{})]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["The horizontal line is made using a ",(0,n.jsx)("code",{children:"line"})," element that takes the full ",(0,n.jsx)("code",{children:"boundsWidth"}),"."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale.ticks()"})," is used to start a loop: 1 iteration per tick!"]}),(0,n.jsxs)("li",{children:["For each tick, a ",(0,n.jsx)("code",{children:"g"})," element wraps a ",(0,n.jsx)("code",{children:"line"})," and a ",(0,n.jsx)("code",{children:"text"})," element forming the tick."]})]}),(0,n.jsx)("h2",{children:"\uD83C\uDF81 Reusable Bottom Axis Component"}),(0,n.jsxs)("p",{children:["This bottom axis will likely be used across ",(0,n.jsx)("b",{children:"multiple"})," charts in your project, so let’s develop a ",(0,n.jsx)("b",{children:"reusable component"})," named"," ",(0,n.jsx)("code",{children:"AxisBottom"}),"."]}),(0,n.jsxs)("p",{children:["The ",(0,n.jsx)("code",{children:"AxisBottom"})," component accepts several properties:"]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale"}),": The scale that the axis will represent."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"pixelsPerTick"}),": Instead of specifying the number of ticks, it's better to define the pixels per tick. This approach ensures a consistent appearance, regardless of whether the chart is displayed on a large screen or a mobile device!"]})]}),(0,n.jsxs)("div",{className:"relative",children:[(0,n.jsx)(f.D,{text:(0,n.jsxs)("p",{children:["This code is inspired by"," ",(0,n.jsx)("a",{href:"https://wattenberger.com/blog/react-and-d3",children:"Amelia Wattenberger's blog post"}),"!"]})}),(0,n.jsx)(o.d,{code:g})]}),(0,n.jsx)("h2",{children:"Exercices"}),(0,n.jsx)(c.v,{localStorageId:e.link,exercises:[{title:(0,n.jsx)("span",{children:"Bubble Plot with bottom axis"}),content:(0,n.jsx)(p.q,{exercise:v[0]})},{title:(0,n.jsx)("span",{children:"Add grid"}),content:(0,n.jsxs)("div",{className:"max-w-96",children:[(0,n.jsx)("p",{children:"Let's tweak the previous sandbox to add grid lines."}),(0,n.jsxs)("p",{children:["To do this, simply adjust the ",(0,n.jsx)("b",{children:"y1"})," property of the tick lines in the ",(0,n.jsx)("b",{children:"AxisBottom"})," component to extend through the entire bounds area."]}),(0,n.jsxs)("p",{children:["This is the advantage of having a ",(0,n.jsx)("b",{children:"custom"})," axis component: you can easily adapt it to match your style. \uD83C\uDF89"]})]})},{title:(0,n.jsx)("span",{children:"Add axis title"}),content:(0,n.jsxs)("div",{className:"max-w-96",children:[(0,n.jsxs)("p",{children:["Adding a title is simply a matter of including a"," ",(0,n.jsx)("code",{children:"text"})," element in your SVG!"]}),(0,n.jsx)("p",{children:"However, handling text in SVG can be a hassle, as it doesn’t natively support wrapping."}),(0,n.jsxs)("p",{children:["Personally, I prefer to place the title manually within the main SVG area rather than in the ",(0,n.jsx)("b",{children:"AxisBottom"})," component, but it's entirely up to you!"]})]})}]}),(0,n.jsx)("h2",{children:"We got axes! \uD83E\uDE93"}),(0,n.jsx)("p",{children:"If you've followed the previous exercises, you now know how to add a bottom axis to your graph."}),(0,n.jsxs)("p",{children:["Adding a ",(0,n.jsx)("b",{children:"left"})," axis works in ",(0,n.jsx)("b",{children:"much the same way"}),"! Wrap it in an ",(0,n.jsx)("code",{children:"AxisLeft"}),"component, and you're good to go!"]}),(0,n.jsx)("p",{children:"Take a moment to review the example code below:"}),(0,n.jsx)(h.$,{vizName:"AxisBasic",VizComponent:u.c,maxWidth:600,height:300,caption:"This axis is rendered without using d3.js to render."})]}):null}let g="\n// AxisBottom.tsx\n\nimport { ScaleLinear } from 'd3';\n\ntype AxisBottomProps = {\n xScale: ScaleLinear;\n pixelsPerTick: number;\n};\n\n// tick length\nconst TICK_LENGTH = 6;\n\nexport const AxisBottom = ({ xScale, pixelsPerTick }: AxisBottomProps) => {\n const range = xScale.range();\n\n const width = range[1] - range[0];\n const numberOfTicksTarget = Math.floor(width / pixelsPerTick);\n\n return (\n <>\n {/* Main horizontal line */}\n \n\n {/* Ticks and labels */}\n {xScale.ticks(numberOfTicksTarget).map((value) => (\n \n \n \n {value}\n \n \n ))}\n >\n );\n};\n".trim(),v=[{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Almost all graphs use this translation mecanism! Let's code it once to integrate it for ever!"})}),toDo:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{children:"Let's improve the bubble plot we started in the previous lesson."}),(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Fill the AxisBottom.tsx file with the code provided in this lesson."}),(0,n.jsx)("li",{children:"Use it to render a bottom axis on the bubble chart."})]})]}),practiceSandbox:"exercise/BubblePlotBottomAxisPractice",solutionSandbox:"exercise/BubblePlotBottomAxisSolution"}]},34699:function(e,t,s){"use strict";s.d(t,{X:function(){return d}});var n=s(85893),i=s(43950);let r=e=>{let{width:t,height:s}=e;return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("defs",{children:(0,n.jsx)("pattern",{id:"pattern_rkDsm",patternUnits:"userSpaceOnUse",width:"9.5",height:"2.5",patternTransform:"rotate(41)",children:(0,n.jsx)("line",{x1:"0",y:"0",x2:"0",y2:"9.5",stroke:"#D9B9F3",strokeWidth:"1"})})}),(0,n.jsx)("rect",{width:t,height:s,fill:"url(#pattern_rkDsm)",opacity:"1"})]})};var l=s(67294);let a=e=>{let{xScale:t,pixelsPerTick:s}=e,i=t.range(),r=(0,l.useMemo)(()=>{let e=i[1]-i[0];return t.ticks(Math.floor(e/s)).map(e=>({value:e,xOffset:t(e)}))},[t]);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("path",{d:["M",i[0],0,"L",i[1],0].join(" "),fill:"none",stroke:"currentColor"}),r.map(e=>{let{value:t,xOffset:s}=e;return(0,n.jsxs)("g",{transform:"translate(".concat(s,", 0)"),children:[(0,n.jsx)("line",{y2:6,stroke:"currentColor"}),(0,n.jsx)("text",{style:{fontSize:"10px",textAnchor:"middle",transform:"translateY(20px)"},children:t},t)]},t)})]})},o=e=>{let{yScale:t,pixelsPerTick:s}=e,i=t.range(),r=(0,l.useMemo)(()=>{let e=i[0]-i[1];return t.ticks(Math.floor(e/s)).map(e=>({value:e,yOffset:t(e)}))},[t]);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("path",{d:["M",0,i[0],"L",0,i[1]].join(" "),fill:"none",stroke:"currentColor"}),r.map(e=>{let{value:t,yOffset:s}=e;return(0,n.jsxs)("g",{transform:"translate(0, ".concat(s,")"),children:[(0,n.jsx)("line",{x2:-6,stroke:"currentColor"}),(0,n.jsx)("text",{style:{fontSize:"10px",textAnchor:"middle",transform:"translateX(-20px)"},children:t},t)]},t)})]})},c={top:30,right:30,bottom:50,left:50},d=e=>{let{width:t,height:s}=e,l=t-c.right-c.left,d=s-c.top-c.bottom,x=i.BYU().domain([0,10]).range([0,l]),h=i.BYU().domain([0,11]).range([d,0]);return i.p2C().domain([1e-24,10]).range(["red","blue"]).clamp(!0),(0,n.jsx)("div",{children:(0,n.jsx)("svg",{width:t,height:s,shapeRendering:"crispEdges",children:(0,n.jsxs)("g",{width:l,height:d,transform:"translate(".concat([c.left,c.top].join(","),")"),overflow:"visible",children:[(0,n.jsx)(r,{width:l,height:d}),(0,n.jsx)(o,{yScale:h,pixelsPerTick:30}),(0,n.jsx)("g",{transform:"translate(0, ".concat(d,")"),children:(0,n.jsx)(a,{xScale:x,pixelsPerTick:60})})]})})})}},81341:function(e,t,s){"use strict";s.d(t,{c:function(){return r}});var n=s(85893),i=s(34699);let r=e=>{let{width:t=700,height:s=400}=e;return(0,n.jsx)(i.X,{width:t,height:s})}},45993:function(e){e.exports={codeChunckCopyButton:"code-block_codeChunckCopyButton__yPrL_",copyButtonContainer:"code-block_copyButtonContainer__BrX9E"}}},function(e){e.O(0,[2343,7754,3950,7823,9484,8190,3710,9774,2888,179],function(){return e(e.s=487)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/_next/static/chunks/pages/course/axis/bottom-axis-bb532bb0bbba2e40.js b/_next/static/chunks/pages/course/axis/bottom-axis-bb532bb0bbba2e40.js
new file mode 100644
index 00000000..6806ff8e
--- /dev/null
+++ b/_next/static/chunks/pages/course/axis/bottom-axis-bb532bb0bbba2e40.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[4445],{487:function(e,t,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/axis/bottom-axis",function(){return s(24008)}])},81122:function(e,t,s){"use strict";s.d(t,{$:function(){return c}});var n=s(85893),i=s(67294),r=s(59973),l=s(80615),a=s(88578),o=s(5);let c=e=>{let{VizComponent:t,vizName:s,height:c=400,maxWidth:d=800,caption:h,fileToOpen:x}=e,[u,m]=(0,i.useState)(!1),p=(0,i.useRef)(null),f=(0,r.B)(p);return(0,n.jsx)("div",{style:{marginLeft:"-50vw",left:"50%"},className:"my-4 py-4 w-screen relative",children:u?(0,n.jsxs)("div",{className:"flex flex-col items-center justify-center w-full",children:[(0,n.jsx)("div",{style:{maxWidth:2e3},className:"w-full z-50",children:(0,n.jsx)(a.X,{vizName:s,fileToOpen:x})}),(0,n.jsx)("div",{className:"flex justify-center mt-2",children:(0,n.jsx)(o.z,{size:"sm",onClick:()=>m(!u),children:"Hide Sandbox"})})]}):(0,n.jsxs)("div",{className:"flex flex-col items-center justify-center",children:[(0,n.jsx)("div",{className:"bg-gray-100 bg-opacity-50 w-screen flex justify-center z-50 pointer-events-none",children:(0,n.jsx)("div",{style:{height:c,width:"100%",maxWidth:d},ref:p,className:"pointer-events-auto",children:(0,n.jsx)(t,{height:c,width:f.width})})}),(0,n.jsx)(l.Y,{children:h}),(0,n.jsx)("div",{className:"flex justify-center",children:(0,n.jsx)(o.z,{size:"sm",onClick:()=>m(!u),children:"Show code"})})]})})}},88578:function(e,t,s){"use strict";s.d(t,{X:function(){return i}});var n=s(85893);s(67294);let i=e=>{let{vizName:t,height:s="500px",fileToOpen:i}=e;return console.log("rerendeeeerrrrr"),(0,n.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+t+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(i?"&module=/".concat(i):""),style:{width:"100%",height:s,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},47498:function(e,t,s){"use strict";s.d(t,{v:function(){return d}});var n=s(85893),i=s(7826),r=s(13742),l=s(61108),a=s(67294),o=s(5),c=s(77522);let d=e=>{let{exercises:t,localStorageId:s}=e,[d,h]=(0,a.useState)([]),[x,u]=(0,a.useState)("");return(0,a.useEffect)(()=>{let e=localStorage.getItem(s),n=e?JSON.parse(e):Array(t.length).fill("todo");h(n)},[]),(0,n.jsx)(i.UQ,{value:x,onValueChange:u,type:"single",collapsible:!0,className:"w-full",children:t.map((e,t)=>(0,n.jsxs)(i.Qd,{value:"item-"+t,children:[(0,n.jsx)(i.o4,{className:"no-decoration hover:bg-gray-50",children:(0,n.jsxs)("div",{className:"text-sm flex justify-start gap-2 items-center",children:[(0,n.jsx)("div",{className:(0,c.cn)("text-xs h-6 w-6 flex justify-center items-center rounded-full text-center leading-none","todo"===d[t]?"bg-gray-200":"failed"===d[t]?"bg-red-300":"bg-green-300"),children:(0,n.jsx)("span",{style:{transform:"translateX(1px)"},children:t+1})}),(0,n.jsx)("span",{children:e.title}),"ok"===d[t]&&(0,n.jsx)(r.Z,{size:16,className:"text-green-500"}),"failed"===d[t]&&(0,n.jsx)(l.Z,{size:16,className:"text-red-500"}),"todo"===d[t]&&(0,n.jsx)("span",{className:"text-gray-400 font-thin",children:"ToDo"})]})}),(0,n.jsxs)(i.vF,{children:[e.content,(0,n.jsxs)("div",{className:"flex justify-center gap-4",children:[(0,n.jsx)(o.z,{variant:"outline",onClick:()=>{let e=[...d];e[t]="failed",h(e),localStorage.setItem(s,JSON.stringify(e)),u("")},children:"Failed"}),(0,n.jsxs)(o.z,{onClick:()=>{let e=[...d];e[t]="ok",h(e),localStorage.setItem(s,JSON.stringify(e)),u("")},children:["Done",(0,n.jsx)("span",{className:"ml-2",children:"\uD83C\uDF89"})]})]})]})]}))})}},13400:function(e,t,s){"use strict";s.d(t,{q:function(){return h}});var n=s(85893),i=s(22725),r=s(88578),l=s(8117),a=s(5),o=s(41664),c=s.n(o),d=s(77522);let h=e=>{let{exercise:t}=e,s=(0,n.jsx)(r.X,{vizName:t.practiceSandbox,height:"500px",fileToOpen:t.fileToOpen}),o=(0,n.jsx)(r.X,{vizName:t.solutionSandbox,height:"500px",fileToOpen:t.fileToOpen});return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)(l.C,{children:"To Do"}),(0,n.jsx)("div",{className:"mt-4",children:t.toDo})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)(l.C,{children:"Why it matters"}),(0,n.jsx)("div",{className:"mt-4 pl-4",children:t.whyItMatters})]})]}),(0,n.jsxs)(i.mQ,{defaultValue:"practice",className:"relative",children:[(0,n.jsx)("div",{className:"flex justify-center items-center",children:(0,n.jsxs)(i.dr,{children:[(0,n.jsx)(i.SP,{value:"practice",children:"Practice"}),(0,n.jsx)(i.SP,{value:"solution",children:"Solution"})]})}),(0,n.jsxs)(i.nU,{value:"practice",children:[(0,n.jsx)("div",{className:"my-4",children:s}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c(),{className:(0,a.d)({size:"sm",variant:"destructive"}),href:"/sandbox?vizName="+t.practiceSandbox,target:"_blank",children:"Show full screen"})})]}),(0,n.jsxs)(i.nU,{value:"solution",children:[(0,n.jsx)("div",{className:"my-4",children:o}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c(),{className:(0,d.cn)((0,a.d)({size:"sm",variant:"destructive"}),"no-underline"),href:"/sandbox?vizName="+t.solutionSandbox,target:"_blank",children:"Show full screen"})})]})]})]})}},41843:function(e,t,s){"use strict";s.d(t,{p:function(){return c}});var n=s(85893),i=s(49700),r=s(63476),l=s(17414),a=s(41664),o=s.n(a);let c=e=>{let{children:t,title:s,seoDescription:a,previousTocItem:c,nextTocItem:d}=e;return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(l.A,{title:s,seoDescription:a}),(0,n.jsx)(i.Z,{}),(0,n.jsx)("div",{className:"wrapper",children:t}),(0,n.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[c?(0,n.jsxs)(o(),{href:c.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,n.jsx)("p",{children:c.name})]}):(0,n.jsx)("div",{className:"w-96"}),d&&(0,n.jsxs)(o(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,n.jsx)("p",{children:d.name})]})]}),(0,n.jsx)("div",{className:"wrapper",children:(0,n.jsx)(r.Z,{})})]})}},63265:function(e,t,s){"use strict";s.d(t,{D:function(){return i}});var n=s(85893);let i=e=>{let{text:t}=e;return(0,n.jsxs)("div",{className:"hidden absolute w-60 top-1/2 -right-10 border-l text-card-foreground border-card-foreground h-28 translate-x-full -translate-y-1/2 xl:flex items-center ",children:[(0,n.jsx)("span",{className:"",children:"→"}),(0,n.jsx)("span",{className:"text-sm ml-2 opacity-70",children:t})]})}},80615:function(e,t,s){"use strict";s.d(t,{Y:function(){return i}});var n=s(85893);let i=e=>{let{children:t}=e;return(0,n.jsx)("p",{className:"text-sm text-gray-500 max-w-xs italic text-center mt-4 font-light",children:t})}},3572:function(e,t,s){"use strict";s.d(t,{d:function(){return d}});var n=s(85893),i=s(32581),r=s(15660),l=s.n(r),a=s(67294),o=s(45993),c=s.n(o);let d=e=>{let{code:t}=e,[s,r]=(0,a.useState)(!1),o=(0,a.useRef)(null);(0,a.useEffect)(()=>{o.current&&l().highlightElement(o.current)},[o,t]);let d=(0,n.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(t),r(!0)},className:c().codeChunckCopyButton,children:s?"Copied":(0,n.jsx)(i.Z,{size:14,style:{padding:0}})});return(0,n.jsxs)("div",{className:"mb-6 relative",children:[(0,n.jsx)("pre",{className:"rounded-md line-numbers",children:(0,n.jsx)("code",{ref:o,className:"language-javascript",children:t})}),(0,n.jsx)("div",{className:c().copyButtonContainer,children:d})]})}},7826:function(e,t,s){"use strict";s.d(t,{Qd:function(){return c},UQ:function(){return o},o4:function(){return d},vF:function(){return h}});var n=s(85893),i=s(67294),r=s(47398),l=s(8971),a=s(77522);let o=r.fC,c=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.ck,{ref:t,className:(0,a.cn)("border-b",s),...i})});c.displayName="AccordionItem";let d=i.forwardRef((e,t)=>{let{className:s,children:i,...o}=e;return(0,n.jsx)(r.h4,{className:"flex mt-0 pb-0 font-normal",children:(0,n.jsxs)(r.xz,{ref:t,className:(0,a.cn)("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",s),...o,children:[i,(0,n.jsx)(l.Z,{className:"h-4 w-4 shrink-0 transition-transform duration-200"})]})})});d.displayName=r.xz.displayName;let h=i.forwardRef((e,t)=>{let{className:s,children:i,...l}=e;return(0,n.jsx)(r.VY,{ref:t,className:"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",...l,children:(0,n.jsx)("div",{className:(0,a.cn)("pb-4 pt-0",s),children:i})})});h.displayName=r.VY.displayName},22725:function(e,t,s){"use strict";s.d(t,{SP:function(){return c},dr:function(){return o},mQ:function(){return a},nU:function(){return d}});var n=s(85893),i=s(67294),r=s(60434),l=s(77522);let a=r.fC,o=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.aV,{ref:t,className:(0,l.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",s),...i})});o.displayName=r.aV.displayName;let c=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.xz,{ref:t,className:(0,l.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",s),...i})});c.displayName=r.xz.displayName;let d=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.VY,{ref:t,className:(0,l.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",s),...i})});d.displayName=r.VY.displayName},59973:function(e,t,s){"use strict";s.d(t,{B:function(){return i}});var n=s(67294);let i=e=>{let t=()=>({width:e.current?e.current.offsetWidth:0,height:e.current?e.current.offsetHeight:0}),[s,i]=(0,n.useState)(t),r=()=>{i(t())};return(0,n.useEffect)(()=>(window.addEventListener("resize",r),()=>window.removeEventListener("resize",r)),[]),(0,n.useEffect)(()=>{r()},[e]),s}},24008:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return j}});var n=s(85893);s(67294);var i=s(43710),r=s(41843),l=s(11236),a=s(88578),o=s(3572),c=s(47498),d=s(41664),h=s.n(d),x=s(81122),u=s(81341),m=s(43950),p=s(63265),f=s(13400);function j(){let e=l.Y.find(e=>"/course/axis/bottom-axis"===e.link),t=(0,m.BYU)().domain([0,100]).range([0,500]);return(console.log(t.ticks(2)),console.log(t.ticks(5)),console.log(t.ticks(9)),console.log(t.ticks(10)),e)?(0,n.jsxs)(r.p,{title:e.name,seoDescription:"",nextTocItem:l.Y.find(e=>"/course/axis/axis-variations"===e.link),previousTocItem:l.Y.find(e=>"/course/axis/margin-and-translation"===e.link),children:[(0,n.jsx)(i.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,n.jsx)(n.Fragment,{children:(0,n.jsxs)("p",{children:["In the previous lesson, we learned how to manage ",(0,n.jsx)("b",{children:"margins"})," ","effectively in our chart. Now, let's explore how to create a"," ",(0,n.jsx)("code",{children:"AxisBottom"})," react component that draws a bottom axis!"]})})}),(0,n.jsxs)("h2",{children:["\uD83D\uDD0D More about ",(0,n.jsx)("code",{children:"scaleLinear()"})]}),(0,n.jsxs)("p",{children:["In the previous lessons we talked a lot about the ",(0,n.jsx)("b",{children:"scaleLinear()"})," ","function of d3.js."]}),(0,n.jsxs)("p",{children:["You should perfectly understand the code below. If not, go back to the"," ",(0,n.jsx)(h(),{href:"/course/scales/linear-scale",children:"scale module"})," of this course!"]}),(0,n.jsx)(o.d,{code:"\nconst xScale = d3.scaleLinear()\n .domain([0, 100])\n .range([0, 500]);\n\nconsole.log(xScale(0)) // 0\nconsole.log(xScale(100)) // 500\n".trim()}),(0,n.jsxs)("p",{children:["What I haven't mentioned yet is that the ",(0,n.jsx)("code",{children:"xScale"})," function includes a few additional methods that are quite useful:"]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale.range()"})," returns the range of the scale, which is"," ",(0,n.jsx)("code",{children:"[0, 500]"})," in this case."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale.ticks(10)"})," generates an array of"," ",(0,n.jsx)("b",{children:"approximately"})," 10 evenly spaced values along the axis. This function is quite intelligent, producing ",(0,n.jsx)("b",{children:"nicely rounded numbers"}),", which can be a lifesaver."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale.domain()"})," provides the input domain of the scale (",(0,n.jsx)("code",{children:"[0, 100]"}),")"]})]}),(0,n.jsx)("h3",{children:"Example \uD83E\uDDD0"}),(0,n.jsxs)("div",{className:"relative",children:[(0,n.jsx)(p.D,{text:"⚠️ Take some time to fully understand this code snippet; it's important!"}),(0,n.jsx)(o.d,{code:"\nxScale.ticks(2) // [0, 50, 100]\nxScale.ticks(5) // [0, 20, 40, 60, 80]\nxScale.ticks(9) // [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]\nxScale.ticks(10) // [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100]\n".trim()})]}),(0,n.jsx)("p",{children:"See?"}),(0,n.jsxs)("p",{children:["The ",(0,n.jsx)("code",{children:".ticks()"})," method doesn't always return the ",(0,n.jsx)("b",{children:"exact"})," ","number of ticks you specify. Instead, it identifies the"," ",(0,n.jsx)("b",{children:"most suitable value"})," close to your target to ensure your axis looks polished and visually appealing!"]}),(0,n.jsx)("h2",{children:"Let's draw! ✏️"}),(0,n.jsxs)("p",{children:["Now that we know ",(0,n.jsx)("b",{children:"where the ticks are going to be"}),", we just need to draw a long horizontal line, and a multitude of small ticks with their labels at those positions!"]}),(0,n.jsx)("p",{children:"Here is a sandbox with a very minimal example. Take a bit of time to read the code carefully!"}),(0,n.jsx)(a.X,{vizName:"AxisBottomMinimal"}),(0,n.jsxs)("p",{children:[(0,n.jsx)("br",{}),(0,n.jsx)("br",{})]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["The horizontal line is made using a ",(0,n.jsx)("code",{children:"line"})," element that takes the full ",(0,n.jsx)("code",{children:"boundsWidth"}),"."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale.ticks()"})," is used to start a loop: 1 iteration per tick!"]}),(0,n.jsxs)("li",{children:["For each tick, a ",(0,n.jsx)("code",{children:"g"})," element wraps a ",(0,n.jsx)("code",{children:"line"})," and a ",(0,n.jsx)("code",{children:"text"})," element forming the tick."]})]}),(0,n.jsx)("h2",{children:"\uD83C\uDF81 Reusable Bottom Axis Component"}),(0,n.jsxs)("p",{children:["This bottom axis will likely be used across ",(0,n.jsx)("b",{children:"multiple"})," charts in your project, so let’s develop a ",(0,n.jsx)("b",{children:"reusable component"})," named"," ",(0,n.jsx)("code",{children:"AxisBottom"}),"."]}),(0,n.jsxs)("p",{children:["The ",(0,n.jsx)("code",{children:"AxisBottom"})," component accepts several properties:"]}),(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"xScale"}),": The scale that the axis will represent."]}),(0,n.jsxs)("li",{children:[(0,n.jsx)("code",{children:"pixelsPerTick"}),": Instead of specifying the number of ticks, it's better to define the pixels per tick. This approach ensures a consistent appearance, regardless of whether the chart is displayed on a large screen or a mobile device!"]})]}),(0,n.jsxs)("div",{className:"relative",children:[(0,n.jsx)(p.D,{text:(0,n.jsxs)("p",{children:["This code is inspired by"," ",(0,n.jsx)("a",{href:"https://wattenberger.com/blog/react-and-d3",children:"Amelia Wattenberger's blog post"}),"!"]})}),(0,n.jsx)(o.d,{code:g})]}),(0,n.jsx)("h2",{children:"Exercices"}),(0,n.jsx)(c.v,{localStorageId:e.link,exercises:[{title:(0,n.jsx)("span",{children:"Bubble Plot with bottom axis"}),content:(0,n.jsx)(f.q,{exercise:b[0]})},{title:(0,n.jsx)("span",{children:"Add grid"}),content:(0,n.jsxs)("div",{className:"max-w-96",children:[(0,n.jsx)("p",{children:"Let's tweak the previous sandbox to add grid lines."}),(0,n.jsxs)("p",{children:["To do this, simply adjust the ",(0,n.jsx)("b",{children:"y1"})," property of the tick lines in the ",(0,n.jsx)("b",{children:"AxisBottom"})," component to extend through the entire bounds area."]}),(0,n.jsxs)("p",{children:["This is the advantage of having a ",(0,n.jsx)("b",{children:"custom"})," axis component: you can easily adapt it to match your style. \uD83C\uDF89"]})]})},{title:(0,n.jsx)("span",{children:"Add axis title"}),content:(0,n.jsxs)("div",{className:"max-w-96",children:[(0,n.jsxs)("p",{children:["Adding a title is simply a matter of including a"," ",(0,n.jsx)("code",{children:"text"})," element in your SVG!"]}),(0,n.jsx)("p",{children:"However, handling text in SVG can be a hassle, as it doesn’t natively support wrapping."}),(0,n.jsxs)("p",{children:["Personally, I prefer to place the title manually within the main SVG area rather than in the ",(0,n.jsx)("b",{children:"AxisBottom"})," component, but it's entirely up to you!"]})]})}]}),(0,n.jsx)("h2",{children:"We got axes! \uD83E\uDE93"}),(0,n.jsx)("p",{children:"If you've followed the previous exercises, you now know how to add a bottom axis to your graph."}),(0,n.jsxs)("p",{children:["Adding a ",(0,n.jsx)("b",{children:"left"})," axis works in ",(0,n.jsx)("b",{children:"much the same way"}),"! Wrap it in an ",(0,n.jsx)("code",{children:"AxisLeft"}),"component, and you're good to go!"]}),(0,n.jsx)("p",{children:"Take a moment to review the example code below:"}),(0,n.jsx)(x.$,{vizName:"AxisBasic",VizComponent:u.c,maxWidth:600,height:300,caption:"This axis is rendered without using d3.js to render."})]}):null}let g="\n// AxisBottom.tsx\n\nimport { ScaleLinear } from 'd3';\n\ntype AxisBottomProps = {\n xScale: ScaleLinear;\n pixelsPerTick: number;\n};\n\n// tick length\nconst TICK_LENGTH = 6;\n\nexport const AxisBottom = ({ xScale, pixelsPerTick }: AxisBottomProps) => {\n const range = xScale.range();\n\n const width = range[1] - range[0];\n const numberOfTicksTarget = Math.floor(width / pixelsPerTick);\n\n return (\n <>\n {/* Main horizontal line */}\n \n\n {/* Ticks and labels */}\n {xScale.ticks(numberOfTicksTarget).map((value) => (\n \n \n \n {value}\n \n \n ))}\n >\n );\n};\n".trim(),b=[{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Almost all graphs use this translation mecanism! Let's code it once to integrate it for ever!"})}),toDo:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{children:"Let's improve the bubble plot we started in the previous lesson."}),(0,n.jsxs)("ul",{children:[(0,n.jsx)("li",{children:"Fill the AxisBottom.tsx file with the code provided in this lesson."}),(0,n.jsx)("li",{children:"Use it to render a bottom axis on the bubble chart."})]})]}),practiceSandbox:"exercise/BubblePlotBottomAxisPractice",solutionSandbox:"exercise/BubblePlotBottomAxisSolution"}]},34699:function(e,t,s){"use strict";s.d(t,{X:function(){return d}});var n=s(85893),i=s(43950);let r=e=>{let{width:t,height:s}=e;return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("defs",{children:(0,n.jsx)("pattern",{id:"pattern_rkDsm",patternUnits:"userSpaceOnUse",width:"9.5",height:"2.5",patternTransform:"rotate(41)",children:(0,n.jsx)("line",{x1:"0",y:"0",x2:"0",y2:"9.5",stroke:"#D9B9F3",strokeWidth:"1"})})}),(0,n.jsx)("rect",{width:t,height:s,fill:"url(#pattern_rkDsm)",opacity:"1"})]})};var l=s(67294);let a=e=>{let{xScale:t,pixelsPerTick:s}=e,i=t.range(),r=(0,l.useMemo)(()=>{let e=i[1]-i[0];return t.ticks(Math.floor(e/s)).map(e=>({value:e,xOffset:t(e)}))},[t]);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("path",{d:["M",i[0],0,"L",i[1],0].join(" "),fill:"none",stroke:"currentColor"}),r.map(e=>{let{value:t,xOffset:s}=e;return(0,n.jsxs)("g",{transform:"translate(".concat(s,", 0)"),children:[(0,n.jsx)("line",{y2:6,stroke:"currentColor"}),(0,n.jsx)("text",{style:{fontSize:"10px",textAnchor:"middle",transform:"translateY(20px)"},children:t},t)]},t)})]})},o=e=>{let{yScale:t,pixelsPerTick:s}=e,i=t.range(),r=(0,l.useMemo)(()=>{let e=i[0]-i[1];return t.ticks(Math.floor(e/s)).map(e=>({value:e,yOffset:t(e)}))},[t]);return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("path",{d:["M",0,i[0],"L",0,i[1]].join(" "),fill:"none",stroke:"currentColor"}),r.map(e=>{let{value:t,yOffset:s}=e;return(0,n.jsxs)("g",{transform:"translate(0, ".concat(s,")"),children:[(0,n.jsx)("line",{x2:-6,stroke:"currentColor"}),(0,n.jsx)("text",{style:{fontSize:"10px",textAnchor:"middle",transform:"translateX(-20px)"},children:t},t)]},t)})]})},c={top:30,right:30,bottom:50,left:50},d=e=>{let{width:t,height:s}=e,l=t-c.right-c.left,d=s-c.top-c.bottom,h=i.BYU().domain([0,10]).range([0,l]),x=i.BYU().domain([0,11]).range([d,0]);return i.p2C().domain([1e-24,10]).range(["red","blue"]).clamp(!0),(0,n.jsx)("div",{children:(0,n.jsx)("svg",{width:t,height:s,shapeRendering:"crispEdges",children:(0,n.jsxs)("g",{width:l,height:d,transform:"translate(".concat([c.left,c.top].join(","),")"),overflow:"visible",children:[(0,n.jsx)(r,{width:l,height:d}),(0,n.jsx)(o,{yScale:x,pixelsPerTick:30}),(0,n.jsx)("g",{transform:"translate(0, ".concat(d,")"),children:(0,n.jsx)(a,{xScale:h,pixelsPerTick:60})})]})})})}},81341:function(e,t,s){"use strict";s.d(t,{c:function(){return r}});var n=s(85893),i=s(34699);let r=e=>{let{width:t=700,height:s=400}=e;return(0,n.jsx)(i.X,{width:t,height:s})}},45993:function(e){e.exports={codeChunckCopyButton:"code-block_codeChunckCopyButton__yPrL_",copyButtonContainer:"code-block_copyButtonContainer__BrX9E"}}},function(e){e.O(0,[2343,7754,3950,7823,9484,8190,3710,9774,2888,179],function(){return e(e.s=487)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/_next/static/chunks/pages/course/axis/margin-and-translation-198cf1fef29d0c84.js b/_next/static/chunks/pages/course/axis/margin-and-translation-198cf1fef29d0c84.js
deleted file mode 100644
index 587aade7..00000000
--- a/_next/static/chunks/pages/course/axis/margin-and-translation-198cf1fef29d0c84.js
+++ /dev/null
@@ -1 +0,0 @@
-(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8790],{26327:function(e,t,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/axis/margin-and-translation",function(){return s(16911)}])},88578:function(e,t,s){"use strict";s.d(t,{X:function(){return i}});var n=s(85893);s(67294);let i=e=>{let{vizName:t,height:s="500px",fileToOpen:i}=e;return console.log("rerendeeeerrrrr"),(0,n.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+t+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(i?"&module=/".concat(i):""),style:{width:"100%",height:s,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},47498:function(e,t,s){"use strict";s.d(t,{v:function(){return d}});var n=s(85893),i=s(7826),r=s(13742),a=s(61108),l=s(67294),o=s(5),c=s(77522);let d=e=>{let{exercises:t,localStorageId:s}=e,[d,h]=(0,l.useState)([]),[x,u]=(0,l.useState)("");return(0,l.useEffect)(()=>{let e=localStorage.getItem(s),n=e?JSON.parse(e):Array(t.length).fill("todo");h(n)},[]),(0,n.jsx)(i.UQ,{value:x,onValueChange:u,type:"single",collapsible:!0,className:"w-full",children:t.map((e,t)=>(0,n.jsxs)(i.Qd,{value:"item-"+t,children:[(0,n.jsx)(i.o4,{className:"no-decoration hover:bg-gray-50",children:(0,n.jsxs)("div",{className:"text-sm flex justify-start gap-2 items-center",children:[(0,n.jsx)("div",{className:(0,c.cn)("text-xs h-6 w-6 flex justify-center items-center rounded-full text-center leading-none","todo"===d[t]?"bg-gray-200":"failed"===d[t]?"bg-red-300":"bg-green-300"),children:(0,n.jsx)("span",{style:{transform:"translateX(1px)"},children:t+1})}),(0,n.jsx)("span",{children:e.title}),"ok"===d[t]&&(0,n.jsx)(r.Z,{size:16,className:"text-green-500"}),"failed"===d[t]&&(0,n.jsx)(a.Z,{size:16,className:"text-red-500"}),"todo"===d[t]&&(0,n.jsx)("span",{className:"text-gray-400 font-thin",children:"ToDo"})]})}),(0,n.jsxs)(i.vF,{children:[e.content,(0,n.jsxs)("div",{className:"flex justify-center gap-4",children:[(0,n.jsx)(o.z,{variant:"outline",onClick:()=>{let e=[...d];e[t]="failed",h(e),localStorage.setItem(s,JSON.stringify(e)),u("")},children:"Failed"}),(0,n.jsxs)(o.z,{onClick:()=>{let e=[...d];e[t]="ok",h(e),localStorage.setItem(s,JSON.stringify(e)),u("")},children:["Done",(0,n.jsx)("span",{className:"ml-2",children:"\uD83C\uDF89"})]})]})]})]}))})}},13400:function(e,t,s){"use strict";s.d(t,{q:function(){return c}});var n=s(85893),i=s(22725),r=s(67294),a=s(88578),l=s(8117),o=s(5);let c=e=>{let{exercise:t}=e,[s,c]=(0,r.useState)(!1);(0,r.useEffect)(()=>{let e=e=>{"Escape"===e.key&&c(!1)};return document.addEventListener("keydown",e),()=>{document.removeEventListener("keydown",e)}},[]);let h=(0,n.jsx)(a.X,{vizName:t.practiceSandbox,height:s?"100%":"500px",fileToOpen:t.fileToOpen}),x=(0,n.jsx)(a.X,{vizName:t.solutionSandbox,height:s?"100%":"500px",fileToOpen:t.fileToOpen});return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)(l.C,{children:"To Do"}),(0,n.jsx)("div",{className:"mt-4",children:t.toDo})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)(l.C,{children:"Why it matters"}),(0,n.jsx)("div",{className:"mt-4 pl-4",children:t.whyItMatters})]})]}),(0,n.jsxs)(i.mQ,{defaultValue:"practice",className:"relative",children:[(0,n.jsxs)("div",{className:"flex justify-center items-center",children:[(0,n.jsxs)(i.dr,{children:[(0,n.jsx)(i.SP,{value:"practice",children:"Practice"}),(0,n.jsx)(i.SP,{value:"solution",children:"Solution"})]}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(o.z,{size:"sm",variant:"outline",onClick:()=>c(!0),children:"Show full screen"})})]}),(0,n.jsx)(i.nU,{value:"practice",children:s?(0,n.jsx)(d,{setIsFullScreen:c,sandbox:h}):(0,n.jsx)("div",{className:"my-4",children:h})}),(0,n.jsx)(i.nU,{value:"solution",children:s?(0,n.jsx)(d,{setIsFullScreen:c,sandbox:x}):(0,n.jsx)("div",{className:"my-4",children:x})})]})]})},d=e=>{let{sandbox:t,setIsFullScreen:s}=e;return(0,n.jsxs)("div",{className:"fixed h-screen inset-0 flex justify-center items-center",children:[(0,n.jsx)("div",{className:"absolute inset-0 w-full h-full bg-white/80"}),(0,n.jsxs)("div",{className:"relative w-11/12 h-4/5",children:[t,(0,n.jsx)("div",{className:"w-full mt-2 flex justify-center items-center gap-2",children:(0,n.jsxs)("div",{className:"relative",children:[(0,n.jsx)(o.z,{onClick:()=>s(!1),variant:"destructive",children:"Leave Fullscreen mode"}),(0,n.jsxs)("span",{className:"absolute w-96 ml-2 text-gray-500 text-xs mt-3",children:["You can also press ",(0,n.jsx)("code",{children:"Esc"})]})]})})]})]})}},41843:function(e,t,s){"use strict";s.d(t,{p:function(){return c}});var n=s(85893),i=s(49700),r=s(63476),a=s(17414),l=s(41664),o=s.n(l);let c=e=>{let{children:t,title:s,seoDescription:l,previousTocItem:c,nextTocItem:d}=e;return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(a.A,{title:s,seoDescription:l}),(0,n.jsx)(i.Z,{}),(0,n.jsx)("div",{className:"wrapper",children:t}),(0,n.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[c?(0,n.jsxs)(o(),{href:c.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,n.jsx)("p",{children:c.name})]}):(0,n.jsx)("div",{className:"w-96"}),d&&(0,n.jsxs)(o(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,n.jsx)("p",{children:d.name})]})]}),(0,n.jsx)("div",{className:"wrapper",children:(0,n.jsx)(r.Z,{})})]})}},80615:function(e,t,s){"use strict";s.d(t,{Y:function(){return i}});var n=s(85893);let i=e=>{let{children:t}=e;return(0,n.jsx)("p",{className:"text-sm text-gray-500 max-w-xs italic text-center mt-4 font-light",children:t})}},3572:function(e,t,s){"use strict";s.d(t,{d:function(){return d}});var n=s(85893),i=s(32581),r=s(15660),a=s.n(r),l=s(67294),o=s(45993),c=s.n(o);let d=e=>{let{code:t}=e,[s,r]=(0,l.useState)(!1),o=(0,l.useRef)(null);(0,l.useEffect)(()=>{o.current&&a().highlightElement(o.current)},[o,t]);let d=(0,n.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(t),r(!0)},className:c().codeChunckCopyButton,children:s?"Copied":(0,n.jsx)(i.Z,{size:14,style:{padding:0}})});return(0,n.jsxs)("div",{className:"mb-6 relative",children:[(0,n.jsx)("pre",{className:"rounded-md line-numbers",children:(0,n.jsx)("code",{ref:o,className:"language-javascript",children:t})}),(0,n.jsx)("div",{className:c().copyButtonContainer,children:d})]})}},7826:function(e,t,s){"use strict";s.d(t,{Qd:function(){return c},UQ:function(){return o},o4:function(){return d},vF:function(){return h}});var n=s(85893),i=s(67294),r=s(47398),a=s(8971),l=s(77522);let o=r.fC,c=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.ck,{ref:t,className:(0,l.cn)("border-b",s),...i})});c.displayName="AccordionItem";let d=i.forwardRef((e,t)=>{let{className:s,children:i,...o}=e;return(0,n.jsx)(r.h4,{className:"flex mt-0 pb-0 font-normal",children:(0,n.jsxs)(r.xz,{ref:t,className:(0,l.cn)("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",s),...o,children:[i,(0,n.jsx)(a.Z,{className:"h-4 w-4 shrink-0 transition-transform duration-200"})]})})});d.displayName=r.xz.displayName;let h=i.forwardRef((e,t)=>{let{className:s,children:i,...a}=e;return(0,n.jsx)(r.VY,{ref:t,className:"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",...a,children:(0,n.jsx)("div",{className:(0,l.cn)("pb-4 pt-0",s),children:i})})});h.displayName=r.VY.displayName},22725:function(e,t,s){"use strict";s.d(t,{SP:function(){return c},dr:function(){return o},mQ:function(){return l},nU:function(){return d}});var n=s(85893),i=s(67294),r=s(60434),a=s(77522);let l=r.fC,o=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.aV,{ref:t,className:(0,a.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",s),...i})});o.displayName=r.aV.displayName;let c=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.xz,{ref:t,className:(0,a.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",s),...i})});c.displayName=r.xz.displayName;let d=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.VY,{ref:t,className:(0,a.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",s),...i})});d.displayName=r.VY.displayName},16911:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return h}});var n=s(85893);s(67294);var i=s(43710),r=s(41843),a=s(11236),l=s(3572),o=s(47498),c=s(80615),d=s(13400);function h(){let e=a.Y.find(e=>"/course/axis/margin-and-translation"===e.link);return e?(0,n.jsxs)(r.p,{title:e.name,seoDescription:"",nextTocItem:a.Y.find(e=>"/course/axis/bottom-axis"===e.link),previousTocItem:a.Y.find(e=>"/course/axis/introduction"===e.link),children:[(0,n.jsx)(i.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["Most chart types use a ",(0,n.jsx)("b",{children:"bottom"})," and a ",(0,n.jsx)("b",{children:"left"})," axis."]}),(0,n.jsxs)("p",{children:["In these cases, we need to ",(0,n.jsx)("b",{children:"leave space"})," for tick labels and axis titles. Let’s look at how to implement this effectively."]})]})}),(0,n.jsx)("h2",{children:"SVG Area and Bounds Area"}),(0,n.jsxs)("p",{children:["Imagine an SVG area with a ",(0,n.jsx)("code",{children:"width"})," of 500px and a"," ",(0,n.jsx)("code",{children:"height"})," of 300px."]}),(0,n.jsxs)("p",{children:["The left and bottom axes aren’t displayed right at the SVG border. Instead, we add ",(0,n.jsx)("b",{children:"margins"})," on all sides: left, right, bottom, and top."]}),(0,n.jsxs)("p",{children:["The area within these margins is known as the ",(0,n.jsx)("b",{children:"bounds"}),", where the chart content is positioned between the x and y axes. In our code, we’ll refer to the width and height of this bounds area as"," ",(0,n.jsx)("code",{children:"boundsWidth"})," and ",(0,n.jsx)("code",{children:"boundsHeight"}),"."]}),(0,n.jsxs)("div",{className:"flex flex-col items-center mt-8 mb-12",children:[(0,n.jsx)("img",{src:"/excalidraw/bounds-explanation.png",style:{maxWidth:750},alt:"Anatomy of the chart areas: some margins are set all around the SVG area. The area inside is called the Bounds."}),(0,n.jsx)(c.Y,{children:"Anatomy of the chart areas: some margins are set all around the SVG area. The area inside is called the Bounds."})]}),(0,n.jsx)("h2",{children:"Implementation"}),(0,n.jsx)("p",{children:"A chart component often starts by defining its margins. An object with 4 properties is ideal for that:"}),(0,n.jsx)(l.d,{code:"\nconst MARGIN = {\n top: 10,\n right: 30,\n bottom: 50,\n left: 30\n}\n ".trim()}),(0,n.jsxs)("p",{children:["Since the chart component has defined ",(0,n.jsx)("code",{children:"width"})," and"," ",(0,n.jsx)("code",{children:"height"}),", we can easily determine the dimensions of the bounds area, referred to as ",(0,n.jsx)("code",{children:"boundsWidth"})," and"," ",(0,n.jsx)("code",{children:"boundsHeight"}),":"]}),(0,n.jsx)(l.d,{code:"\nconst boundsWidth = width - MARGIN.right - MARGIN.left;\nconst boundsHeight = height - MARGIN.top - MARGIN.bottom;\n ".trim()}),(0,n.jsx)("h3",{children:"\uD83E\uDE84 The tricky part"}),(0,n.jsx)("p",{children:"Finally the svg is going to be rendered like this:"}),(0,n.jsx)(l.d,{code:'\n\n '.trim()}),(0,n.jsx)("p",{children:"What's going on here? \uD83D\uDE31"}),(0,n.jsxs)("p",{children:["1️⃣ The SVG area is created as usual with the ",(0,n.jsx)("code",{children:"svg"})," element, along with the specified ",(0,n.jsx)("code",{children:"width"})," and ",(0,n.jsx)("code",{children:"height"}),"."]}),(0,n.jsxs)("p",{children:["2️⃣ The ",(0,n.jsx)("code",{children:"g"})," element is used to group other SVG elements, similar to how a ",(0,n.jsx)("code",{children:"div"})," works in HTML. This group represents the bounds, defined by its ",(0,n.jsx)("code",{children:"boundsWidth"})," and"," ",(0,n.jsx)("code",{children:"boundsHeight"})," dimensions!"]}),(0,n.jsxs)("p",{children:["3️⃣ The ",(0,n.jsx)("code",{children:"transform"})," property is used to translate the bounds slightly to the right and down, creating space for the left and top margins!"]}),(0,n.jsx)("h2",{children:"Exercices"}),(0,n.jsx)(o.v,{localStorageId:e.link,exercises:[{title:(0,n.jsx)("span",{children:"Let's translate this! ↔️"}),content:(0,n.jsx)(d.q,{exercise:x[0]})},{title:(0,n.jsx)("span",{children:"Bubble plot kick off \uD83E\uDEE7"}),content:(0,n.jsx)(d.q,{exercise:x[1]})}]}),(0,n.jsx)("h2",{children:"Drawing the Axis"}),(0,n.jsxs)("p",{children:["Now that we’ve created space for it, it’s time to ",(0,n.jsx)("b",{children:"draw the axis"}),". Let’s build some reusable components for this!"]})]}):null}let x=[{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Almost all graphs use this translation mecanism! Let's code it once to integrate it for ever!"})}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["The ",(0,n.jsx)("code",{children:"Graph"})," component renders a SVG are that is 500px"," ",(0,n.jsx)("code",{children:"width"})," and 300px ",(0,n.jsx)("code",{children:"height"}),"."]}),(0,n.jsx)("li",{children:"The component define its margin as a const: 100px at the left and bottom, 30px at the top and right"}),(0,n.jsx)("li",{children:"The bounds is represented as a grey rectangle"}),(0,n.jsx)("li",{children:"Two circles are drawn within the rectangle. In a dataset where both the X and Y axes range from 0 to 100, render the circles at coordinates (33, 33) and (66, 66)."})]}),practiceSandbox:"exercise/BoundsAreaTranslationPractice",solutionSandbox:"exercise/BoundsAreaTranslationSolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{children:"Let's remind how to loop on a dataset to render shape."}),(0,n.jsx)("p",{children:"Oh and let's introduce a new scale type too!"})]}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["This time, loop on ",(0,n.jsx)("code",{children:"data"})," to render ",(0,n.jsx)("b",{children:"10 circles"}),", one for each item in the dataset."]}),(0,n.jsxs)("li",{children:["There is a ",(0,n.jsx)("code",{children:"size"})," property for each data item. Use it to control the circle size!"]}),(0,n.jsxs)("li",{children:["Data must be mapped to circle ",(0,n.jsx)("b",{children:"area"}),", not to circle ",(0,n.jsx)("b",{children:"radius"}),". Use the",(0,n.jsx)("code",{children:"scaleSqrt"})," function of d3 for that!"]})]}),practiceSandbox:"exercise/BubblePlotKickOffPractice",solutionSandbox:"exercise/BubblePlotKickOffSolution",fileToOpen:"Graph.tsx"}]},45993:function(e){e.exports={codeChunckCopyButton:"code-block_codeChunckCopyButton__yPrL_",copyButtonContainer:"code-block_copyButtonContainer__BrX9E"}}},function(e){e.O(0,[2343,7754,7823,9484,8190,3710,9774,2888,179],function(){return e(e.s=26327)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/_next/static/chunks/pages/course/axis/margin-and-translation-e481dc8c6abf9ce8.js b/_next/static/chunks/pages/course/axis/margin-and-translation-e481dc8c6abf9ce8.js
new file mode 100644
index 00000000..9dd1f821
--- /dev/null
+++ b/_next/static/chunks/pages/course/axis/margin-and-translation-e481dc8c6abf9ce8.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[8790],{26327:function(e,t,s){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/axis/margin-and-translation",function(){return s(16911)}])},88578:function(e,t,s){"use strict";s.d(t,{X:function(){return i}});var n=s(85893);s(67294);let i=e=>{let{vizName:t,height:s="500px",fileToOpen:i}=e;return console.log("rerendeeeerrrrr"),(0,n.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+t+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(i?"&module=/".concat(i):""),style:{width:"100%",height:s,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},47498:function(e,t,s){"use strict";s.d(t,{v:function(){return d}});var n=s(85893),i=s(7826),r=s(13742),a=s(61108),l=s(67294),o=s(5),c=s(77522);let d=e=>{let{exercises:t,localStorageId:s}=e,[d,h]=(0,l.useState)([]),[x,u]=(0,l.useState)("");return(0,l.useEffect)(()=>{let e=localStorage.getItem(s),n=e?JSON.parse(e):Array(t.length).fill("todo");h(n)},[]),(0,n.jsx)(i.UQ,{value:x,onValueChange:u,type:"single",collapsible:!0,className:"w-full",children:t.map((e,t)=>(0,n.jsxs)(i.Qd,{value:"item-"+t,children:[(0,n.jsx)(i.o4,{className:"no-decoration hover:bg-gray-50",children:(0,n.jsxs)("div",{className:"text-sm flex justify-start gap-2 items-center",children:[(0,n.jsx)("div",{className:(0,c.cn)("text-xs h-6 w-6 flex justify-center items-center rounded-full text-center leading-none","todo"===d[t]?"bg-gray-200":"failed"===d[t]?"bg-red-300":"bg-green-300"),children:(0,n.jsx)("span",{style:{transform:"translateX(1px)"},children:t+1})}),(0,n.jsx)("span",{children:e.title}),"ok"===d[t]&&(0,n.jsx)(r.Z,{size:16,className:"text-green-500"}),"failed"===d[t]&&(0,n.jsx)(a.Z,{size:16,className:"text-red-500"}),"todo"===d[t]&&(0,n.jsx)("span",{className:"text-gray-400 font-thin",children:"ToDo"})]})}),(0,n.jsxs)(i.vF,{children:[e.content,(0,n.jsxs)("div",{className:"flex justify-center gap-4",children:[(0,n.jsx)(o.z,{variant:"outline",onClick:()=>{let e=[...d];e[t]="failed",h(e),localStorage.setItem(s,JSON.stringify(e)),u("")},children:"Failed"}),(0,n.jsxs)(o.z,{onClick:()=>{let e=[...d];e[t]="ok",h(e),localStorage.setItem(s,JSON.stringify(e)),u("")},children:["Done",(0,n.jsx)("span",{className:"ml-2",children:"\uD83C\uDF89"})]})]})]})]}))})}},13400:function(e,t,s){"use strict";s.d(t,{q:function(){return h}});var n=s(85893),i=s(22725),r=s(88578),a=s(8117),l=s(5),o=s(41664),c=s.n(o),d=s(77522);let h=e=>{let{exercise:t}=e,s=(0,n.jsx)(r.X,{vizName:t.practiceSandbox,height:"500px",fileToOpen:t.fileToOpen}),o=(0,n.jsx)(r.X,{vizName:t.solutionSandbox,height:"500px",fileToOpen:t.fileToOpen});return(0,n.jsxs)("div",{children:[(0,n.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,n.jsxs)("div",{children:[(0,n.jsx)(a.C,{children:"To Do"}),(0,n.jsx)("div",{className:"mt-4",children:t.toDo})]}),(0,n.jsxs)("div",{children:[(0,n.jsx)(a.C,{children:"Why it matters"}),(0,n.jsx)("div",{className:"mt-4 pl-4",children:t.whyItMatters})]})]}),(0,n.jsxs)(i.mQ,{defaultValue:"practice",className:"relative",children:[(0,n.jsx)("div",{className:"flex justify-center items-center",children:(0,n.jsxs)(i.dr,{children:[(0,n.jsx)(i.SP,{value:"practice",children:"Practice"}),(0,n.jsx)(i.SP,{value:"solution",children:"Solution"})]})}),(0,n.jsxs)(i.nU,{value:"practice",children:[(0,n.jsx)("div",{className:"my-4",children:s}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c(),{className:(0,l.d)({size:"sm",variant:"destructive"}),href:"/sandbox?vizName="+t.practiceSandbox,target:"_blank",children:"Show full screen"})})]}),(0,n.jsxs)(i.nU,{value:"solution",children:[(0,n.jsx)("div",{className:"my-4",children:o}),(0,n.jsx)("div",{className:"absolute right-0",children:(0,n.jsx)(c(),{className:(0,d.cn)((0,l.d)({size:"sm",variant:"destructive"}),"no-underline"),href:"/sandbox?vizName="+t.solutionSandbox,target:"_blank",children:"Show full screen"})})]})]})]})}},41843:function(e,t,s){"use strict";s.d(t,{p:function(){return c}});var n=s(85893),i=s(49700),r=s(63476),a=s(17414),l=s(41664),o=s.n(l);let c=e=>{let{children:t,title:s,seoDescription:l,previousTocItem:c,nextTocItem:d}=e;return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(a.A,{title:s,seoDescription:l}),(0,n.jsx)(i.Z,{}),(0,n.jsx)("div",{className:"wrapper",children:t}),(0,n.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[c?(0,n.jsxs)(o(),{href:c.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,n.jsx)("p",{children:c.name})]}):(0,n.jsx)("div",{className:"w-96"}),d&&(0,n.jsxs)(o(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,n.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,n.jsx)("p",{children:d.name})]})]}),(0,n.jsx)("div",{className:"wrapper",children:(0,n.jsx)(r.Z,{})})]})}},80615:function(e,t,s){"use strict";s.d(t,{Y:function(){return i}});var n=s(85893);let i=e=>{let{children:t}=e;return(0,n.jsx)("p",{className:"text-sm text-gray-500 max-w-xs italic text-center mt-4 font-light",children:t})}},3572:function(e,t,s){"use strict";s.d(t,{d:function(){return d}});var n=s(85893),i=s(32581),r=s(15660),a=s.n(r),l=s(67294),o=s(45993),c=s.n(o);let d=e=>{let{code:t}=e,[s,r]=(0,l.useState)(!1),o=(0,l.useRef)(null);(0,l.useEffect)(()=>{o.current&&a().highlightElement(o.current)},[o,t]);let d=(0,n.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(t),r(!0)},className:c().codeChunckCopyButton,children:s?"Copied":(0,n.jsx)(i.Z,{size:14,style:{padding:0}})});return(0,n.jsxs)("div",{className:"mb-6 relative",children:[(0,n.jsx)("pre",{className:"rounded-md line-numbers",children:(0,n.jsx)("code",{ref:o,className:"language-javascript",children:t})}),(0,n.jsx)("div",{className:c().copyButtonContainer,children:d})]})}},7826:function(e,t,s){"use strict";s.d(t,{Qd:function(){return c},UQ:function(){return o},o4:function(){return d},vF:function(){return h}});var n=s(85893),i=s(67294),r=s(47398),a=s(8971),l=s(77522);let o=r.fC,c=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.ck,{ref:t,className:(0,l.cn)("border-b",s),...i})});c.displayName="AccordionItem";let d=i.forwardRef((e,t)=>{let{className:s,children:i,...o}=e;return(0,n.jsx)(r.h4,{className:"flex mt-0 pb-0 font-normal",children:(0,n.jsxs)(r.xz,{ref:t,className:(0,l.cn)("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",s),...o,children:[i,(0,n.jsx)(a.Z,{className:"h-4 w-4 shrink-0 transition-transform duration-200"})]})})});d.displayName=r.xz.displayName;let h=i.forwardRef((e,t)=>{let{className:s,children:i,...a}=e;return(0,n.jsx)(r.VY,{ref:t,className:"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",...a,children:(0,n.jsx)("div",{className:(0,l.cn)("pb-4 pt-0",s),children:i})})});h.displayName=r.VY.displayName},22725:function(e,t,s){"use strict";s.d(t,{SP:function(){return c},dr:function(){return o},mQ:function(){return l},nU:function(){return d}});var n=s(85893),i=s(67294),r=s(60434),a=s(77522);let l=r.fC,o=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.aV,{ref:t,className:(0,a.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",s),...i})});o.displayName=r.aV.displayName;let c=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.xz,{ref:t,className:(0,a.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",s),...i})});c.displayName=r.xz.displayName;let d=i.forwardRef((e,t)=>{let{className:s,...i}=e;return(0,n.jsx)(r.VY,{ref:t,className:(0,a.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",s),...i})});d.displayName=r.VY.displayName},16911:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return h}});var n=s(85893);s(67294);var i=s(43710),r=s(41843),a=s(11236),l=s(3572),o=s(47498),c=s(80615),d=s(13400);function h(){let e=a.Y.find(e=>"/course/axis/margin-and-translation"===e.link);return e?(0,n.jsxs)(r.p,{title:e.name,seoDescription:"",nextTocItem:a.Y.find(e=>"/course/axis/bottom-axis"===e.link),previousTocItem:a.Y.find(e=>"/course/axis/introduction"===e.link),children:[(0,n.jsx)(i.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("p",{children:["Most chart types use a ",(0,n.jsx)("b",{children:"bottom"})," and a ",(0,n.jsx)("b",{children:"left"})," axis."]}),(0,n.jsxs)("p",{children:["In these cases, we need to ",(0,n.jsx)("b",{children:"leave space"})," for tick labels and axis titles. Let’s look at how to implement this effectively."]})]})}),(0,n.jsx)("h2",{children:"SVG Area and Bounds Area"}),(0,n.jsxs)("p",{children:["Imagine an SVG area with a ",(0,n.jsx)("code",{children:"width"})," of 500px and a"," ",(0,n.jsx)("code",{children:"height"})," of 300px."]}),(0,n.jsxs)("p",{children:["The left and bottom axes aren’t displayed right at the SVG border. Instead, we add ",(0,n.jsx)("b",{children:"margins"})," on all sides: left, right, bottom, and top."]}),(0,n.jsxs)("p",{children:["The area within these margins is known as the ",(0,n.jsx)("b",{children:"bounds"}),", where the chart content is positioned between the x and y axes. In our code, we’ll refer to the width and height of this bounds area as"," ",(0,n.jsx)("code",{children:"boundsWidth"})," and ",(0,n.jsx)("code",{children:"boundsHeight"}),"."]}),(0,n.jsxs)("div",{className:"flex flex-col items-center mt-8 mb-12",children:[(0,n.jsx)("img",{src:"/excalidraw/bounds-explanation.png",style:{maxWidth:750},alt:"Anatomy of the chart areas: some margins are set all around the SVG area. The area inside is called the Bounds."}),(0,n.jsx)(c.Y,{children:"Anatomy of the chart areas: some margins are set all around the SVG area. The area inside is called the Bounds."})]}),(0,n.jsx)("h2",{children:"Implementation"}),(0,n.jsx)("p",{children:"A chart component often starts by defining its margins. An object with 4 properties is ideal for that:"}),(0,n.jsx)(l.d,{code:"\nconst MARGIN = {\n top: 10,\n right: 30,\n bottom: 50,\n left: 30\n}\n ".trim()}),(0,n.jsxs)("p",{children:["Since the chart component has defined ",(0,n.jsx)("code",{children:"width"})," and"," ",(0,n.jsx)("code",{children:"height"}),", we can easily determine the dimensions of the bounds area, referred to as ",(0,n.jsx)("code",{children:"boundsWidth"})," and"," ",(0,n.jsx)("code",{children:"boundsHeight"}),":"]}),(0,n.jsx)(l.d,{code:"\nconst boundsWidth = width - MARGIN.right - MARGIN.left;\nconst boundsHeight = height - MARGIN.top - MARGIN.bottom;\n ".trim()}),(0,n.jsx)("h3",{children:"\uD83E\uDE84 The tricky part"}),(0,n.jsx)("p",{children:"Finally the svg is going to be rendered like this:"}),(0,n.jsx)(l.d,{code:'\n\n '.trim()}),(0,n.jsx)("p",{children:"What's going on here? \uD83D\uDE31"}),(0,n.jsxs)("p",{children:["1️⃣ The SVG area is created as usual with the ",(0,n.jsx)("code",{children:"svg"})," element, along with the specified ",(0,n.jsx)("code",{children:"width"})," and ",(0,n.jsx)("code",{children:"height"}),"."]}),(0,n.jsxs)("p",{children:["2️⃣ The ",(0,n.jsx)("code",{children:"g"})," element is used to group other SVG elements, similar to how a ",(0,n.jsx)("code",{children:"div"})," works in HTML. This group represents the bounds, defined by its ",(0,n.jsx)("code",{children:"boundsWidth"})," and"," ",(0,n.jsx)("code",{children:"boundsHeight"})," dimensions!"]}),(0,n.jsxs)("p",{children:["3️⃣ The ",(0,n.jsx)("code",{children:"transform"})," property is used to translate the bounds slightly to the right and down, creating space for the left and top margins!"]}),(0,n.jsx)("h2",{children:"Exercices"}),(0,n.jsx)(o.v,{localStorageId:e.link,exercises:[{title:(0,n.jsx)("span",{children:"Let's translate this! ↔️"}),content:(0,n.jsx)(d.q,{exercise:x[0]})},{title:(0,n.jsx)("span",{children:"Bubble plot kick off \uD83E\uDEE7"}),content:(0,n.jsx)(d.q,{exercise:x[1]})}]}),(0,n.jsx)("h2",{children:"Drawing the Axis"}),(0,n.jsxs)("p",{children:["Now that we’ve created space for it, it’s time to ",(0,n.jsx)("b",{children:"draw the axis"}),". Let’s build some reusable components for this!"]})]}):null}let x=[{whyItMatters:(0,n.jsx)(n.Fragment,{children:(0,n.jsx)("p",{children:"Almost all graphs use this translation mecanism! Let's code it once to integrate it for ever!"})}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["The ",(0,n.jsx)("code",{children:"Graph"})," component renders a SVG are that is 500px"," ",(0,n.jsx)("code",{children:"width"})," and 300px ",(0,n.jsx)("code",{children:"height"}),"."]}),(0,n.jsx)("li",{children:"The component define its margin as a const: 100px at the left and bottom, 30px at the top and right"}),(0,n.jsx)("li",{children:"The bounds is represented as a grey rectangle"}),(0,n.jsx)("li",{children:"Two circles are drawn within the rectangle. In a dataset where both the X and Y axes range from 0 to 100, render the circles at coordinates (33, 33) and (66, 66)."})]}),practiceSandbox:"exercise/BoundsAreaTranslationPractice",solutionSandbox:"exercise/BoundsAreaTranslationSolution",fileToOpen:"Graph.tsx"},{whyItMatters:(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)("p",{children:"Let's remind how to loop on a dataset to render shape."}),(0,n.jsx)("p",{children:"Oh and let's introduce a new scale type too!"})]}),toDo:(0,n.jsxs)("ul",{children:[(0,n.jsxs)("li",{children:["This time, loop on ",(0,n.jsx)("code",{children:"data"})," to render ",(0,n.jsx)("b",{children:"10 circles"}),", one for each item in the dataset."]}),(0,n.jsxs)("li",{children:["There is a ",(0,n.jsx)("code",{children:"size"})," property for each data item. Use it to control the circle size!"]}),(0,n.jsxs)("li",{children:["Data must be mapped to circle ",(0,n.jsx)("b",{children:"area"}),", not to circle ",(0,n.jsx)("b",{children:"radius"}),". Use the",(0,n.jsx)("code",{children:"scaleSqrt"})," function of d3 for that!"]})]}),practiceSandbox:"exercise/BubblePlotKickOffPractice",solutionSandbox:"exercise/BubblePlotKickOffSolution",fileToOpen:"Graph.tsx"}]},45993:function(e){e.exports={codeChunckCopyButton:"code-block_codeChunckCopyButton__yPrL_",copyButtonContainer:"code-block_copyButtonContainer__BrX9E"}}},function(e){e.O(0,[2343,7754,7823,9484,8190,3710,9774,2888,179],function(){return e(e.s=26327)}),_N_E=e.O()}]);
\ No newline at end of file
diff --git a/_next/static/chunks/pages/course/canvas/drawing-shapes-with-canvas-b987979bb2ffc953.js b/_next/static/chunks/pages/course/canvas/drawing-shapes-with-canvas-b987979bb2ffc953.js
new file mode 100644
index 00000000..2baba152
--- /dev/null
+++ b/_next/static/chunks/pages/course/canvas/drawing-shapes-with-canvas-b987979bb2ffc953.js
@@ -0,0 +1 @@
+(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[51],{73527:function(e,t,n){(window.__NEXT_P=window.__NEXT_P||[]).push(["/course/canvas/drawing-shapes-with-canvas",function(){return n(88908)}])},81122:function(e,t,n){"use strict";n.d(t,{$:function(){return o}});var s=n(85893),i=n(67294),r=n(59973),a=n(80615),l=n(88578),c=n(5);let o=e=>{let{VizComponent:t,vizName:n,height:o=400,maxWidth:d=800,caption:h,fileToOpen:x}=e,[u,f]=(0,i.useState)(!1),j=(0,i.useRef)(null),m=(0,r.B)(j);return(0,s.jsx)("div",{style:{marginLeft:"-50vw",left:"50%"},className:"my-4 py-4 w-screen relative",children:u?(0,s.jsxs)("div",{className:"flex flex-col items-center justify-center w-full",children:[(0,s.jsx)("div",{style:{maxWidth:2e3},className:"w-full z-50",children:(0,s.jsx)(l.X,{vizName:n,fileToOpen:x})}),(0,s.jsx)("div",{className:"flex justify-center mt-2",children:(0,s.jsx)(c.z,{size:"sm",onClick:()=>f(!u),children:"Hide Sandbox"})})]}):(0,s.jsxs)("div",{className:"flex flex-col items-center justify-center",children:[(0,s.jsx)("div",{className:"bg-gray-100 bg-opacity-50 w-screen flex justify-center z-50 pointer-events-none",children:(0,s.jsx)("div",{style:{height:o,width:"100%",maxWidth:d},ref:j,className:"pointer-events-auto",children:(0,s.jsx)(t,{height:o,width:m.width})})}),(0,s.jsx)(a.Y,{children:h}),(0,s.jsx)("div",{className:"flex justify-center",children:(0,s.jsx)(c.z,{size:"sm",onClick:()=>f(!u),children:"Show code"})})]})})}},88578:function(e,t,n){"use strict";n.d(t,{X:function(){return i}});var s=n(85893);n(67294);let i=e=>{let{vizName:t,height:n="500px",fileToOpen:i}=e;return console.log("rerendeeeerrrrr"),(0,s.jsx)("iframe",{src:"https://codesandbox.io/embed/github/holtzy/react-graph-gallery/tree/main/viz/"+t+"?fontsize=14&hidenavigation=1&theme=dark&expanddevtools=0&view=split"+(i?"&module=/".concat(i):""),style:{width:"100%",height:n,border:"solid",borderWidth:2,borderRadius:"4px",overflow:"hidden"},allow:"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking",sandbox:"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"})}},47498:function(e,t,n){"use strict";n.d(t,{v:function(){return d}});var s=n(85893),i=n(7826),r=n(13742),a=n(61108),l=n(67294),c=n(5),o=n(77522);let d=e=>{let{exercises:t,localStorageId:n}=e,[d,h]=(0,l.useState)([]),[x,u]=(0,l.useState)("");return(0,l.useEffect)(()=>{let e=localStorage.getItem(n),s=e?JSON.parse(e):Array(t.length).fill("todo");h(s)},[]),(0,s.jsx)(i.UQ,{value:x,onValueChange:u,type:"single",collapsible:!0,className:"w-full",children:t.map((e,t)=>(0,s.jsxs)(i.Qd,{value:"item-"+t,children:[(0,s.jsx)(i.o4,{className:"no-decoration hover:bg-gray-50",children:(0,s.jsxs)("div",{className:"text-sm flex justify-start gap-2 items-center",children:[(0,s.jsx)("div",{className:(0,o.cn)("text-xs h-6 w-6 flex justify-center items-center rounded-full text-center leading-none","todo"===d[t]?"bg-gray-200":"failed"===d[t]?"bg-red-300":"bg-green-300"),children:(0,s.jsx)("span",{style:{transform:"translateX(1px)"},children:t+1})}),(0,s.jsx)("span",{children:e.title}),"ok"===d[t]&&(0,s.jsx)(r.Z,{size:16,className:"text-green-500"}),"failed"===d[t]&&(0,s.jsx)(a.Z,{size:16,className:"text-red-500"}),"todo"===d[t]&&(0,s.jsx)("span",{className:"text-gray-400 font-thin",children:"ToDo"})]})}),(0,s.jsxs)(i.vF,{children:[e.content,(0,s.jsxs)("div",{className:"flex justify-center gap-4",children:[(0,s.jsx)(c.z,{variant:"outline",onClick:()=>{let e=[...d];e[t]="failed",h(e),localStorage.setItem(n,JSON.stringify(e)),u("")},children:"Failed"}),(0,s.jsxs)(c.z,{onClick:()=>{let e=[...d];e[t]="ok",h(e),localStorage.setItem(n,JSON.stringify(e)),u("")},children:["Done",(0,s.jsx)("span",{className:"ml-2",children:"\uD83C\uDF89"})]})]})]})]}))})}},13400:function(e,t,n){"use strict";n.d(t,{q:function(){return h}});var s=n(85893),i=n(22725),r=n(88578),a=n(8117),l=n(5),c=n(41664),o=n.n(c),d=n(77522);let h=e=>{let{exercise:t}=e,n=(0,s.jsx)(r.X,{vizName:t.practiceSandbox,height:"500px",fileToOpen:t.fileToOpen}),c=(0,s.jsx)(r.X,{vizName:t.solutionSandbox,height:"500px",fileToOpen:t.fileToOpen});return(0,s.jsxs)("div",{children:[(0,s.jsxs)("div",{className:"grid grid-cols-2 gap-4 pt-4",children:[(0,s.jsxs)("div",{children:[(0,s.jsx)(a.C,{children:"To Do"}),(0,s.jsx)("div",{className:"mt-4",children:t.toDo})]}),(0,s.jsxs)("div",{children:[(0,s.jsx)(a.C,{children:"Why it matters"}),(0,s.jsx)("div",{className:"mt-4 pl-4",children:t.whyItMatters})]})]}),(0,s.jsxs)(i.mQ,{defaultValue:"practice",className:"relative",children:[(0,s.jsx)("div",{className:"flex justify-center items-center",children:(0,s.jsxs)(i.dr,{children:[(0,s.jsx)(i.SP,{value:"practice",children:"Practice"}),(0,s.jsx)(i.SP,{value:"solution",children:"Solution"})]})}),(0,s.jsxs)(i.nU,{value:"practice",children:[(0,s.jsx)("div",{className:"my-4",children:n}),(0,s.jsx)("div",{className:"absolute right-0",children:(0,s.jsx)(o(),{className:(0,l.d)({size:"sm",variant:"destructive"}),href:"/sandbox?vizName="+t.practiceSandbox,target:"_blank",children:"Show full screen"})})]}),(0,s.jsxs)(i.nU,{value:"solution",children:[(0,s.jsx)("div",{className:"my-4",children:c}),(0,s.jsx)("div",{className:"absolute right-0",children:(0,s.jsx)(o(),{className:(0,d.cn)((0,l.d)({size:"sm",variant:"destructive"}),"no-underline"),href:"/sandbox?vizName="+t.solutionSandbox,target:"_blank",children:"Show full screen"})})]})]})]})}},41843:function(e,t,n){"use strict";n.d(t,{p:function(){return o}});var s=n(85893),i=n(49700),r=n(63476),a=n(17414),l=n(41664),c=n.n(l);let o=e=>{let{children:t,title:n,seoDescription:l,previousTocItem:o,nextTocItem:d}=e;return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.A,{title:n,seoDescription:l}),(0,s.jsx)(i.Z,{}),(0,s.jsx)("div",{className:"wrapper",children:t}),(0,s.jsxs)("div",{className:"flex justify-center items-center space-x-6 my-24 py-12 bg-muted/50",children:[o?(0,s.jsxs)(c(),{href:o.link,className:"text-gray-500 no-underline flex flex-col justify-start items-end w-96 h-32 border-r border-black p-8 hover:bg-muted ",children:[(0,s.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l to-fuchsia-300 from-blue-400 bg-clip-text",children:"← Previous"}),(0,s.jsx)("p",{children:o.name})]}):(0,s.jsx)("div",{className:"w-96"}),d&&(0,s.jsxs)(c(),{href:d.link,className:"text-gray-500 no-underline flex flex-col justify-start w-96 h-32 border-l border-black p-8 hover:bg-muted ",children:[(0,s.jsx)("span",{className:"uppercase font-light text-transparent bg-gradient-to-l from-fuchsia-300 to-blue-400 bg-clip-text",children:"Next →"}),(0,s.jsx)("p",{children:d.name})]})]}),(0,s.jsx)("div",{className:"wrapper",children:(0,s.jsx)(r.Z,{})})]})}},63265:function(e,t,n){"use strict";n.d(t,{D:function(){return i}});var s=n(85893);let i=e=>{let{text:t}=e;return(0,s.jsxs)("div",{className:"hidden absolute w-60 top-1/2 -right-10 border-l text-card-foreground border-card-foreground h-28 translate-x-full -translate-y-1/2 xl:flex items-center ",children:[(0,s.jsx)("span",{className:"",children:"→"}),(0,s.jsx)("span",{className:"text-sm ml-2 opacity-70",children:t})]})}},80615:function(e,t,n){"use strict";n.d(t,{Y:function(){return i}});var s=n(85893);let i=e=>{let{children:t}=e;return(0,s.jsx)("p",{className:"text-sm text-gray-500 max-w-xs italic text-center mt-4 font-light",children:t})}},3572:function(e,t,n){"use strict";n.d(t,{d:function(){return d}});var s=n(85893),i=n(32581),r=n(15660),a=n.n(r),l=n(67294),c=n(45993),o=n.n(c);let d=e=>{let{code:t}=e,[n,r]=(0,l.useState)(!1),c=(0,l.useRef)(null);(0,l.useEffect)(()=>{c.current&&a().highlightElement(c.current)},[c,t]);let d=(0,s.jsx)("div",{onClick:()=>{navigator.clipboard.writeText(t),r(!0)},className:o().codeChunckCopyButton,children:n?"Copied":(0,s.jsx)(i.Z,{size:14,style:{padding:0}})});return(0,s.jsxs)("div",{className:"mb-6 relative",children:[(0,s.jsx)("pre",{className:"rounded-md line-numbers",children:(0,s.jsx)("code",{ref:c,className:"language-javascript",children:t})}),(0,s.jsx)("div",{className:o().copyButtonContainer,children:d})]})}},7826:function(e,t,n){"use strict";n.d(t,{Qd:function(){return o},UQ:function(){return c},o4:function(){return d},vF:function(){return h}});var s=n(85893),i=n(67294),r=n(47398),a=n(8971),l=n(77522);let c=r.fC,o=i.forwardRef((e,t)=>{let{className:n,...i}=e;return(0,s.jsx)(r.ck,{ref:t,className:(0,l.cn)("border-b",n),...i})});o.displayName="AccordionItem";let d=i.forwardRef((e,t)=>{let{className:n,children:i,...c}=e;return(0,s.jsx)(r.h4,{className:"flex mt-0 pb-0 font-normal",children:(0,s.jsxs)(r.xz,{ref:t,className:(0,l.cn)("flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",n),...c,children:[i,(0,s.jsx)(a.Z,{className:"h-4 w-4 shrink-0 transition-transform duration-200"})]})})});d.displayName=r.xz.displayName;let h=i.forwardRef((e,t)=>{let{className:n,children:i,...a}=e;return(0,s.jsx)(r.VY,{ref:t,className:"overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down",...a,children:(0,s.jsx)("div",{className:(0,l.cn)("pb-4 pt-0",n),children:i})})});h.displayName=r.VY.displayName},22725:function(e,t,n){"use strict";n.d(t,{SP:function(){return o},dr:function(){return c},mQ:function(){return l},nU:function(){return d}});var s=n(85893),i=n(67294),r=n(60434),a=n(77522);let l=r.fC,c=i.forwardRef((e,t)=>{let{className:n,...i}=e;return(0,s.jsx)(r.aV,{ref:t,className:(0,a.cn)("inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",n),...i})});c.displayName=r.aV.displayName;let o=i.forwardRef((e,t)=>{let{className:n,...i}=e;return(0,s.jsx)(r.xz,{ref:t,className:(0,a.cn)("inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",n),...i})});o.displayName=r.xz.displayName;let d=i.forwardRef((e,t)=>{let{className:n,...i}=e;return(0,s.jsx)(r.VY,{ref:t,className:(0,a.cn)("mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",n),...i})});d.displayName=r.VY.displayName},59973:function(e,t,n){"use strict";n.d(t,{B:function(){return i}});var s=n(67294);let i=e=>{let t=()=>({width:e.current?e.current.offsetWidth:0,height:e.current?e.current.offsetHeight:0}),[n,i]=(0,s.useState)(t),r=()=>{i(t())};return(0,s.useEffect)(()=>(window.addEventListener("resize",r),()=>window.removeEventListener("resize",r)),[]),(0,s.useEffect)(()=>{r()},[e]),n}},88908:function(e,t,n){"use strict";n.r(t),n.d(t,{default:function(){return b}});var s=n(85893),i=n(67294),r=n(43710),a=n(41843),l=n(11236),c=n(81122);let o=e=>{let{width:t,height:n}=e,r=(0,i.useRef)(null);return(0,i.useEffect)(()=>{let e=r.current;if(!e)return;let s=e.getContext("2d");s.clearRect(0,0,t,n),s.beginPath(),s.arc(100,100,50,0,2*Math.PI),s.fillStyle="blue",s.fill()},[]),(0,s.jsx)("div",{children:(0,s.jsx)("canvas",{ref:r,width:t,height:n})})},d=e=>{let{width:t=700,height:n=400}=e;return 0===t?null:(0,s.jsx)(o,{width:t,height:n})};var h=n(3572),x=n(41664),u=n.n(x);let f=e=>{let{width:t,height:n}=e,r=(0,i.useRef)(null);return(0,i.useEffect)(()=>{let e=r.current;if(!e)return;let s=e.getContext("2d");s.clearRect(0,0,t,n),s.beginPath(),s.rect(100,100,80,50),s.fillStyle="purple",s.fill()},[]),(0,s.jsx)("div",{children:(0,s.jsx)("canvas",{ref:r,width:t,height:n})})},j=e=>{let{width:t=700,height:n=400}=e;return 0===t?null:(0,s.jsx)(f,{width:t,height:n})};var m=n(63265);let p=e=>{let{width:t,height:n}=e,r=(0,i.useRef)(null);return(0,i.useEffect)(()=>{let e=r.current;if(!e)return;let s=e.getContext("2d");s.clearRect(0,0,t,n),s.beginPath(),s.rect(50,50,150,150),s.fillStyle="purple",s.fill(),s.beginPath(),s.arc(240,80,70,0,2*Math.PI),s.fillStyle="orange",s.fill(),s.beginPath(),s.moveTo(110,140),s.lineTo(160,200),s.lineTo(60,200),s.closePath(),s.fillStyle="green",s.fill(),s.beginPath(),s.ellipse(300,170,80,20,Math.PI/4,0,2*Math.PI),s.fillStyle="blue",s.fill()},[]),(0,s.jsx)("div",{children:(0,s.jsx)("canvas",{ref:r,width:t,height:n})})},g=e=>{let{width:t=700,height:n=400}=e;return 0===t?null:(0,s.jsx)(p,{width:t,height:n})};var v=n(47498),w=n(13400);function b(){let e=l.Y.find(e=>"/course/canvas/drawing-shapes-with-canvas"===e.link);return e?(0,s.jsxs)(a.p,{title:e.name,seoDescription:"",nextTocItem:l.Y.find(e=>"/course/canvas/combining-svg-and-canvas"===e.link),previousTocItem:l.Y.find(e=>"/course/canvas/introduction"===e.link),children:[(0,s.jsx)(r.Z,{title:e.name,lessonStatus:e.status,readTime:e.readTime,selectedLesson:e,description:(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)("p",{children:["Remember the"," ",(0,s.jsx)(u(),{href:"'/course/svg/introduction'",children:"SVG module"})," where we learned how to draw various shapes on the screen? Now, we'll be doing this again, but with ",(0,s.jsx)("code",{children:"canvas"})," instead—and the approach is quite different!"]}),(0,s.jsx)("p",{children:"Let's make some circles again! \uD83C\uDF89"})]})}),(0,s.jsx)("h2",{children:"Let's make a circle (again)"}),(0,s.jsxs)("h3",{children:["\uD83D\uDCCD Start with a ",(0,s.jsx)("code",{children:"canvas"})," element"]}),(0,s.jsxs)("p",{children:["Everything begins with the DOM. In the ",(0,s.jsx)("code",{children:"return"})," statement of our graph component, rather than rendering multiple SVG elements as we did previously,"]}),(0,s.jsxs)("p",{children:["we now render ",(0,s.jsx)("u",{children:"just a single"})," ",(0,s.jsx)("code",{children:"canvas"})," element."]}),(0,s.jsx)(h.d,{code:"\nreturn (\n