Package detail

react-krpano-toolkit

vuvandinh123534MIT1.0.5

A React toolkit for KRPano integration with reusable functions and screen/hotspot configuration management

krpano, react, typescript, 360

readme

🎯 React Krpano toolkit

Vũ Văn Định - @your_github - vuvandinh.work@gmail.com - Website : vuvandinh.id.vn

📦 Cài đặt

Từ npm:

npm install react-krpano-toolkit

Từ yarn:

yarn add react-krpano-toolkit

📋 Mục lục

  1. Scene Operations
  2. View Operations
  3. Element Operations
  4. Sound Operations
  5. Control Operations
  6. Utility Operations
  7. Base Execute Function
  8. Shortcuts
  9. Kết hợp nhiều thao tác

🚀 Khởi tạo


📂 Cấu trúc thư mục gợi ý

public/
└── krpano/
    ├── tour.xml
    ├── tour.js
    ├── tour.swf
    └── tiles/...
src/
└── App.js
└── main.js

Tổng quan

react-krpano-toolkit là thư viện React mạnh mẽ giúp bạn tích hợp Krpano Panorama Viewer vào ứng dụng React một cách dễ dàng và linh hoạt. Thư viện cung cấp cả API core lẫn event system, hỗ trợ tương tác 2 chiều giữa React và Krpano.

Hook Nhóm Chức năng / Mô tả
useKrpano Core Tổng hợp Sự kiện sẽ gửi đi đến krpano .
useKrpanoGlobalAction Core Thực hiện các hành động global trên Krpano, như load scene, load panorama, reset view.
useControl Core Quản lý các control (buttons, UI) trong panorama, thao tác show/hide, enable/disable.
useElement Core Quản lý các element trong panorama như layers, hotspots, plugin, hỗ trợ thêm/xóa/sửa element.
useExecute Core Gọi trực tiếp các lệnh Krpano (execute) với chuỗi lệnh JS/krpano action.
useScene Core Quản lý scenes: chuyển scene, load scene mới, lấy thông tin scenes hiện có.
useSound Core Quản lý âm thanh: play, pause, stop, điều chỉnh volume, loop.
useUtility Core Các hàm tiện ích: lấy thông tin trạng thái, chuyển đổi tọa độ, tính toán góc nhìn.
useView Core Quản lý view (camera): thay đổi hlookat, vlookat, fov, zoom, và theo dõi thay đổi view.
useLoading Core Theo dõi trạng thái load panorama, hiển thị progress hoặc loading overlay.

Hook Nhóm Chức năng / Mô tả
useKrpanoEventBridge Events Hook core để tạo bridge giữa Krpano → React, nhận mọi event từ Krpano.
useKrpanoCommand Events Truy cập trực tiếp Krpano API từ context, cho phép gọi lệnh và đọc trạng thái Krpano.
useLayerEvents Events Lắng nghe các event liên quan đến layer: click, hover (over), out.
useHotspotEvent Events Lắng nghe các event liên quan đến hotspot: click, hover, out, down, up.
useViewEvents Events Lắng nghe thay đổi view: viewchange, viewchanged, idle.
useSceneEvents Events Lắng nghe sự kiện scene: new scene, remove scene.
useMouseEvents Events Lắng nghe các sự kiện chuột: click, dblclick, mousedown, mouseup, mousemove.
useSystemEvents Events Lắng nghe các sự kiện hệ thống Krpano: onloadcomplete, onxmlcomplete, onready, onerror, onresize, onfullscreenchange.
useKeyboardEvents Events Lắng nghe các sự kiện bàn phím: keydown, keyup, kèm thông tin keycode và modifier keys.
useKrpanoEventListener Events Quản lý sự kiện từ Krpano → React. Cho phép đăng ký, xóa, trigger các event hệ thống, scene, view, hotspot, layer, mouse, keyboard. Hỗ trợ cleanup tự động, setup hotspot/layer event dễ dàng và trigger custom event từ React.keys.

Bắt Đầu

Khởi tạo KrpanoProvider

KrpanoProvidercontext provider chịu trách nhiệm quản lý trạng thái và các API chung cho Krpano trong toàn bộ ứng dụng. Bạn cần bọc toàn bộ ứng dụng trong main.js (hoặc file root của React) để mọi component con có thể truy cập Krpano context.

// main.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { KrpanoProvider } from "./contexts/KrpanoProvider";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <KrpanoProvider>
      <App />
    </KrpanoProvider>
  </React.StrictMode>
);

Lưu ý: KrpanoProvider phải nằm ngoài App, để toàn bộ component trong App có thể sử dụng Krpano context.


2. Sử dụng KrpanoViewer trong App.js

KrpanoViewercomponent chính để hiển thị panorama. Bạn chỉ cần đặt component này vào nơi muốn hiển thị panorama.

// App.js
import React from "react";
import { KrpanoViewer } from "./components/KrpanoViewer";

function App() {
  return (
    <div style={{ width: "100%", height: "100vh" }}>
      <KrpanoViewer
        path="./krpano"      // Đường dn ti thư mc cha pano
        xmlName="tour.xml"   // (Tùy chn) Tên file XML, mc định là "tour.xml"
        jsName="tour.js"     // (Tùy chn) Tên file JS kèm theo, mc định là "tour.js"
        swfName="./krpano/tour.swf" // (Tùy chn) Tên file SWF, mc định "./krpano/tour.swf"
        style={{ width: "100%", height: "100%" }} // Tùy chnh CSS cho container
      />
    </div>
  );
}

export default App;

Các props của KrpanoViewer:

Prop Type Mặc định Mô tả
path string bắt buộc Đường dẫn tới thư mục chứa file panorama (XML, JS, SWF, images).
xmlName string "tour.xml" Tên file XML cấu hình panorama.
jsName string "tour.js" Tên file JS kèm theo (nếu có).
swfName string "./krpano/tour.swf" Tên file SWF cho fallback Flash (nếu cần).
style object {} Tùy chỉnh CSS cho container Krpano.

✅ Lưu ý quan trọng

  1. path phải chính xác tới thư mục chứa các file panorama (XML, JS, SWF, tiles...).
  2. Nếu bạn không truyền xmlName, jsName hoặc swfName, KrpanoViewer sẽ sử dụng giá trị mặc định.
  3. Container của KrpanoViewer cần có kích thước rõ ràng (widthheight), nếu không panorama sẽ không hiển thị đúng.
  4. KrpanoProvider phải bọc toàn bộ ứng dụng để hỗ trợ các hook và API context từ Krpano.

Sự kiện từ React gửi xuống Krpano

Scene Operations với hook useKrpano

Mục đích: Khi React muốn điều khiển panorama (Krpano), ví dụ thay đổi view, bật layer, zoom…

Ví dụ: Click button trong React để show/hide layer:

1. loadScene() - Chuyển scene

Mục đích: Chuyển đổi giữa các scene trong tour 360°

const krpano = useKrpano();

// ✅ Chuyển scene cơ bản
krpano.scene.loadScene('bedroom');

// ✅ Chuyển scene với hiệu ứng blend
krpano.scene.loadScene('kitchen', { 
  blend: 'BLEND(2.0)', // Fade 2 giây
  flags: 'MERGE'       // Merge với scene hiện tại
});

// ✅ Chuyển scene với hiệu ứng crossfade
krpano.scene.loadScene('livingroom', { 
  blend: 'CROSSBLEND(1.5)' // Crossfade 1.5 giây
});

// ✅ Chuyển scene ngay lập tức
krpano.scene.loadScene('bathroom', { 
  blend: 'NOBLEND' 
});

2. removeScene() - Xóa scene

Mục đích: Xóa scene khỏi bộ nhớ để tiết kiệm tài nguyên

// ✅ Xóa scene không cần thiết
krpano.scene.removeScene('old_scene');

// ✅ Xóa nhiều scene trong loop
const unusedScenes = ['temp1', 'temp2', 'temp3'];
unusedScenes.forEach(scene => {
  krpano.scene.removeScene(scene);
});

3. addScene() - Thêm scene mới

Mục đích: Thêm scene động vào tour

// ✅ Thêm scene trống
krpano.scene.addScene('new_scene');

// ✅ Thêm scene và load XML
krpano.scene.addScene('outdoor', '/xml/outdoor.xml');

// ✅ Thêm scene cho gallery động
const addGalleryScene = (imageUrl: string, sceneName: string) => {
  krpano.scene.addScene(sceneName);
  krpano.utility.set(`scene[${sceneName}].image.sphere`, imageUrl);
};

4. copyScene() - Sao chép scene

Mục đích: Tạo bản sao của scene để tùy chỉnh

// ✅ Sao chép scene làm template
krpano.scene.copyScene('master_bedroom', 'bedroom_variant');

// ✅ Tạo nhiều variant của cùng một scene
const createVariants = (baseScene: string) => {
  krpano.scene.copyScene(baseScene, `${baseScene}_night`);
  krpano.scene.copyScene(baseScene, `${baseScene}_day`);
};

View Operations

1. lookAt() - Nhìn về hướng cụ thể

Mục đích: Điều khiển hướng nhìn camera với animation mượt

// ✅ Nhìn về hướng cụ thể với animation
krpano.view.lookAt(90, 0, 80, { 
  smooth: true, 
  time: 2.0, 
  tween: 'easeInOutSine' 
});

// ✅ Nhìn ngay lập tức (không animation)
krpano.view.lookAt(180, -10, 90, { smooth: false });

// ✅ Tạo camera path (tour tự động)
const cameraPath = [
  { h: 0, v: 0, f: 90 },
  { h: 90, v: 10, f: 70 },
  { h: 180, v: -5, f: 100 },
  { h: 270, v: 5, f: 80 }
];

const startAutoTour = () => {
  cameraPath.forEach((point, index) => {
    setTimeout(() => {
      krpano.view.lookAt(point.h, point.v, point.f, {
        smooth: true,
        time: 3.0,
        tween: 'easeInOutQuad'
      });
    }, index * 4000);
  });
};

// ✅ Nhìn về hotspot
const lookAtHotspot = (hotspotName: string) => {
  const h = krpano.utility.get(`hotspot[${hotspotName}].ath`);
  const v = krpano.utility.get(`hotspot[${hotspotName}].atv`);
  krpano.view.lookAt(h, v, undefined, { smooth: true, time: 1.5 });
};

2. lookTo() - Di chuyển camera đến vị trí

Mục đích: Di chuyển camera mượt đến tọa độ cụ thể

// ✅ Di chuyển mượt đến vị trí
krpano.view.lookTo(45, 15, { smooth: true, time: 1.0 });

// ✅ Snap đến vị trí ngay lập tức
krpano.view.lookTo(90, 0, { smooth: false });

// ✅ Tạo shake effect
const shakeCamera = () => {
  const original = {
    h: krpano.utility.get('view.hlookat'),
    v: krpano.utility.get('view.vlookat')
  };

  for (let i = 0; i < 10; i++) {
    setTimeout(() => {
      krpano.view.lookTo(
        original.h + Math.random() * 4 - 2,
        original.v + Math.random() * 4 - 2,
        { smooth: false }
      );
    }, i * 50);
  }

  setTimeout(() => {
    krpano.view.lookTo(original.h, original.v, { smooth: true, time: 0.5 });
  }, 500);
};

3. zoomTo() - Zoom camera

Mục đích: Thay đổi field of view (độ rộng góc nhìn)

// ✅ Zoom in mượt
krpano.view.zoomTo(30, { smooth: true, time: 1.5 }); // Zoom in

// ✅ Zoom out mượt
krpano.view.zoomTo(120, { smooth: true, time: 1.0 }); // Zoom out

// ✅ Zoom ngay lập tức
krpano.view.zoomTo(90, { smooth: false }); // Standard view

// ✅ Tạo zoom pulse effect
const zoomPulse = () => {
  const originalFov = krpano.utility.get('view.fov');
  krpano.view.zoomTo(originalFov - 20, { smooth: true, time: 0.3 });
  setTimeout(() => {
    krpano.view.zoomTo(originalFov, { smooth: true, time: 0.3 });
  }, 300);
};

// ✅ Zoom levels preset
const zoomLevels = {
  wide: 120,
  normal: 90,
  medium: 60,
  close: 30,
  macro: 15
};

const setZoomLevel = (level: keyof typeof zoomLevels) => {
  krpano.view.zoomTo(zoomLevels[level], { smooth: true, time: 1.0 });
};

4. moveCamera() - Di chuyển camera theo hướng

Mục đích: Di chuyển camera theo các hướng cơ bản

// ✅ Di chuyển cơ bản
krpano.view.moveCamera('up', 10);    // Lên 10 độ
krpano.view.moveCamera('down', 5);   // Xuống 5 độ
krpano.view.moveCamera('left', 15);  // Trái 15 độ
krpano.view.moveCamera('right', 20); // Phải 20 độ

// ✅ Tạo camera drift effect
const startDrift = () => {
  const drift = () => {
    krpano.view.moveCamera('right', 0.5);
    setTimeout(drift, 100);
  };
  drift();
};

// ✅ Keyboard controls simulation
const handleKeyboard = (key: string) => {
  switch(key) {
    case 'ArrowUp': krpano.view.moveCamera('up', 5); break;
    case 'ArrowDown': krpano.view.moveCamera('down', 5); break;
    case 'ArrowLeft': krpano.view.moveCamera('left', 5); break;
    case 'ArrowRight': krpano.view.moveCamera('right', 5); break;
  }
};

5. stopMovement() - Dừng chuyển động

Mục đích: Dừng tất cả animation và chuyển động

// ✅ Dừng tất cả chuyển động
krpano.view.stopMovement();

// ✅ Emergency stop cho auto tour
const emergencyStop = () => {
  krpano.view.stopMovement();
  console.log('Tour stopped by user');
};

Element Operations

1. show() - Hiển thị element

Mục đích: Hiển thị hotspot/layer/plugin với hoặc không có animation

// ✅ Hiển thị ngay lập tức
krpano.element.show('hotspot', 'info_button');

// ✅ Hiển thị với fade in
krpano.element.show('hotspot', 'menu', { 
  time: 1.0, 
  tween: 'easeOutSine' 
});

// ✅ Hiển thị layer với slide effect
krpano.element.show('layer', 'sidebar', { 
  time: 0.8, 
  tween: 'easeOutBack' 
});

// ✅ Hiển thị theo sequence
const showSequence = (elements: string[]) => {
  elements.forEach((element, index) => {
    setTimeout(() => {
      krpano.element.show('hotspot', element, { time: 0.5 });
    }, index * 200);
  });
};

showSequence(['btn1', 'btn2', 'btn3', 'btn4']);

// ✅ Conditional show
const showIfCondition = (elementName: string, condition: boolean) => {
  if (condition) {
    krpano.element.show('hotspot', elementName);
  }
};

2. hide() - Ẩn element

Mục đích: Ẩn hotspot/layer/plugin với animation

// ✅ Ẩn ngay lập tức
krpano.element.hide('hotspot', 'temp_marker');

// ✅ Ẩn với fade out
krpano.element.hide('layer', 'overlay', { 
  time: 0.8, 
  tween: 'easeInSine' 
});

// ✅ Ẩn tất cả hotspots
const hideAllHotspots = (hotspotNames: string[]) => {
  hotspotNames.forEach(name => {
    krpano.element.hide('hotspot', name, { time: 0.3 });
  });
};

// ✅ Auto-hide sau thời gian
const autoHide = (elementName: string, delay: number) => {
  setTimeout(() => {
    krpano.element.hide('layer', elementName, { time: 0.5 });
  }, delay);
};

3. toggle() - Chuyển đổi hiển thị

Mục đích: Bật/tắt hiển thị element

// ✅ Toggle cơ bản
krpano.element.toggle('layer', 'menu');

// ✅ Toggle với tracking state
let menuVisible = false;
const toggleMenu = () => {
  krpano.element.toggle('layer', 'navigation');
  menuVisible = !menuVisible;
  console.log('Menu is now:', menuVisible ? 'visible' : 'hidden');
};

// ✅ Toggle group
const toggleGroup = (groupName: string) => {
  const elements = [`${groupName}_1`, `${groupName}_2`, `${groupName}_3`];
  elements.forEach(element => {
    krpano.element.toggle('hotspot', element);
  });
};

4. animate() - Tạo animation tùy chỉnh

Mục đích: Tạo các hiệu ứng animation phức tạp

// ✅ Animation đơn giản
krpano.element.animate('layer', 'popup', {
  x: 100,
  y: 200,
  alpha: 1.0
}, { time: 1.0, tween: 'easeOutBounce' });

// ✅ Animation phức tạp với nhiều thuộc tính
krpano.element.animate('hotspot', 'logo', {
  scale: 1.2,
  rotate: 360,
  alpha: 0.8,
  x: 50,
  y: -30
}, { 
  time: 2.0, 
  tween: 'easeInOutElastic',
  onComplete: 'trace(Animation completed!)'
});

// ✅ Pulse animation
const pulseAnimation = (elementName: string) => {
  krpano.element.animate('hotspot', elementName, {
    scale: 1.3,
    alpha: 0.7
  }, { time: 0.5, tween: 'easeOutSine' });

  setTimeout(() => {
    krpano.element.animate('hotspot', elementName, {
      scale: 1.0,
      alpha: 1.0
    }, { time: 0.5, tween: 'easeInSine' });
  }, 500);
};

// ✅ Floating animation
const floatingAnimation = (elementName: string) => {
  const float = () => {
    krpano.element.animate('hotspot', elementName, {
      y: krpano.utility.get(`hotspot[${elementName}].y`) - 10
    }, { time: 2.0, tween: 'easeInOutSine' });

    setTimeout(() => {
      krpano.element.animate('hotspot', elementName, {
        y: krpano.utility.get(`hotspot[${elementName}].y`) + 10
      }, { time: 2.0, tween: 'easeInOutSine' });
      setTimeout(float, 4000);
    }, 2000);
  };
  float();
};

// ✅ Shake animation
const shakeElement = (elementName: string) => {
  for (let i = 0; i < 6; i++) {
    setTimeout(() => {
      krpano.element.animate('hotspot', elementName, {
        x: krpano.utility.get(`hotspot[${elementName}].x`) + (i % 2 === 0 ? 5 : -5)
      }, { time: 0.1 });
    }, i * 100);
  }
};

5. addElement() - Thêm element mới

Mục đích: Tạo hotspot/layer/plugin động

// ✅ Thêm hotspot cơ bản
krpano.element.addElement('hotspot', 'new_marker', {
  url: 'images/marker.png',
  ath: 90,
  atv: 0,
  scale: 1.0,
  visible: true
});

// ✅ Thêm layer thông tin
krpano.element.addElement('layer', 'info_panel', {
  url: 'images/panel.png',
  x: 100,
  y: 100,
  width: 300,
  height: 200,
  alpha: 0.9,
  visible: true
});

// ✅ Thêm hotspot với sự kiện
krpano.element.addElement('hotspot', 'interactive_btn', {
  url: 'images/button.png',
  ath: 45,
  atv: 10,
  onclick: 'loadscene(next_room)'
});

// ✅ Tạo hotspot grid
const createHotspotGrid = (rows: number, cols: number) => {
  for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
      krpano.element.addElement('hotspot', `grid_${i}_${j}`, {
        url: 'images/grid_point.png',
        ath: (360 / cols) * j,
        atv: ((180 / rows) * i) - 90,
        scale: 0.5,
        alpha: 0.7
      });
    }
  }
};

6. removeElement() - Xóa element

Mục đích: Xóa hotspot/layer/plugin không cần thiết

// ✅ Xóa element đơn lẻ
krpano.element.removeElement('hotspot', 'temp_marker');

// ✅ Xóa nhiều elements
const removeElements = (elementNames: string[]) => {
  elementNames.forEach(name => {
    krpano.element.removeElement('hotspot', name);
  });
};

// ✅ Dọn dẹp elements với prefix
const cleanupElementsWithPrefix = (prefix: string) => {
  // Note: Trong thực tế cần get danh sách elements trước
  const elements = ['temp_1', 'temp_2', 'temp_3']; // Mock data
  elements.filter(name => name.startsWith(prefix))
          .forEach(name => {
            krpano.element.removeElement('hotspot', name);
          });
};

7. cloneElement() - Sao chép element

Mục đích: Tạo bản sao của element để tùy chỉnh

// ✅ Sao chép hotspot
krpano.element.cloneElement('hotspot', 'original_marker', 'cloned_marker');

// ✅ Tạo nhiều bản sao
const createClones = (originalName: string, count: number) => {
  for (let i = 1; i <= count; i++) {
    krpano.element.cloneElement('hotspot', originalName, `${originalName}_copy_${i}`);
  }
};

// ✅ Clone và modify
const cloneAndModify = (original: string, newName: string, modifications: any) => {
  krpano.element.cloneElement('hotspot', original, newName);
  Object.entries(modifications).forEach(([key, value]) => {
    krpano.utility.set(`hotspot[${newName}].${key}`, value);
  });
};

Sound Operations

1. playSound() - Phát âm thanh

Mục đích: Phát các hiệu ứng âm thanh và nhạc nền

// ✅ Phát âm thanh cơ bản
krpano.sound.playSound('click_sound', 'audio/click.mp3');

// ✅ Phát nhạc nền với loop
krpano.sound.playSound('background_music', 'audio/ambient.mp3', {
  volume: 0.3,
  loops: -1 // Loop vô hạn
});

// ✅ Phát sound effect
krpano.sound.playSound('door_open', 'audio/door.wav', {
  volume: 0.8,
  loops: 1
});

// ✅ Phát âm thanh theo scene
const playSceneAmbient = (sceneName: string) => {
  const soundMap = {
    kitchen: 'audio/kitchen_ambient.mp3',
    garden: 'audio/birds.mp3',
    bedroom: 'audio/night_ambient.mp3'
  };

  if (soundMap[sceneName]) {
    krpano.sound.playSound('scene_ambient', soundMap[sceneName], {
      volume: 0.4,
      loops: -1
    });
  }
};

// ✅ Random sound effect
const playRandomSound = () => {
  const sounds = ['sound1.mp3', 'sound2.mp3', 'sound3.mp3'];
  const randomSound = sounds[Math.floor(Math.random() * sounds.length)];
  krpano.sound.playSound('random_sfx', `audio/${randomSound}`, { volume: 0.6 });
};

2. stopSound() - Dừng âm thanh

Mục đích: Dừng âm thanh đang phát

// ✅ Dừng âm thanh cụ thể
krpano.sound.stopSound('background_music');

// ✅ Dừng âm thanh khi chuyển scene
const stopSceneSounds = () => {
  krpano.sound.stopSound('scene_ambient');
  krpano.sound.stopSound('scene_effects');
};

// ✅ Fade out trước khi stop
const fadeOutAndStop = (soundName: string) => {
  // Fade volume to 0 over 2 seconds, then stop
  krpano.utility.call(`tween(sound[${soundName}].volume, 0, 2.0, default, stopsound(${soundName}))`);
};

3. pauseSound() - Tạm dừng âm thanh

Mục đích: Tạm dừng âm thanh (có thể resume sau)

// ✅ Pause/Resume music player
let musicPaused = false;
const toggleMusic = () => {
  if (musicPaused) {
    krpano.sound.playSound('background_music'); // Resume
  } else {
    krpano.sound.pauseSound('background_music');
  }
  musicPaused = !musicPaused;
};

// ✅ Pause khi user inactive
const handleUserInactivity = (inactive: boolean) => {
  if (inactive) {
    krpano.sound.pauseSound('scene_ambient');
  } else {
    krpano.sound.playSound('scene_ambient');
  }
};

4. setSoundVolume() - Điều chỉnh âm lượng

Mục đích: Thay đổi âm lượng của âm thanh đang phát

// ✅ Điều chỉnh âm lượng cơ bản
krpano.sound.setSoundVolume('background_music', 0.5);

// ✅ Fade volume effect
const fadeVolume = (soundName: string, from: number, to: number, duration: number) => {
  krpano.utility.call(`tween(sound[${soundName}].volume, ${to}, ${duration})`);
};

// ✅ Volume slider
const handleVolumeSlider = (soundName: string, sliderValue: number) => {
  const volume = sliderValue / 100; // Convert 0-100 to 0-1
  krpano.sound.setSoundVolume(soundName, volume);
};

// ✅ Distance-based volume (3D audio effect)
const updateSoundByDistance = (soundName: string, distance: number) => {
  const maxDistance = 100;
  const volume = Math.max(0, 1 - (distance / maxDistance));
  krpano.sound.setSoundVolume(soundName, volume);
};

5. stopAllSounds() - Dừng tất cả âm thanh

Mục đích: Dừng toàn bộ âm thanh trong scene

// ✅ Emergency stop all sounds
krpano.sound.stopAllSounds();

// ✅ Mute toggle
let soundsMuted = false;
const toggleMute = () => {
  if (soundsMuted) {
    // Unmute - restart sounds
    krpano.sound.playSound('background_music', null, { volume: 0.3, loops: -1 });
  } else {
    krpano.sound.stopAllSounds();
  }
  soundsMuted = !soundsMuted;
};

// ✅ Scene cleanup
const cleanupSceneSounds = () => {
  krpano.sound.stopAllSounds();
  console.log('All scene sounds stopped');
};

Control Operations

1. enterFullscreen() / exitFullscreen() - Quản lý fullscreen

Mục đích: Điều khiển chế độ toàn màn hình

// ✅ Enter fullscreen
krpano.control.enterFullscreen();

// ✅ Exit fullscreen
krpano.control.exitFullscreen();

// ✅ Toggle fullscreen
krpano.control.toggleFullscreen();

// ✅ Fullscreen with callback
const enterFullscreenMode = () => {
  krpano.control.enterFullscreen();
  console.log('Entered fullscreen mode');
};

// ✅ Conditional fullscreen
const conditionalFullscreen = (condition: boolean) => {
  if (condition) {
    krpano.control.enterFullscreen();
  } else {
    krpano.control.exitFullscreen();
  }
};

2. enableControl() / disableControl() - Điều khiển user control

Mục đích: Bật/tắt khả năng điều khiển của user

// ✅ Enable user control
krpano.control.enableControl();

// ✅ Disable user control (for auto tour)
krpano.control.disableControl();

// ✅ Temporary disable during loading
const temporaryDisableControl = (duration: number) => {
  krpano.control.disableControl();
  setTimeout(() => {
    krpano.control.enableControl();
  }, duration);
};

// ✅ Conditional control based on user role
const setControlBasedOnRole = (userRole: 'admin' | 'viewer' | 'guest') => {
  if (userRole === 'admin') {
    krpano.control.enableControl();
  } else if (userRole === 'viewer') {
    krpano.control.enableControl();
  } else {
    krpano.control.disableControl(); // Guests can only watch
  }
};

3. setCursor() - Thay đổi cursor

Mục đích: Thay đổi hình dạng con trỏ chuột

// ✅ Set different cursor types
krpano.control.setCursor('normal');
krpano.control.setCursor('drag');
krpano.control.setCursor('dragging');
krpano.control.setCursor('moving');

// ✅ Interactive cursor feedback
const setCursorOnHover = (isHovering: boolean) => {
  if (isHovering) {
    krpano.control.setCursor('drag');
  } else {
    krpano.control.setCursor('normal');
  }
};

// ✅ Context-based cursor
const setContextCursor = (mode: 'view' | 'edit' | 'measure') => {
  switch(mode) {
    case 'view':
      krpano.control.setCursor('normal');
      break;
    case 'edit':
      krpano.control.setCursor('drag');
      break;
    case 'measure':
      // Custom cursor for measuring tool
      krpano.control.setCursor('normal');
      break;
  }
};

4. showWaitcursor() / hideWaitcursor() - Loading cursor

Mục đích: Hiển thị cursor loading khi xử lý

// ✅ Show loading cursor
krpano.control.showWaitcursor();

// ✅ Hide loading cursor
krpano.control.hideWaitcursor();

// ✅ Show during async operations
const performAsyncOperation = async () => {
  krpano.control.showWaitcursor();

  try {
    // Simulate async operation
    await new Promise(resolve => setTimeout(resolve, 2000));
    console.log('Operation completed');
  } finally {
    krpano.control.hideWaitcursor();
  }
};

// ✅ Auto-hide after timeout
const showWaitWithTimeout = (timeout: number = 5000) => {
  krpano.control.showWaitcursor();
  setTimeout(() => {
    krpano.control.hideWaitcursor();
  }, timeout);
};

Utility Operations

1. loadXML() - Load file XML

Mục đích: Tải cấu hình XML mới

// ✅ Load new XML configuration
krpano.utility.loadXML('/config/new_tour.xml');

// ✅ Load XML with keep display
krpano.utility.loadXML('/config/addon.xml', { keepdisplay: true });

// ✅ Load XML based on user selection
const loadTourConfiguration = (tourType: 'basic' | 'premium' | 'vip') => {
  const xmlPaths = {
    basic: '/config/basic_tour.xml',
    premium: '/config/premium_tour.xml',
    vip: '/config/vip_tour.xml'
  };

  krpano.utility.loadXML(xmlPaths[tourType]);
};

// ✅ Dynamic XML loading
const loadDynamicConfig = (userId: string) => {
  krpano.utility.loadXML(`/config/user_${userId}.xml`);
};

2. reload() - Reload tour

Mục đích: Tải lại toàn bộ tour

// ✅ Simple reload
krpano.utility.reload();

// ✅ Reload with confirmation
const reloadWithConfirmation = () => {
  if (confirm('Bạn có muốn tải lại tour?')) {
    krpano.utility.reload();
  }
};

// ✅ Auto-reload on error
const autoReloadOnError = () => {
  // Simulate error detection
  setTimeout(() => {
    console.log('Error detected, reloading...');
    krpano.utility.reload();
  }, 5000);
};

// ✅ Reload with save state
const reloadWithState = () => {
  // Save current state
  const currentState = {
    scene: krpano.utility.get('xml.scene'),
    hlookat: krpano.utility.get('view.hlookat'),
    vlookat: krpano.utility.get('view.vlookat'),
    fov: krpano.utility.get('view.fov')
  };

  localStorage.setItem('tourState', JSON.stringify(currentState));
  krpano.utility.reload();
};

3. screenshot() - Chụp màn hình

Mục đích: Tạo ảnh chụp màn hình tour

// ✅ Basic screenshot
krpano.utility.screenshot();

// ✅ High resolution screenshot
krpano.utility.screenshot({ scale: 2.0, alpha: false });

// ✅ Screenshot with transparency
krpano.utility.screenshot({ scale: 1.0, alpha: true });

// ✅ Screenshot for thumbnail generation
const generateThumbnail = () => {
  krpano.utility.screenshot({ scale: 0.5, alpha: false });
  console.log('Thumbnail generated');
};

// ✅ Batch screenshot for all scenes
const screenshotAllScenes = (sceneNames: string[]) => {
  sceneNames.forEach((sceneName, index) => {
    setTimeout(() => {
      krpano.scene.loadScene(sceneName);
      setTimeout(() => {
        krpano.utility.screenshot({ scale: 1.0 });
        console.log(`Screenshot taken for ${sceneName}`);
      }, 1000);
    }, index * 2000);
  });
};

4. trace() - Debug logging

Mục đích: Ghi log debug thông tin

// ✅ Simple trace
krpano.utility.trace('Debug message');

// ✅ Trace with variables
const debugCurrentState = () => {
  const currentScene = krpano.utility.get('xml.scene');
  const currentFov = krpano.utility.get('view.fov');
  krpano.utility.trace(`Current scene: ${currentScene}, FOV: ${currentFov}`);
};

// ✅ Conditional tracing
const conditionalTrace = (condition: boolean, message: string) => {
  if (condition) {
    krpano.utility.trace(`DEBUG: ${message}`);
  }
};

// ✅ Performance tracing
const tracePerformance = (operationName: string, startTime: number) => {
  const endTime = performance.now();
  const duration = endTime - startTime;
  krpano.utility.trace(`${operationName} took ${duration.toFixed(2)}ms`);
};

5. error() - Error logging

Mục đích: Ghi log lỗi

// ✅ Simple error logging
krpano.utility.error('Something went wrong!');

// ✅ Error with context
const logErrorWithContext = (error: Error, context: string) => {
  krpano.utility.error(`${context}: ${error.message}`);
};

// ✅ Try-catch with error logging
const safeOperation = () => {
  try {
    // Risky operation
    throw new Error('Test error');
  } catch (error) {
    krpano.utility.error(`Operation failed: ${error.message}`);
  }
};

6. get() / set() - Đọc/ghi biến

Mục đích: Truy cập và thay đổi thuộc tính Krpano

// ✅ Get values
const currentScene = krpano.utility.get('xml.scene');
const viewFov = krpano.utility.get('view.fov');
const hotspotVisible = krpano.utility.get('hotspot[info].visible');

// ✅ Set values
krpano.utility.set('view.fov', 90);
krpano.utility.set('hotspot[marker].alpha', 0.8);
krpano.utility.set('layer[menu].visible', true);

// ✅ Dynamic property access
const getHotspotProperty = (hotspotName: string, property: string) => {
  return krpano.utility.get(`hotspot[${hotspotName}].${property}`);
};

const setHotspotProperty = (hotspotName: string, property: string, value: any) => {
  krpano.utility.set(`hotspot[${hotspotName}].${property}`, value);
};

// ✅ Batch operations
const setMultipleProperties = (properties: Record<string, any>) => {
  Object.entries(properties).forEach(([path, value]) => {
    krpano.utility.set(path, value);
  });
};

// Example usage:
setMultipleProperties({
  'view.fov': 80,
  'hotspot[info].alpha': 0.9,
  'layer[menu].x': 100,
  'layer[menu].y': 50
});

7. call() - Thực thi lệnh

Mục đích: Thực thi lệnh Krpano trực tiếp

// ✅ Simple call
krpano.utility.call('trace(Hello World)');

// ✅ Complex operations
krpano.utility.call('tween(view.fov, 60, 2.0, easeInOutSine)');

// ✅ Multiple commands
const executeMultipleCommands = () => {
  krpano.utility.call(`
    set(hotspot[marker].visible, true);
    tween(hotspot[marker].alpha, 1.0, 1.0);
    playsound(notification);
  `);
};

// ✅ Conditional execution
const conditionalCall = (condition: boolean) => {
  if (condition) {
    krpano.utility.call('loadscene(next_room)');
  } else {
    krpano.utility.call('trace(Condition not met)');
  }
};

8. callwith() - Thực thi với tham số

Mục đích: Thực thi lệnh với nhiều tham số

// ✅ Call with parameters
krpano.utility.callwith('loadscene', 'bedroom', 'null', 'BLEND(1.0)');

// ✅ Dynamic parameters
const callWithDynamicParams = (action: string, ...params: any[]) => {
  krpano.utility.callwith(action, ...params);
};

// Example:
callWithDynamicParams('tween', 'view.fov', 90, 2.0, 'easeOutSine');

9. wait() - Delay execution

Mục đích: Trì hoãn thực thi lệnh

// ✅ Simple wait
krpano.utility.wait(2.0); // Wait 2 seconds

// ✅ Wait with callback
krpano.utility.wait(1.5, 'trace(Timer finished)');

// ✅ Sequential operations with delays
const sequentialOperations = () => {
  krpano.utility.call('trace(Step 1)');
  krpano.utility.wait(1.0, 'trace(Step 2)');
  krpano.utility.wait(2.0, 'loadscene(next_room)');
  krpano.utility.wait(3.0, 'trace(Sequence completed)');
};

// ✅ Timed auto-tour
const startTimedAutoTour = (scenes: string[], interval: number) => {
  scenes.forEach((scene, index) => {
    krpano.utility.wait(interval * index, `loadscene(${scene})`);
  });
};

Base Execute Function

Sử dụng hàm execute cơ bản

Mục đích: Thực thi lệnh với type safety

const krpano = useKrpano();

// ✅ Set hotspot properties
krpano.execute({
  type: 'hotspot',
  name: 'info_button',
  options: {
    visible: true,
    alpha: 0.9,
    scale: 1.2,
    handcursor: true
  }
});

// ✅ Set layer properties
krpano.execute({
  type: 'layer',
  name: 'overlay',
  options: {
    x: 100,
    y: 200,
    width: 300,
    height: 150,
    alpha: 0.8,
    visible: true
  }
});

// ✅ Set view properties
krpano.execute({
  type: 'view',
  options: {
    hlookat: 90,
    vlookat: 10,
    fov: 80,
    fovmin: 30,
    fovmax: 150
  }
});

// ✅ Raw command execution
krpano.execute({
  raw: 'tween(view.fov, 60, 2.0, easeInOutSine, trace(Zoom completed))'
});

// ✅ Plugin configuration
krpano.execute({
  type: 'plugin',
  name: 'webvr',
  options: {
    enabled: true,
    keeptexture: true,
    showstereosupport: false
  }
});

// ✅ Sound configuration
krpano.execute({
  type: 'sound',
  name: 'ambient',
  options: {
    url: 'audio/forest.mp3',
    volume: 0.6,
    loops: -1
  }
});

// ✅ Events setup
krpano.execute({
  type: 'events',
  options: {
    onloadcomplete: 'trace(Tour loaded successfully)',
    onresize: 'trace(Window resized)',
    onclick: 'trace(User clicked)'
  }
});

// ✅ Display settings
krpano.execute({
  type: 'display',
  options: {
    width: '100%',
    height: '100%',
    align: 'center',
    background: '#000000'
  }
});

Shortcuts

Sử dụng các shortcuts tiện lợi

const krpano = useKrpano();

// ✅ Quick show/hide (default to hotspot)
krpano.show('info_marker');
krpano.hide('temp_marker');
krpano.toggle('menu_button');

// ✅ Specify element type
krpano.show('sidebar', 'layer');
krpano.hide('overlay', 'layer');
krpano.toggle('audio_player', 'plugin');

// ✅ Quick scene loading
krpano.loadScene('kitchen');

// ✅ Quick camera control
krpano.lookAt(180, 0, 90);
krpano.zoomTo(60);

// ✅ Combined shortcuts
const quickTour = () => {
  krpano.show('loading', 'layer');
  krpano.loadScene('bedroom');
  krpano.lookAt(90, 10, 80);
  krpano.hide('loading', 'layer');
};

Kết hợp nhiều thao tác

1. Tour tự động hoàn chỉnh

const createAutoTour = () => {
  const scenes = [
    { name: 'entrance', lookAt: [0, 0, 90], duration: 3000 },
    { name: 'living_room', lookAt: [90, -5, 85], duration: 4000 },
    { name: 'kitchen', lookAt: [180, 0, 95], duration: 3500 },
    { name: 'bedroom', lookAt: [270, 10, 75], duration: 4000 }
  ];

  let currentIndex = 0;

  const nextScene = () => {
    if (currentIndex < scenes.length) {
      const scene = scenes[currentIndex];

      // Show loading
      krpano.element.show('layer', 'loading', { time: 0.3 });

      // Load scene
      krpano.scene.loadScene(scene.name, { blend: 'BLEND(1.5)' });

      // Set camera position
      krpano.view.lookAt(scene.lookAt[0], scene.lookAt[1], scene.lookAt[2], {
        smooth: true,
        time: 2.0,
        tween: 'easeInOutSine'
      });

      // Hide loading
      setTimeout(() => {
        krpano.element.hide('layer', 'loading', { time: 0.3 });
      }, 1500);

      // Play scene sound
      krpano.sound.playSound('scene_ambient', `audio/${scene.name}.mp3`, {
        volume: 0.4,
        loops: 1
      });

      currentIndex++;

      // Schedule next scene
      if (currentIndex < scenes.length) {
        setTimeout(nextScene, scene.duration);
      } else {
        // Tour completed
        krpano.element.show('layer', 'tour_complete', { time: 1.0 });
        krpano.sound.playSound('completion', 'audio/complete.mp3');
      }
    }
  };

  nextScene();
};

2. Interactive hotspot system

const createInteractiveHotspots = () => {
  const hotspots = [
    { 
      name: 'info_1', 
      position: [45, 10], 
      info: 'This is the living room area',
      image: 'images/info.png'
    },
    { 
      name: 'info_2', 
      position: [135, -5], 
      info: 'Kitchen with modern appliances',
      image: 'images/kitchen.png'
    },
    { 
      name: 'info_3', 
      position: [225, 15], 
      info: 'Comfortable bedroom space',
      image: 'images/bedroom.png'
    }
  ];

  hotspots.forEach((hotspot, index) => {
    // Create hotspot
    krpano.element.addElement('hotspot', hotspot.name, {
      url: 'images/hotspot_marker.png',
      ath: hotspot.position[0],
      atv: hotspot.position[1],
      scale: 0.8,
      alpha: 0.7,
      onclick: `showInfo(${hotspot.name})`
    });

    // Create info layer
    krpano.element.addElement('layer', `${hotspot.name}_info`, {
      url: hotspot.image,
      x: 100,
      y: 100,
      width: 300,
      height: 200,
      alpha: 0,
      visible: false,
      zorder: 1000
    });

    // Pulse animation
    setTimeout(() => {
      krpano.element.animate('hotspot', hotspot.name, {
        scale: 1.0,
        alpha: 1.0
      }, { 
        time: 0.5, 
        tween: 'easeOutBounce' 
      });
    }, index * 500);
  });

  // Global function for showing info
  (window as any).showInfo = (hotspotName: string) => {
    // Hide all info panels
    hotspots.forEach(h => {
      krpano.element.hide('layer', `${h.name}_info`, { time: 0.3 });
    });

    // Show selected info
    krpano.element.show('layer', `${hotspotName}_info`, { time: 0.5 });

    // Auto hide after 5 seconds
    setTimeout(() => {
      krpano.element.hide('layer', `${hotspotName}_info`, { time: 0.5 });
    }, 5000);
  };
};

3. Adaptive quality system

const createAdaptiveQuality = () => {
  const checkPerformance = () => {
    // Simulate performance check
    const fps = 60; // Mock FPS
    const devicePixelRatio = window.devicePixelRatio || 1;
    const isMobile = /Mobi|Android/i.test(navigator.userAgent);

    let quality: 'low' | 'medium' | 'high' = 'medium';

    if (isMobile || fps < 30) {
      quality = 'low';
    } else if (fps > 50 && devicePixelRatio > 1) {
      quality = 'high';
    }

    return quality;
  };

  const applyQualitySettings = (quality: 'low' | 'medium' | 'high') => {
    const settings = {
      low: {
        details: 8,
        tessellation: 0.5,
        renderinterface: false
      },
      medium: {
        details: 12,
        tessellation: 1.0,
        renderinterface: true
      },
      high: {
        details: 16,
        tessellation: 1.5,
        renderinterface: true
      }
    };

    const config = settings[quality];

    krpano.execute({
      type: 'display',
      options: {
        details: config.details,
        tessellation: config.tessellation,
        renderinterface: config.renderinterface
      }
    });

    krpano.utility.trace(`Applied ${quality} quality settings`);
  };

  const currentQuality = checkPerformance();
  applyQualitySettings(currentQuality);
};

4. User preference system

const createUserPreferenceSystem = () => {
  const defaultPreferences = {
    autoRotate: false,
    soundEnabled: true,
    soundVolume: 0.7,
    showHelp: true,
    quality: 'medium' as 'low' | 'medium' | 'high',
    controlSensitivity: 1.0
  };

  const loadPreferences = () => {
    const saved = localStorage.getItem('krpano_preferences');
    return saved ? { ...defaultPreferences, ...JSON.parse(saved) } : defaultPreferences;
  };

  const savePreferences = (preferences: typeof defaultPreferences) => {
    localStorage.setItem('krpano_preferences', JSON.stringify(preferences));
  };

  const applyPreferences = (preferences: typeof defaultPreferences) => {
    // Apply sound settings
    if (preferences.soundEnabled) {
      krpano.sound.playSound('ambient', 'audio/ambient.mp3', {
        volume: preferences.soundVolume,
        loops: -1
      });
    } else {
      krpano.sound.stopAllSounds();
    }

    // Apply control sensitivity
    krpano.execute({
      type: 'control',
      options: {
        mousetype: preferences.controlSensitivity > 1 ? 'drag' : 'moveto',
        dragspeed: preferences.controlSensitivity
      }
    });

    // Apply auto-rotate
    if (preferences.autoRotate) {
      startAutoRotate();
    }

    // Show/hide help
    krpano.execute({
      type: 'layer',
      name: 'help',
      options: {
        visible: preferences.showHelp
      }
    });
  };

  const startAutoRotate = () => {
    const rotate = () => {
      const currentH = krpano.utility.get('view.hlookat');
      krpano.view.lookAt((currentH + 1) % 360, 0, undefined, {
        smooth: true,
        time: 0.1
      });
      setTimeout(rotate, 100);
    };
    rotate();
  };

  const preferences = loadPreferences();
  applyPreferences(preferences);

  return {
    updatePreference: (key: keyof typeof defaultPreferences, value: any) => {
      const updated = { ...preferences, [key]: value };
      savePreferences(updated);
      applyPreferences(updated);
    },
    getPreferences: () => preferences
  };
};

5. Analytics tracking system

const createAnalyticsSystem = () => {
  const trackEvent = (eventName: string, data?: any) => {
    // Send to analytics service
    console.log('Analytics:', eventName, data);

    // Could integrate with Google Analytics, etc.
    if ((window as any).gtag) {
      (window as any).gtag('event', eventName, data);
    }
  };

  const trackSceneVisit = (sceneName: string) => {
    trackEvent('scene_visit', {
      scene_name: sceneName,
      timestamp: new Date().toISOString(),
      duration: 0 // Will be updated when leaving scene
    });
  };

  const trackHotspotClick = (hotspotName: string) => {
    trackEvent('hotspot_click', {
      hotspot_name: hotspotName,
      scene: krpano.utility.get('xml.scene'),
      timestamp: new Date().toISOString()
    });
  };

  const trackViewChange = () => {
    const viewData = {
      hlookat: krpano.utility.get('view.hlookat'),
      vlookat: krpano.utility.get('view.vlookat'),
      fov: krpano.utility.get('view.fov')
    };

    trackEvent('view_change', viewData);
  };

  // Setup automatic tracking
  const setupAutoTracking = () => {
    // Track scene changes
    krpano.execute({
      type: 'events',
      options: {
        onnewscene: 'trackSceneVisit(get(xml.scene))',
        onviewchange: 'trackViewChange()'
      }
    });
  };

  setupAutoTracking();

  return {
    trackEvent,
    trackSceneVisit,
    trackHotspotClick,
    trackViewChange
  };
};

🎯 Tóm tắt các trường hợp sử dụng chính:

  1. Scene Management: Chuyển cảnh, quản lý tour đa phòng
  2. Camera Control: Điều khiển góc nhìn, tạo auto-tour
  3. Interactive Elements: Hotspot tương tác, menu, popup
  4. Audio Experience: Nhạc nền, sound effects theo context
  5. User Experience: Fullscreen, loading states, preferences
  6. Performance: Adaptive quality, optimization
  7. Analytics: Tracking user behavior
  8. Accessibility: Control options, user preferences

2 Hook Sự kiện từ Krpano gửi lên React

useKrpanoEventListener

Hook này giúp lắng nghe và quản lý các sự kiện từ Krpano, bao gồm:

  1. Sự kiện hệ thống (onloadcomplete, onxmlcomplete, onready, onerror, onresize, onfullscreenchange)
  2. Sự kiện scene (onnewscene, onremovescene)
  3. Sự kiện view (onviewchange, onviewchanged, onidle)
  4. Sự kiện mouse/keyboard (onclick, ondblclick, onmousedown, onmouseup, onmousemove, onkeydown, onkeyup)
  5. Sự kiện hotspot (onhotspotclick, onhotspotover, onhotspotout)
  6. Sự kiện layer (onlayerclick, onlayerover, onlayerout)

Hook cung cấp các API để thêm, xóa, trigger và quản lý sự kiện một cách linh hoạt.


📌 Cách sử dụng cơ bản

import React, { useEffect } from "react";
import { useKrpanoEventListener } from "react-krpano-toolkit";

function MyComponent() {
  const {
    addEventListener,
    removeEventListener,
    setupHotspotEvents,
    setupLayerEvents,
    triggerCustomEvent
  } = useKrpanoEventListener();

  useEffect(() => {
    // Lắng nghe sự kiện toàn cục từ Krpano
    const cleanup = addEventListener("onready", (data) => {
      console.log("Krpano ready!", data);
    });

    // Trả về cleanup function khi unmount
    return () => cleanup();
  }, [addEventListener]);

  useEffect(() => {
    // Setup hotspot events
    const cleanupHotspot = setupHotspotEvents("hotspot1", {
      onclick: (data) => console.log("Hotspot clicked:", data),
      onover: (data) => console.log("Hotspot hover:", data),
      onout: (data) => console.log("Hotspot out:", data),
    });

    // Setup layer events
    const cleanupLayer = setupLayerEvents("layer1", {
      onclick: (data) => console.log("Layer clicked:", data),
    });

    return () => {
      cleanupHotspot();
      cleanupLayer();
    };
  }, [setupHotspotEvents, setupLayerEvents]);

  const triggerEvent = () => {
    triggerCustomEvent("oncustom", { msg: "Hello from React!" });
  };

  return <button onClick={triggerEvent}>Trigger Custom Event</button>;
}

⚡ Các hàm chính

Hàm Mô tả Tham số Trả về
addEventListener Thêm listener cho một sự kiện Krpano eventType: KrpanoEventType, handler: KrpanoEventHandler Hàm cleanup để xóa listener
removeEventListener Xóa listener đã đăng ký eventType, handler -
removeAllEventListeners Xóa tất cả listener hoặc theo eventType eventType? -
registerEventHandlers Đăng ký nhiều handler cùng lúc handlers: KrpanoEventHandlers Hàm cleanup
triggerCustomEvent Gửi sự kiện tùy chỉnh tới Krpano eventType: string, data: any -
setupHotspotEvents Thiết lập listener cho hotspot hotspotName: string, { onclick?, onover?, onout?, ondown?, onup? } Hàm cleanup
setupLayerEvents Thiết lập listener cho layer layerName: string, { onclick?, onover?, onout? } Hàm cleanup
isListening Kiểm tra đang lắng nghe sự kiện eventType boolean
getListenerCount Lấy số lượng listener đang đăng ký eventType number
getAllListeners Lấy danh sách tất cả các eventType đang lắng nghe - string[]

✅ Lưu ý

  1. Luôn gọi cleanup function khi component unmount để tránh memory leak.
  2. Hotspot/Layer events chỉ kích hoạt khi tên hotspot/layer đúng với tên bạn setup.
  3. triggerCustomEvent có thể dùng để gửi event từ React xuống Krpano, ví dụ kết hợp với hotspot/layer custom.
  4. Hook yêu cầu KrpanoProvider phải bọc component, nếu không sẽ throw lỗi.

Liên hệ

Vũ Văn Định - @your_github - vuvandinh.work@gmail.com

Project Link: https://github.com/vuvandinh203/react-krpano-toolkit

(back to top)