0

Làm chủ OpenSeadragon Bài 3: Cài đặt & Tích hợp cơ bản - Đưa OpenSeadragon vào Vanilla JS và các Framework hiện đại như ReactJS / VueJS.

Chào mừng bạn đến với bài đầu tiên trong series Làm chủ OpenSeadragon [cite: x]. Ở bài viết này, chúng ta sẽ cùng bóc tách những khái niệm cơ bản nhất: Deep Zoom là gì, OpenSeadragon đóng vai trò ra sao trong kiến trúc Frontend, và tại sao đây lại là "cứu cánh" cho các dự án Web phải xử lý hình ảnh chất lượng siêu cao [cite: x].


1. Cài đặt thư viện

Khởi tạo hoặc mở dự án ReactJS của bạn (sử dụng Vite, Create React App hoặc Next.js đều được). Mở terminal và chạy lệnh sau để cài đặt OpenSeadragon [cite: x]:

npm install openseadragon
# hoặc
yarn add openseadragon

2. Chuẩn bị tài nguyên tĩnh (Static Assets)

Trước khi code, bạn cần chú ý hai tài nguyên tĩnh bắt buộc phải có để OSD hoạt động [cite: x]:

  • Dữ liệu DZI: Copy file hinh-goc.dzi và thư mục hinh-goc_files (đã tạo ở Bài 2) vào thư mục public của dự án React (ví dụ: public/deepzoom/) [cite: x].
  • Bộ icon điều hướng của OSD: OpenSeadragon có sẵn các icon nút bấm (zoom in, zoom out, home, full screen). Bạn cần copy thư mục images từ node_modules/openseadragon/build/openseadragon/images/ thả vào thư mục public (ví dụ: public/osd-images/) [cite: x].

3. Xây dựng Component DeepZoomViewer

Tạo một file mới tên là DeepZoomViewer.jsx. Ý tưởng cốt lõi ở đây là tạo một thẻ <div> trống, sau đó dùng useEffect để yêu cầu OSD "bơm" bản vẽ (canvas) của nó vào trong <div> đó [cite: x].

Dưới đây là đoạn code chuẩn nhất để tích hợp [cite: x]:

import React, { useEffect, useRef } from 'react';
import OpenSeadragon from 'openseadragon';

const DeepZoomViewer = () => {
  // Sử dụng useRef để lưu trữ instance của viewer, giúp dọn dẹp (cleanup) dễ dàng
  const viewerRef = useRef(null);

  useEffect(() => {
    // Khởi tạo OpenSeadragon
    viewerRef.current = OpenSeadragon({
      id: 'osd-container', // Trùng với id của thẻ div bên dưới
      prefixUrl: '/osd-images/', // Đường dẫn tới thư mục chứa icon điều hướng
      tileSources: '/deepzoom/hinh-goc.dzi', // Đường dẫn tới file DZI
      
      // Các tuỳ chọn UI cơ bản
      showNavigator: true, // Hiển thị bản đồ mini (minimap) ở góc
      navigatorPosition: 'BOTTOM_RIGHT',
      animationTime: 0.5, // Tốc độ hiệu ứng zoom/pan (giây)
      blendTime: 0.1, // Thời gian mờ dần khi load các mảnh ảnh mới
      constrainDuringPan: true, // Không cho phép người dùng kéo ảnh ra ngoài khu vực xem
      maxZoomPixelRatio: 2, // Giới hạn mức độ zoom tối đa
    });

    // Cleanup function: Hủy instance khi component bị unmount
    return () => {
      if (viewerRef.current) {
        viewerRef.current.destroy();
        viewerRef.current = null;
      }
    };
  }, []); // Cấp dependency rỗng để chỉ chạy 1 lần khi mount

  return (
    <div 
      id="osd-container" 
      style={{ width: '100%', height: '800px', backgroundColor: '#000' }} 
    />
  );
};

export default DeepZoomViewer;

4. Giải thích các Cấu hình (Configuration) quan trọng

Trong đoạn code trên, object truyền vào OpenSeadragon({...}) chính là trái tim của hệ thống. Dưới đây là các keys quan trọng nhất bạn cần hiểu [cite: x]:

  • id: Chuỗi ID của thẻ HTML mà OSD sẽ render vào. Yêu cầu thẻ này bắt buộc phải có thông số widthheight cụ thể (có thể dùng px, vh, hoặc %) [cite: x].
  • prefixUrl: OSD dùng đường dẫn này để nối với tên các file ảnh icon (như zoomin_rest.png). Nếu bạn thấy các nút bấm bị lỗi (icon vỡ), chắc chắn 100% là cấu hình này đang trỏ sai thư mục [cite: x].
  • tileSources: Dữ liệu đầu vào. Nó có thể là URL trỏ tới file .dzi trên server của bạn, hoặc thậm chí là URL từ một server khác (nếu server đó đã mở CORS) [cite: x].
  • showNavigator: Mở tính năng Minimap (Bản đồ nhỏ). Rất hữu ích khi bức ảnh quá khổng lồ và người dùng cần biết mình đang đứng ở góc nào của bức tranh [cite: x].
  • constrainDuringPan: Nếu đặt là false, người dùng có thể kéo bức ảnh bay mất khỏi màn hình (chỉ còn lại nền đen). Đặt là true sẽ khóa ảnh lại trong giới hạn của khung nhìn [cite: x].

5. Lưu ý "Tử Huyệt" với React 18 Strict Mode

Nếu bạn dùng React 18 ở chế độ StrictMode (chế độ mặc định khi tạo app mới), React sẽ cố tình render useEffect 2 lần trong môi trường Development để giúp bạn tìm bug [cite: x].

Nếu bạn quên viết hàm dọn dẹp (return () => viewerRef.current.destroy()) trong useEffect, OpenSeadragon sẽ tạo ra hai cái viewer chồng đè lên nhau trong cùng một thẻ div. Các nút bấm sẽ bị nhân đôi và việc điều khiển zoom sẽ bị loạn [cite: x].

Đoạn code trong phần 3 đã xử lý triệt để vấn đề này bằng hàm destroy(), đảm bảo instance cũ luôn bị tiêu hủy trước khi instance mới (nếu có) được tạo ra [cite: x].


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí