wave icon indicating copy to clipboard operation
wave copied to clipboard

Image Grid

Open dott1718 opened this issue 3 years ago • 11 comments

Current implementations to nicely show multiple images or galleries in wave apps involve quite a bit of javascript and/or HTML & CSS usage. It would be helpful to further abstract that functionality to the wave framework and to add common image displays to speed up the app development process. It would also help to prevent speed issues and to align UX across wave apps.

We are looking for either a Carousel/Lightbox style implementation (https://www.joomforest.com/joomla-extensions/jf-responsive-carousel) or an Image Grid (https://www.w3schools.com/howto/howto_js_image_grid.asp)

Requirements:

  • Customizable in image width/height, number of images per row/column
  • Should take a list of image paths as input (open for discussion)
  • Automatic resizing for speed improvement
  • Responsive to clicks, e.g. trigger a reload and generate an args id or event
  • Add mouse hover tooltips per image
  • (lower priority) ability to show samples from image annotator with annotations (with mouse hover tooltips to show the corresponding classes to the boxes)
  • (optional) pre-caching

dott1718 avatar Aug 19 '22 11:08 dott1718

Some designs can be found here. Let's discuss the API prior to implementation. cc @lo5

mturoci avatar Sep 14 '22 11:09 mturoci

Proposal

Develop two separate components, Carousel Card and Image Grid Card. Both open a lightbox (modal with image) when an image is clicked. We could also somehow integrate Image Grid with Carousel Card by using a "View All" button that opens a modal with Image Grid.

Proposed API for Carousel Card

export interface State {
  /** An identifying name for this component. */
  name: Id
  /** List of images to be displayed. */
  images: Image[]
  /** True if the current image should be submitted when the image changes. */
  trigger?: B
}

// Similar to Image Card but with description
/** Create an image. */
export interface Image {
  /** The image title, displayed under the image. */
  title: S
  /** The image description, displayed under the title. */
  description: S
  /** The image MIME subtype. One of `apng`, `bmp`, `gif`, `x-icon`, `jpeg`, `png`, `webp`. Required only if `image` is set. */
  type?: S
  /** Image data, base64-encoded. */
  image?: S
  /** The path or URL or data URL of the image, e.g. `/foo.png` or `http://example.com/foo.png` or `data:image/png;base64,???`. */
  path?: S
  /** The width of the image, e.g. '100px'. */
  width?: S
  /** True if the component should be visible. Defaults to true. */
  visible?: B
}

Questions

@mturoci

Should we display multiple images (pages) in a Carousel? image

Do we also need to support this variant?

image

What about having the title displayed between the image and description instead of using a tooltip? Screenshot 2022-09-14 at 14 54 22

@dott1718 what do you mean exactly by "Automatic resizing for speed improvement"?

aalencar avatar Sep 15 '22 11:09 aalencar

related to #1542

aalencar avatar Sep 15 '22 12:09 aalencar

Currently we implement it with a markup card, therefore we need to manually load, resize and save resized images for them to occupy same area sizes on the card. It would be great if the component will be able to e.g. take the raw image paths and take care of resizing, therefore saving resized images to disk will not be needed anymore.

dott1718 avatar Sep 16 '22 09:09 dott1718

After discussing with @dott1718, we decided to go with Image Grid as of now. Resizing should be done on the Python side though.

aalencar avatar Sep 16 '22 10:09 aalencar

As for API I would reuse existing ui.image so the API I would start with would be:

export interface State {
  /** An identifying name for this component. */
  name: Id
  /** List of images to be displayed. */
  images: Image[]
}

mturoci avatar Sep 16 '22 10:09 mturoci

Implemetation notes: add virtualization and as a stretch goal create a dynamic grid that minimizes gaps between images of different sizes.

aalencar avatar Sep 22 '22 13:09 aalencar

Hi, I would like to work on this issue if it is still available.

jding712 avatar Nov 30 '22 04:11 jding712

You can go for it if you feel like, but it's pretty complex. I would suggest having a look at good first issues if you are first-time contributor to this project.

mturoci avatar Nov 30 '22 08:11 mturoci

Hello! I'm working alongside @jding712. We're basing our implementation on this PR: https://github.com/h2oai/wave/pull/1112. One question I had, mostly out of curiosity: how does wave know the connection between the Python-side components (i.e. TallStatsCard) with the typescript-side cards (i.e. cards.register('tall_stats', View)?

knassre-cmu avatar Dec 03 '22 17:12 knassre-cmu

how does wave know the connection between the Python-side components

We have a generator that creates python API off the TS API. See https://github.com/h2oai/wave/blob/master/tools/wavegen/src/wavegen.ts. Then these objects are serialized and sent over (browser => server, server => browser) via a websocket connection.

If you would like to test your changes by creating a python example (recommended), you need to run make generate once you have your TS interface ready to create it's Python counterpart. We also recommend going through the contributing guide first to get you started.

mturoci avatar Dec 05 '22 08:12 mturoci