UNPKG

smartdown-gallery

Version:

Example Smartdown documents and associated resources that demonstrate various Smartdown features and serve as raw material for other Smartdown demos.

258 lines (196 loc) 9.65 kB
### Inline Playables Smartdown's playable mechanism enables a variety of interactive content to be embedded into a document. By default, a playable is displayed in the way that a typical *figure* or *graphic* might be displayed, as a *block* that is separated from its preceding and following text. But there are many examples where an *inline* playable would be useful. This document explores Smartdown's attempts to make this a practical feature. #### Inhibiting paragraph breaks An early experiment with inlining playables relies up using special syntax to inhibit a paragraph's normal `display: block` policy and instead use an `display: inline` policy so that it abuts adjacent elements such as playables that have been annotated with `/inline`. - Ordinarily, Smartdown text is formatted in *paragraphs*, which are rendered with `display: inline-block`, which is usually what you want. - Smartdown playables are `display: block` by default, although the recently added `/inline` qualifier changes that to `inline-block`. - In order to get a playable to *abut* a paragraph, we need to adjust the adjacent paragraphs' `display` to be `inline`, when it detects that the playable is marked `/inline`. ##### Simple Examples Here is a P5JS circle: ```p5js/playable/autoplay/inline p5.setup = function() { }; p5.draw = function() { p5.ellipse(50, 50, 80, 80); }; ``` and here is a rectangle prefixed with math $E=mc^2$ ```p5js/playable/autoplay/inline p5.setup = function() { }; p5.draw = function() { p5.rect(5, 5, 80, 80); }; ``` $E=mc^2$ and also suffixed with the same math. So you can see how the circle and rectangle above were rendered inline with the text. #### Inline Target Div An alternative, and much more flexible, mechanism for adding inline playables is enabled by allowing Smartdown to create an *inline target div* easily, and then to reference that div in a subsequent playable. This allows the code that specifies an inline div's content to be placed elsewhere in the document source. ##### Animated Sparkline Example This initial example will demonstrate an animated [sparkline](https://en.wikipedia.org/wiki/Sparkline) adapted from the example from [http://bl.ocks.org/benjchristensen/1148374](http://bl.ocks.org/benjchristensen/1148374). First, we'll define a Javascript function `drawSparkline` which we will use in a few different contexts. ```d3/playable/autoplay function drawSparkline(id, width, height, interpolation, animate, updateDelay, transitionDelay) { // create an SVG element inside the #graph div that fills 100% of the div var graph = d3.select(id).append("svg:svg"); graph .attr("width", `${width}px`) .attr("height", `${height}px`); // create a simple data array that we'll plot with a line (this array represents only the Y values, X will just be the index location) var data = [3, 6, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 9, 3, 6, 3, 6, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 9, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 9, 3, 6, 2, 7, 5, 2, 1, 3, 8, 9, 2, 9]; // X scale will fit values from 0-10 within pixels 0-100 var x = d3.scaleLinear().domain([0, 48]).range([-5, width]); // starting point is -5 so the first value doesn't show and slides off the edge as part of the transition // Y scale will fit values from 0-10 within pixels 0-100 var y = d3.scaleLinear().domain([0, 10]).range([0, height]); // create a line object that represents the SVN line we're creating var line = d3.line() // assign the X function to plot our line as we wish .x(function(d,i) { // verbose logging to show what's actually being done //console.log('Plotting X value for data point: ' + d + ' using index: ' + i + ' to be at: ' + x(i) + ' using our xScale.'); // return the X coordinate where we want to plot this datapoint return x(i); }) .y(function(d) { // verbose logging to show what's actually being done //console.log('Plotting Y value for data point: ' + d + ' to be at: ' + y(d) + " using our yScale."); // return the Y coordinate where we want to plot this datapoint return y(d); }) .curve(d3.curveBasis); // display the line by appending an svg:path element with the data line we created above graph.append("svg:path").attr("d", line(data)); // or it can be done like this //graph.selectAll("path").data([data]).enter().append("svg:path").attr("d", line); function redrawWithAnimation() { // update with animation graph.selectAll("path") .data([data]) // set the new data .attr("transform", "translate(" + x(1) + ")") // set the transform to the right by x(1) pixels (6 for the scale we've set) to hide the new value .attr("d", line) // apply the new data values ... but the new value is hidden at this point off the right of the canvas .transition() // start a transition to bring the new value into view .ease("linear") .duration(transitionDelay) // for this demo we want a continual slide so set this to the same as the setInterval amount below .attr("transform", "translate(" + x(0) + ")"); // animate a slide to the left back to x(0) pixels to reveal the new value /* thanks to 'barrym' for examples of transform: https://gist.github.com/1137131 */ } function redrawWithoutAnimation() { // static update without animation graph.selectAll("path") .data([data]) // set the new data .attr("d", line); // apply the new data values } setInterval(function() { var v = data.shift(); // remove the first element of the array data.push(v); // add a new element to the array (we're just taking the number we just shifted off the front and appending to the end) if(animate) { redrawWithAnimation(); } else { redrawWithoutAnimation(); } }, updateDelay); } window.drawSparkline = drawSparkline; ``` ##### Sparkline playable that uses inline target div The playable below will use the `/&div1` syntax to direct its rendering to the div in the next paragraph. We'll test Smartdown's playable progress bar feature, so you should see a blueish progress bar in place of where the inline playable will eventually appear. That is, until you click this checkbox... [](:Xdoit), whereupon the `doit` variable will be defined and the playable will continue. Toggling the checkbox will do the obvious thing. This paragraph has an *inline target div* called `div1`. It's right here: [](:&div1) and uses the following syntax to specify that a Smartdown cell is to be created: `[](:&div1)`. This div can be populated by a playable that refers to DOM id `inline-target-div1`. Alternatively, the syntax `/&div1` can be added to the playable's definition, which will inhibit the normal creation of a playable div, and will ensure that `this.div` will refer to the targeted div `inline-target-div`. As another test, we'll also make the playable itself `/inline`, so the play/stop button should appear inline right here ... ```d3 /playable/autoplay/inline/&div1 const targetDiv1 = this.div; this.dependOn.doit = () => { if (env.doit) { this.div.innerHTML = ''; drawSparkline(this.div, 300, 30, "basis", false, 1000, 1000); } else { this.div.innerHTML = ''; } }; ``` ... and this text should follow the play/stop button. ##### Sparkline playable that uses paragraph break inhibition An early experiment with inlining playables relies up using special syntax to inhibit a paragraph's normal `display: block` policy and instead use an `display: inline` policy so that it abuts adjacent elements such as playables that have been annotated with `/inline`. Check out my sparkline without break inhibition ```d3 /playable/autoplay/inline drawSparkline(this.div, 300, 30, "basis", false, 1000, 1000); ``` Isn't it cool? ##### Non-Javascript Inline Playables We can use the same inline div target mechanism for other playable languages, such as Mermaid or Graphviz. Here's a little Graphviz diagram inlined into this paragraph right here ... [](:&graphviz1) ... and these words follow the graphic, which is defined in the playable below: ```graphviz/autoplay/playable/&graphviz1 digraph L0 { size = "2,2"; ordering=out; node [shape = box]; n0 [label="E"]; n1 [label="T"]; n2 [label="F"]; n3 [label="IDENT : a "]; n4 [label="+"]; n5 [label="T"]; n6 [label="F"]; n7 [label="("]; n8 [label="E"]; n9 [label="T"]; n10 [label="F"]; n11 [label="IDENT : b "]; n12 [label="*"]; n13 [label="F"]; n14 [label="IDENT : c "]; n15 [label=")"]; n16 [label="*"]; n17 [label="F"]; n18 [label="("]; n19 [label="E"]; n20 [label="T"]; n21 [label="F"]; n22 [label="IDENT : d "]; n23 [label="*"]; n24 [label="F"]; n25 [label="IDENT : e "]; n26 [label="+"]; n27 [label="T"]; n28 [label="F"]; n29 [label="("]; n30 [label="E"]; n31 [label="T"]; n32 [label="F"]; n33 [label="IDENT : a "]; n34 [label="*"]; n35 [label="F"]; n36 [label="IDENT : b "]; n37 [label=")"]; n38 [label=")"]; n39 [label="+"]; n40 [label="T"]; n41 [label="F"]; n42 [label="IDENT : q "]; n0 -> { n1 n4 n5 n39 n40 }; n1 -> n2 ; n2 -> n3 ; n5 -> { n6 n16 n17 }; n6 -> { n7 n8 n15 }; n8 -> n9 ; n9 -> { n10 n12 n13 }; n10 -> n11 ; n13 -> n14 ; n17 -> { n18 n19 n38 }; n19 -> { n20 n26 n27 }; n20 -> { n21 n23 n24 }; n21 -> n22 ; n24 -> n25 ; n27 -> n28 ; n28 -> { n29 n30 n37 }; n30 -> n31 ; n31 -> { n32 n34 n35 }; n32 -> n33 ; n35 -> n36 ; n40 -> n41 ; n41 -> n42 ; } ``` --- [Back to Home](:@Home)