CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue-cropper

A Vue.js component that provides comprehensive image cropping functionality for Vue 2 applications.

Pending
Overview
Eval results
Files

event-handling.mddocs/

Event Handling

Comprehensive event system for responding to image loading, cropping interactions, and real-time preview updates in VueCropper.

Capabilities

Image Loading Events

Events fired during image loading and processing phases.

/**
 * Image load completion event
 * @param status - "success" for successful load, "error" for failures, or Error object
 */
@img-load: (status: 'success' | 'error' | Error) => void;

/**
 * Detailed error information when image loading fails
 * @param error - Error object with failure details
 */
@img-load-error: (error: Error) => void;

Usage Examples:

<template>
  <VueCropper
    :img="imageUrl"
    @img-load="handleImageLoad"
    @img-load-error="handleImageError"
  />
</template>

<script>
export default {
  methods: {
    handleImageLoad(status) {
      if (status === 'success') {
        console.log('Image loaded successfully');
        this.imageReady = true;
      } else if (status === 'error') {
        console.error('Failed to load image');
        this.showErrorMessage = true;
      } else if (status instanceof Error) {
        console.error('Image load error:', status.message);
      }
    },
    
    handleImageError(error) {
      console.error('Detailed error:', error);
      this.errorDetails = error.message;
      this.showRetryOption = true;
    }
  }
};
</script>

Movement and Interaction Events

Events fired during user interactions with the image and crop box.

/**
 * Image movement/dragging events
 * @param data - Movement data with position information
 */
@img-moving: (data: MovingData) => void;

/**
 * Crop box movement/dragging events  
 * @param data - Movement data with crop box position
 */
@crop-moving: (data: MovingData) => void;

/**
 * Crop box size change events (modern name)
 * @param data - Size change data with dimensions
 */
@change-crop-size: (data: CropSizeData) => void;

/**
 * Legacy camelCase events (for compatibility)
 */
@imgLoad: (status: 'success' | 'error' | Error) => void;
@imgMoving: (data: MovingData) => void;
@realTime: (data: PreviewData) => void;
@changeCropSize: (data: CropSizeData) => void;
@cropMoving: (data: MovingData) => void;

interface MovingData {
  moving: boolean;
  axis: {
    x1: number;  // top-left x coordinate
    x2: number;  // top-right x coordinate  
    y1: number;  // top-left y coordinate
    y2: number;  // bottom-right y coordinate
  };
}

interface CropSizeData {
  width: number;     // crop box width
  height: number;    // crop box height
}

Usage Examples:

<template>
  <VueCropper
    :img="imageUrl"
    @img-moving="handleImageMove"
    @crop-moving="handleCropMove"
    @change-crop-size="handleCropSizeChange"
  />
  
  <div class="status-panel">
    <p>Image Moving: {{ imageMoving ? 'Yes' : 'No' }}</p>
    <p>Crop Position: {{ cropPosition.x }}, {{ cropPosition.y }}</p>
    <p>Crop Size: {{ cropSize.width }} × {{ cropSize.height }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageMoving: false,
      cropPosition: { x: 0, y: 0 },
      cropSize: { width: 0, height: 0 }
    };
  },
  methods: {
    handleImageMove(data) {
      this.imageMoving = data.moving;
      if (data.moving) {
        console.log('Image being dragged to:', data.axis);
        // Update UI to show drag state
        this.showDragIndicator = true;
      } else {
        this.showDragIndicator = false;
      }
    },
    
    handleCropMove(data) {
      if (data.moving) {
        this.cropPosition = {
          x: data.axis.x1,
          y: data.axis.y1
        };
        // Sync with external preview or coordinates display
        this.updateExternalPreview(data.axis);
      }
    },
    
    handleCropSizeChange(data) {
      this.cropSize = {
        width: data.width,
        height: data.height
      };
      // Validate minimum/maximum sizes
      if (data.width < 50 || data.height < 50) {
        this.showSizeWarning = true;
      }
    }
  }
};
</script>

Real-time Preview Events

Core event for implementing live preview functionality.

/**
 * Real-time preview updates during cropping operations
 * @param data - Complete preview data for rendering external previews
 */
@real-time: (data: PreviewData) => void;

interface PreviewData {
  url: string;      // preview image URL/base64
  img: string;      // CSS transform styles for image element
  div: string;      // CSS transform styles for container element  
  w: number;        // preview width in pixels
  h: number;        // preview height in pixels
}

Usage Examples:

<template>
  <div class="cropper-layout">
    <div class="main-cropper">
      <VueCropper
        :img="imageUrl"
        @real-time="handleRealTimePreview"
      />
    </div>
    
    <div class="preview-panels">
      <!-- Large Preview -->
      <div class="preview-large">
        <h3>Large Preview</h3>
        <div 
          class="preview-container"
          :style="{ width: previews.w + 'px', height: previews.h + 'px' }"
        >
          <div :style="previews.div">
            <img :src="previews.url" :style="previews.img">
          </div>
        </div>
      </div>
      
      <!-- Small Preview -->
      <div class="preview-small">
        <h3>Small Preview (50%)</h3>
        <div 
          class="preview-container"
          :style="{ 
            width: (previews.w * 0.5) + 'px', 
            height: (previews.h * 0.5) + 'px',
            overflow: 'hidden'
          }"
        >
          <div :style="{
            ...parseCSSTransform(previews.div),
            zoom: 0.5
          }">
            <img :src="previews.url" :style="previews.img">
          </div>
        </div>
      </div>
      
      <!-- Fixed Size Preview -->
      <div class="preview-fixed">
        <h3>Avatar Preview (100x100)</h3>
        <div 
          class="preview-container avatar-preview"
          :style="{ 
            width: '100px', 
            height: '100px',
            overflow: 'hidden',
            borderRadius: '50%'
          }"
        >
          <div :style="{
            ...parseCSSTransform(previews.div),
            zoom: 100 / previews.w
          }">
            <img :src="previews.url" :style="previews.img">
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageUrl: '/path/to/image.jpg',
      previews: {
        url: '',
        img: '',
        div: '',
        w: 0,
        h: 0
      }
    };
  },
  methods: {
    handleRealTimePreview(data) {
      this.previews = data;
      
      // Optional: emit to parent component
      this.$emit('preview-updated', data);
      
      // Optional: store for later use
      this.lastPreviewData = data;
    },
    
    parseCSSTransform(cssString) {
      // Helper to parse CSS transform string into object
      // Implementation depends on your specific needs
      return {
        transform: cssString
      };
    }
  }
};
</script>

<style scoped>
.cropper-layout {
  display: flex;
  gap: 20px;
}

.main-cropper {
  flex: 1;
  height: 400px;
}

.preview-panels {
  width: 300px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

.preview-container {
  border: 1px solid #ddd;
  margin: 5px;
  position: relative;
}

.avatar-preview {
  border: 2px solid #007bff;
}
</style>

Install with Tessl CLI

npx tessl i tessl/npm-vue-cropper

docs

component-configuration.md

event-handling.md

index.md

programmatic-control.md

tile.json