Public
Edited
Feb 26, 2024
Paused
1 fork
8 stars
Insert cell
Insert cell
Insert cell
Insert cell
// Array of File Attachments Promises
fileAttachments = [
FileAttachment("Act_1-Scene_1.jpg"),
FileAttachment("Act_1-Scene_2.jpg"),
FileAttachment("Act_1-Scene_3.jpg"),
FileAttachment("Act_1-Scene_4.jpg"),
FileAttachment("Act_2-Scene_1.jpg"),
FileAttachment("Act_2-Scene_2.jpg"),
FileAttachment("Act_2-Scene_3.jpg"),
FileAttachment("Act_2-Scene_4.jpg"),
FileAttachment("Act_2-Scene_5.jpg"),
FileAttachment("Act_2-Scene_6.jpg")
]
Insert cell
Insert cell
viewof height = Inputs.range([100, 800], {
label: "Image Height (pixels)",
value: 200,
step: 1
})
Insert cell
carouselImage = fileAttachments[index].image({
height: height,
width: 0.75 * height
})
Insert cell
Insert cell
Insert cell
Insert cell
viewof toggleImage = Inputs.toggle({
label: html`${await fileAttachments[index].image({
height: 100,
width: 75
})}`,
value: fileAttachments[index].name,
values: [fileAttachments[index].name, "No image selected"]
})
Insert cell
Insert cell
Insert cell
images = await Promise.all(
fileAttachments.map(
async (file) =>
await file.image({
name: file.name, // Propagate name to image object.
height: 100,
width: 75,
url: await file.url() // Add image's url as an additional attribute.
})
)
)
Insert cell
Insert cell
viewof imageButton = Inputs.button(
images.map((image, i) => [image, () => image.name])
)
Insert cell
imageButton
Insert cell
Insert cell
Insert cell
imagesToClone = await Promise.all(
fileAttachments.map((file) =>
file.image({
name: file.name, // Propagate name to image object
height: 100,
width: 75
})
)
)
Insert cell
viewof imageButtonCloned = Inputs.button(
imagesToClone.map((image, i) => [image, () => image.cloneNode(true)]) // Return a clone of the image allowing for re-display
)
Insert cell
Cloned Image Selected: ${imageButtonCloned}
Insert cell
Insert cell
viewof imagesClonedRadio = {
const images = new Map(
(
await Promise.all(
fileAttachments.map((file) =>
file.image({
name: file.name,
height: 100,
width: 75
})
)
)
).map((image) => [image, image.cloneNode(true)]) // clone of image is used for the Map value
);

const getValue = (n) => {
let img;
const itr = images.values();

for (let i = 0; i < n; i++) {
img = itr.next().value;
}
return img;
};

return Inputs.radio(images, {
label: html`<b>Cloned Radio Images</b>`,
value: getValue(2),
format: ([img, imgClone]) => img
});
}
Insert cell
| Image Selected | Name | Height | Width |
| -------------- | ---- | ------ | ----- |
|${imagesClonedRadio} | ${imagesClonedRadio.name} | ${imagesClonedRadio.height} | ${imagesClonedRadio.width} |

Insert cell
Insert cell
viewof imagesClonedCheckBox = {
const images = new Map(
(
await Promise.all(
fileAttachments.map((file) =>
file.image({
name: file.name,
height: 100,
width: 75
})
)
)
).map((image) => [image, image.cloneNode(true)]) // clone of image is used for the Map value
);

return Inputs.checkbox(images, {
label: html`<b>Cloned Checkbox Images</b>`,
format: ([img, imgClone]) => img
});
}
Insert cell
// See: https://observablehq.com/@mbostock/html-in-markdown
md`<table>
<thead>
<tr>
<th>Image(s) Selected</th>
<th>Name</th>
<th>Height</th>
<th>Width</th>
</tr>
</thead>
<tbody>
${imagesClonedCheckBox.map(
(image) =>
html`<tr>
<td> ${image} <td> ${image.name} <td> ${image.height} <td> ${image.width}`
)}
</tbody>
</table>`
Insert cell
Insert cell
// Additional metadata for images via: https://github.com/mattiasw/ExifReader
// exifMetadata will be reused later on in the notebook
exifMetadata = await Promise.all(
fileAttachments.map(async (file) => {
const arrayBuffer = await file.arrayBuffer();
return await ExifReader.load(arrayBuffer);
})
)
Insert cell
Insert cell
Insert cell
// Array of keyed images
keyedImages = (
await Promise.all(
// exifMetadata could have been created with that map via an async function, but it's in a separate cell for reuse later in the notebook
fileAttachments.map((file) =>
file.image({ name: file.name, height: height, width: 0.75 * height })
)
)
).map((image, i) => ({
name: image.name,
"JFIF Version": exifMetadata[i]["JFIF Version"].description, // Referenced in fileAttachments' order
image
}))
Insert cell
Insert cell
Insert cell
search
Insert cell
Insert cell
// Only 'search'-ed images are 'table'-ed
viewof imagesTable = Inputs.table(search, {
format: {
image: (image) => image.cloneNode(true) // Cloning allows re-dislay of original image from selections; if any.
}
})
Insert cell
Insert cell
imagesTable
Insert cell
html`Table image(s):${imagesTable.map(
(tableRow) => html`<br>${tableRow.name}: ${tableRow.image}`
)}`
Insert cell
Insert cell
imageMetadata = new Map(
Object.keys(exifMetadata[index]).map((attribute) => [
attribute,
exifMetadata[index][attribute].description
])
)
Insert cell
Insert cell
viewof imageAttribute = Inputs.select(imageMetadata, {
label: html`${await fileAttachments[index].image({
height: 150,
width: 150 * 0.75
})}`
})
Insert cell
imageAttribute
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more