🏠 back to Observable

toward an HTML custom-width (responsive) template following Torben (for the ES6 unaware)

I’m hoping someone will be willing to help me make use of @toja 's notebook explaining how to create a responsive <div> container into which I can import a map cell.

Here’s Torben’s notebook

I have been trying to re-cast it in HTML using exactly his example code, but I remain unsuccessful. Here’s my attempt:



<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">        
    </head>
    <body>
	
	<div id="chart" style="max-width: 600px"></div>
	
        <script type="module">
		var notebook = (await import("https://api.observablehq.com/@d3/bivariate-choropleth.js?v=3")).default
		
		var Runtime = await import("@observablehq/runtime@4/dist/runtime.js")
		
		var customWidth = function () {
		  return (new Runtime.Library).Generators.observe(function (change) {
			let width = change(target.clientWidth);
			function resized() {
			  let w = target.clientWidth;
			  if (w !== width) change(width = w);
			}
			window.addEventListener("resize", resized);
			return function () {
			  window.removeEventListener("resize", resized);
			};
		  });
		}

		var runtime = new Runtime.Runtime(Object.assign(new Runtime.Library, { width: customWidth }))
		
		document
		  .querySelector("#chart")
		  .appendChild(await runtime.module(notebook).value("chart"));

		</script>

    </body>
</html>

A couple of things appear to be issues:

  1. I am getting a Uncaught SyntaxError: Unexpected reserved word error on my use of await. Tooling around the internet tells me that this might have something to do with the need to specifically declare a function to be an async funtion, but I am a bit lost about how to do this.

  2. When I finally get to the bit on document I am guessing it will probably fail because of the way I just plunked it into my script.

Anyone willing to help out on this?

Thanks in advance!!

Here’s a script that should work:

// use static imports because top-level `await` isn’t yet supported in browsers
import notebook from "https://api.observablehq.com/@d3/bivariate-choropleth.js?v=3";
// use a URL instead of a package reference because bare specifiers (like `@observablehq/runtime`) aren’t supported in browsers
import { Runtime, Library } from "https://unpkg.com/@observablehq/runtime@4/dist/runtime.js";

// only initialize the standard library once
const library = new Library()
function customWidth() {
  return library.Generators.observe(function(change) {
    let width = change(target.clientWidth);

    function resized() {
      let w = target.clientWidth;
      if (w !== width) change(width = w);
    }
    window.addEventListener("resize", resized);
    return function() {
      window.removeEventListener("resize", resized);
    };
  });
}
library.width = customWidth

const runtime = new Runtime(library)

// Replace the top-level `await` with `.then`
runtime.module(notebook)
  .value("chart")
  .then(function(chart) {
    document
      .querySelector("#chart")
      .appendChild(chart)
  });
1 Like

Also note that this doesn’t handle updates well. This is because module.value() returns a promise to the current value of the cell, which means that if the cell is re-evaluated, the .then() callback won’t be called. That’s why the default embed code uses this style instead:

runtime.module(notebook, function(name) {
  // called once at startup with the name of each named cell
  // in the notebook
  if (name === "chart") {
    return new Inspector(document.getElementById("chart"));
  }
});

1 Like

Awesome! Thanks @j-f1!! It works like a charm :slight_smile:

1 Like