### A Pluto.jl notebook ### # v0.17.0 using Markdown using InteractiveUtils # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). macro bind(def, element) quote local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end local el = $(esc(element)) global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) el end end # ╔═╡ db24490e-7eac-11ea-094e-9d3fc8f22784 md"# Introducing _bound_ variables With the `@bind` macro, Pluto.jl can synchronize a Julia variable with an HTML object!" # ╔═╡ bd24d02c-7eac-11ea-14ab-95021678e71e @bind x html"" # ╔═╡ cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2 md"This syntax displays the HTML object as the cell's output, and uses its latest value as the definition of `x`. Of course, the variable `x` is _reactive_, and all references to `x` come to life ✨ _Try moving the slider!_ 👆" # ╔═╡ cb1fd532-7eac-11ea-307c-ab16b1977819 x # ╔═╡ 816ea402-7eae-11ea-2134-fb595cca3068 md"" # ╔═╡ ce7bec8c-7eae-11ea-0edb-ad27d2df059d md"### Combining bonds The `@bind` macro returns a `Bond` object, which can be used inside Markdown and HTML literals:" # ╔═╡ fc99521c-7eae-11ea-269b-0d124b8cbe48 begin dog_slider = @bind 🐶 html"" cat_slider = @bind 🐱 html"" md""" **How many pets do you have?** Dogs: $(dog_slider) Cats: $(cat_slider) """ end # ╔═╡ 1cf27d7c-7eaf-11ea-3ee3-456ed1e930ea md""" You have $(🐶) dogs and $(🐱) cats! """ # ╔═╡ e3204b38-7eae-11ea-32be-39db6cc9faba md"" # ╔═╡ 5301eb68-7f14-11ea-3ff6-1f075bf73955 md"### Input types You can use _any_ DOM element that fires an `input` event. For example:" # ╔═╡ c7203996-7f14-11ea-00a3-8192ccc54bd6 md""" `a = ` $(@bind a html"") `b = ` $(@bind b html"") `c = ` $(@bind c html"") `d = ` $(@bind d html"") `e = ` $(@bind e html"") `f = ` $(@bind f html"") """ # ╔═╡ ede8009e-7f15-11ea-192a-a5c6135a9dcf (a, b, c, d, e, f) # ╔═╡ e2168b4c-7f32-11ea-355c-cf5932419a70 md"""**You can also use JavaScript to write more complicated input objects.** The `input` event can be triggered on any object using ```js obj.dispatchEvent(new CustomEvent("input")) ``` Try drawing a rectangle in the canvas below 👇 and notice that the `area` variable updates.""" # ╔═╡ 7f4b0e1e-7f16-11ea-02d3-7955921a70bd @bind dims html""" """ # ╔═╡ 5876b98e-7f32-11ea-1748-0bb47823cde1 area = abs(dims[1] * dims[2]) # ╔═╡ 72c7f60c-7f48-11ea-33d9-c5ea55a0ad1f dims # ╔═╡ d774fafa-7f34-11ea-290d-37805806e14b md"" # ╔═╡ 8db857f8-7eae-11ea-3e53-058a953f2232 md"""## Can I use it? The `@bind` macro is **built into Pluto.jl** — it works without having to install a package. You can use the (tiny) package [PlutoUI.jl](https://github.com/JuliaPluto/PlutoUI.jl) for some predefined input elements. For example, you use `PlutoUI` to write ```julia @bind x Slider(5:15) ``` instead of ```julia @bind x html"" ``` Have a look at the [sample notebook about PlutoUI](./sample/PlutoUI.jl.jl)! _The `@bind` syntax in not limited to `html"..."` objects, but **can be used for any HTML-showable object!**_ """ # ╔═╡ d5b3be4a-7f52-11ea-2fc7-a5835808207d md""" #### More packages In fact, **_any package_ can add bindable values to their objects**. For example, a geoplotting package could add a JS `input` event to their plot that contains the cursor coordinates when it is clicked. You can then use those coordinates inside Julia. Take a look at the [JavaScript sample notebook](./sample/JavaScript.jl) to learn more about these techniques! """ # ╔═╡ aa8f6a0e-303a-11eb-02b7-5597c167596d # ╔═╡ 5c1ececa-303a-11eb-1faf-0f3a6f94ac48 md"""## Separate definition and reference Interactivity works through reactivity. If you put a bond and a reference to the same variable together, then setting the bond will trigger the _entire cell_ to re-evaluate, including the bond itself. So **do not** write ```julia md""\"$(@bind r html"") $(r^2)""\" ``` Instead, create two cells: ```julia md""\"$(@bind r html"")""\" ``` ```julia r^2 ``` """ # ╔═╡ 55783466-7eb1-11ea-32d8-a97311229e93 # ╔═╡ 582769e6-7eb1-11ea-077d-d9b4a3226aac md"## Behind the scenes #### What is x? It's an **`Int64`**! Not an Observable, not a callback function, but simply _the latest value of the input element_. The update mechanism is _lossy_ and _lazy_, which means that it will skip values if your code is still running - and **only send the latest value when your code is ready again**. This is important when changing a slider from `0` to `100`, for example. If it would send all intermediate values, it might take a while for your code to process everything, causing a noticeable lag." # ╔═╡ 8f829274-7eb1-11ea-3888-13c00b3ba70f md"""#### What does the macro do? The `@bind` macro does not actually contain the interactivity mechanism, this is built into Pluto itself. Still, it does two things: it assigns a _default value_ to the variable (`missing` in most cases), and it wraps the second argument in a `PlutoRunner.Bond` object. For example, _expanding_ the `@bind` macro turns this expression: ```julia @bind x Slider(5:15) ``` into (simplified): ```julia begin local el = Slider(5:15) global x = AbstractPlutoDingetjes.intial_value(el) PlutoRunner.create_bond(el, :x) end ``` We see that the macro creates a variable `x`, which is given the value `AbstractPlutoDingetjes.intial_value(el)`. This function returns `missing` by default, unless a method was implemented for your widget type. For example, `PlutoUI` has a `Slider` type, and it defines a method for `intial_value(slider::Slider)` that returns the default number. Declaring a default value using `AbstractPlutoDingetjes` is **not necessary**, as shown by the earlier examples in this notebook, but the default value will be used for `x` if the `notebook.jl` file is _run as a plain julia file_, without Pluto's interactivity. You don't need to worry about this if you are just getting started with Pluto and interactive elements, but more advanced users should take a look at [`AbstractPlutoDingetjes.jl`](https://github.com/JuliaPluto/AbstractPlutoDingetjes.jl). """ # ╔═╡ ced18648-7eb2-11ea-2052-07795685f0da md"#### JavaScript? Yes! We are using `Generator.input` from [`observablehq/stdlib`](https://github.com/observablehq/stdlib#Generators_input) to create a JS _Generator_ (kind of like an Observable) that listens to `onchange`, `onclick` or `oninput` events, [depending on the element type](https://github.com/observablehq/stdlib#Generators_input). This makes it super easy to create nice HTML/JS-based interaction elements - a package creator simply has to write a `show` method for MIME type `text/html` that creates a DOM object that triggers the `input` event. In other words, _Pluto's `@bind` will behave exactly like [`viewof` in observablehq](https://observablehq.com/@observablehq/introduction-to-views)_. _If you want to make a cool new UI for Pluto, go to the [JavaScript sample notebook](./sample/JavaScript.jl) to learn how!_" # ╔═╡ dddb9f34-7f37-11ea-0abb-272ef1123d6f md"" # ╔═╡ 23db0e90-7f35-11ea-1c05-115773b44afa md"" # ╔═╡ f7555734-7f34-11ea-069a-6bb67e201bdc md"That's it for now! Let us know what you think using the feedback box below! 👇" # ╔═╡ Cell order: # ╟─db24490e-7eac-11ea-094e-9d3fc8f22784 # ╠═bd24d02c-7eac-11ea-14ab-95021678e71e # ╟─cf72c8a2-7ead-11ea-32b7-d31d5b2dacc2 # ╠═cb1fd532-7eac-11ea-307c-ab16b1977819 # ╟─816ea402-7eae-11ea-2134-fb595cca3068 # ╟─ce7bec8c-7eae-11ea-0edb-ad27d2df059d # ╠═fc99521c-7eae-11ea-269b-0d124b8cbe48 # ╠═1cf27d7c-7eaf-11ea-3ee3-456ed1e930ea # ╟─e3204b38-7eae-11ea-32be-39db6cc9faba # ╟─5301eb68-7f14-11ea-3ff6-1f075bf73955 # ╟─c7203996-7f14-11ea-00a3-8192ccc54bd6 # ╠═ede8009e-7f15-11ea-192a-a5c6135a9dcf # ╟─e2168b4c-7f32-11ea-355c-cf5932419a70 # ╟─7f4b0e1e-7f16-11ea-02d3-7955921a70bd # ╠═5876b98e-7f32-11ea-1748-0bb47823cde1 # ╠═72c7f60c-7f48-11ea-33d9-c5ea55a0ad1f # ╟─d774fafa-7f34-11ea-290d-37805806e14b # ╟─8db857f8-7eae-11ea-3e53-058a953f2232 # ╟─d5b3be4a-7f52-11ea-2fc7-a5835808207d # ╟─aa8f6a0e-303a-11eb-02b7-5597c167596d # ╟─5c1ececa-303a-11eb-1faf-0f3a6f94ac48 # ╟─55783466-7eb1-11ea-32d8-a97311229e93 # ╟─582769e6-7eb1-11ea-077d-d9b4a3226aac # ╟─8f829274-7eb1-11ea-3888-13c00b3ba70f # ╟─ced18648-7eb2-11ea-2052-07795685f0da # ╟─dddb9f34-7f37-11ea-0abb-272ef1123d6f # ╟─23db0e90-7f35-11ea-1c05-115773b44afa # ╟─f7555734-7f34-11ea-069a-6bb67e201bdc