Skip to content

Viewer.js

JavaScript image viewer.

Dynamic loading

      document.getElementById('button').addEventListener('click', function () {
        var image = new Image();

        image.src = '../images/tibet-1.jpg';

        var viewer = new Viewer(image, {
          hidden: function () {
            viewer.destroy();
          },
        });

        // image.click();
        viewer.show();
      });

Vue.js+Viewer.js component

<template>
  <div>
    <div
        v-if="loading"
        class="d-flex flex-row align-center justify-center"
        :style="progressStyle"
    >
      <v-progress-circular
          indeterminate
          :color="progressCircularColor"
      ></v-progress-circular>
    </div>
    <!-- a block container is required -->
    <div v-else>
      <img
          ref="image"
          :src="src"
          :alt="alt"
          :width="width"
          :height="height"
          :style="imgStyle"
      >
    </div>
  </div>
</template>

<script lang="ts">
import {Vue, Component, Prop, Ref, Watch} from 'vue-property-decorator';
import colors from 'vuetify/lib/util/colors'
import Viewer from 'viewerjs';
import 'viewerjs/dist/viewer.css';

function defaultOptions() {
  return {
    navbar: false,
    toolbar: {
      flipHorizontal: 1,
      flipVertical: 1,
      next: 0,
      oneToOne: 1,
      play: 0,
      prev: 0,
      reset: 1,
      rotateLeft: 1,
      rotateRight: 1,
      zoomIn: 1,
      zoomOut: 1,
    } as Viewer.ToolbarOptions,
  } as Viewer.Options;
}

@Component
export default class ImagePreview extends Vue {
  @Prop({type: String})
  readonly src!: string;

  @Prop({type: String})
  readonly alt!: string;

  @Prop({type: String})
  readonly backgroundColor!: string;

  @Prop({type: String})
  readonly progressColor!: string;

  @Prop({type: [String, Number]})
  readonly width!: string | number;

  @Prop({type: [String, Number]})
  readonly height!: string | number;

  @Prop({type: [String, Number]})
  readonly minWidth!: string | number;

  @Prop({type: [String, Number]})
  readonly minHeight!: string | number;

  @Prop({type: [String, Number]})
  readonly maxWidth!: string | number;

  @Prop({type: [String, Number]})
  readonly maxHeight!: string | number;

  @Prop({type: Object, default: defaultOptions})
  readonly options!: Viewer.Options;

  @Prop({type: Boolean})
  readonly loading!: boolean;

  @Prop({type: Boolean})
  readonly preview!: boolean;

  @Ref()
  readonly image!: HTMLImageElement;

  viewer?: Viewer;

  mounted() {
    this.refreshViewer();
  }

  @Watch('options')
  watchOptions() {
    this.refreshViewer();
  }

  refreshViewer() {
    if (this.preview) {
      this.viewer = new Viewer(this.image, this.options);
    }
  }

  show() {
    if (this.viewer) {
      this.viewer.show();
    }
  }

  get progressCircularColor() {
    if (this.progressColor) {
      return this.progressColor;
    }
    if (this.$vuetify.theme.dark) {
      return colors.grey.darken1;
    } else {
      return colors.grey.lighten5;
    }
  }

  get previewBackgroundColor() {
    if (this.backgroundColor) {
      return this.backgroundColor;
    }
    if (this.$vuetify.theme.dark) {
      return colors.grey.darken3;
    } else {
      return colors.grey.lighten2;
    }
  }

  get progressStyle() {
    return {
      'width': this.width,
      'height': this.height,
      'min-width': this.minWidth,
      'min-height': this.minHeight,
      'max-width': this.maxWidth,
      'max-height': this.maxHeight,
      'background-color': this.previewBackgroundColor,
    };
  }

  get imgStyle() {
    return {
      'min-width': this.minWidth,
      'min-height': this.minHeight,
      'max-width': this.maxWidth,
      'max-height': this.maxHeight,
    };
  }
}
</script>

Features

  • Supports 52 options
  • Supports 23 methods
  • Supports 17 events
  • Supports modal and inline modes
  • Supports touch
  • Supports move
  • Supports zoom
  • Supports rotation
  • Supports scale (flip)
  • Supports keyboard
  • Cross-browser support

See also

Favorite site