Downloading Text, JSON and Images with clientside JavaScript

Recently on the Terra Draw website I wanted to add the ability to download a GeoJSON file - it struck me that I wasn't immediately aware how to do this with it exclusively being a client side app. After a bit of research I was able to construct a simple solution for this. I have generalised this to three examples, namely text, JSON and images that you can reuse in your apps.

The core of this is the URL.createObjectURL function in the browser, which can take a File, a Blob or a MediaStream and return a string containing an object URL that represents the source object. In the cases below we will create a Blob object which is an immutable raw data object.

Below I will show how to take this object URL and download it directly in the browser. We can do this using the download attribute on a anchor element. A common misconception is we need to attach the anchor element to the DOM, but actually this is not necessary. Following are examples for a .txt file, a .json file and a png image file.

Text File #

// Turn the JSON object into a string
const data = "Hello world";

// Pass the string to a Blob and turn it
// into an ObjectURL
const blob = new Blob([data], { type: "text/plain" });
const jsonObjectUrl = URL.createObjectURL(blob);

// Create an anchor element, set it's
// href to be the Object URL we have created
// and set the download property to be the file name
// we want to set
const filename = "example.txt";
const anchorEl = document.createElement("a");
anchorEl.href = jsonObjectUrl;
anchorEl.download = filename;

// There is no need to actually attach the DOM
// element but we do need to click on it
anchor.click();

// We don't want to keep a reference to the file
// any longer so we release it manually
URL.revokeObjectURL(jsonObjectUrl);

JSON #

const json = { numberProp: 1, stringProp: "hello world" };

// Turn the JSON object into a string
const data = JSON.stringify(json);

// Pass the string to a Blob and turn it
// into an ObjectURL
const blob = new Blob([data], { type: "application/json" });
const jsonObjectUrl = URL.createObjectURL(blob);

// Create an anchor element, set it's
// href to be the Object URL we have created
// and set the download property to be the file name
// we want to set
const filename = "example.json";
const anchorEl = document.createElement("a");
anchorEl.href = jsonObjectUrl;
anchorEl.download = filename;

// There is no need to actually attach the DOM
// element but we do need to click on it
anchor.click();

// We don't want to keep a reference to the file
// any longer so we release it manually
URL.revokeObjectURL(jsonObjectUrl);

Image #

const canvas = document.createElement("canvas");
const d = canvas.width;
const ctx = canvas.getContext("2d");

if (!ctx) {
throw new Error("Could not get canvas context");
}

// Create an image on the canvas,
// in this case a red triangle
ctx.beginPath();
ctx.moveTo(d / 2, 0);
ctx.lineTo(d, d);
ctx.lineTo(0, d);
ctx.closePath();
ctx.fillStyle = "red";
ctx.fill();

// Image type - png should be supported by all browser
// Many browsers will also support image/jpeg and image/webp too
const imageType = "image/png";

// Quality: a number between 0 and 1, where 0 is lowest quality
const imageQuality = 0.9;

// The canvas toBlob method will turn the canvas
// image into a blob for us to use
canvas.toBlob(
(blob) => {
const jsonObjectUrl = URL.createObjectURL(blob);

// Create an anchor element, set it's
// href to be the Object URL we have created
// and set the download property to be the file name
// we want to set
const anchorEl = document.createElement("a");
anchorEl.href = jsonObjectUrl;
anchorEl.download = "example.png";

// There is no need to actually attach the DOM
// element but we do need to click on it
anchorEl.click();
URL.revokeObjectURL(jsonObjectUrl);
},
imageType,
imageQuality
);

Published