Преглед на файлове

Add hot spot dragging and a few more minor changes (#881).

* Hotspot dragging (hot spot attribute draggable + dragHandler function)
* Allow Image and ImageData and ImageBitmap as parameter panorama for equirectangular scenes
pull/918/head
NiHoel преди 4 години
committed by GitHub
родител
ревизия
6758d060f7
No known key found for this signature in database GPG ключ ID: 4AEE18F83AFDEB23
променени са 4 файла, в които са добавени 115 реда и са изтрити 9 реда
  1. +16
    -3
      doc/json-config-parameters.md
  2. +72
    -5
      src/js/pannellum.js
  3. +16
    -0
      tests/run_tests.py
  4. +11
    -1
      tests/tests.html

+ 16
- 3
doc/json-config-parameters.md Целия файл

@@ -323,6 +323,18 @@ If `clickHandlerFunc` is specified, this function is added as an event handler
for the hot spot's `click` event. The event object and the contents of
`clickHandlerArgs` are passed to the function as arguments.

#### `draggable`

If specified, the hotspot can moved using the mouse or by touch.

#### `dragHandlerFunc` (function) and `dragHandlerArgs` (object)

If `dragHandlerFunc` is specified, this function is added as an event handler
when dragging of the hotspot starts and ends. The event object and the contents of
`dragHandlerArgs` are passed to the function as arguments. Possible types of the
event object are: `mousedown`, `pointerdown`, `touchend`, `pointerup`, `pointerleave`,
`mouseup`, and `mouseleave`.

#### `scale` (boolean)

When `true`, the hot spot is scaled to match changes in the field of view,
@@ -367,11 +379,12 @@ if this option is enabled.

## `equirectangular` specific options

### `panorama` (string)
### `panorama` (string or HTMLImageElement or ImageData or ImageBitmap)

Sets the URL to the equirectangular panorama image. This is relative to
`basePath` if it is set, else it is relative to the location of
If a string is passed, it sets the URL to the equirectangular panorama image.
This is relative to `basePath` if it is set, else it is relative to the location of
`pannellum.htm`. An absolute URL can also be used.
Alternatively, an already loaded image can be passed.

### `haov` (number)



+ 72
- 5
src/js/pannellum.js Целия файл

@@ -40,6 +40,7 @@ var _this = this;
var config,
renderer,
preview,
draggingHotSpot,
isUserInteracting = false,
latestInteraction = Date.now(),
onPointerDownPointerX = 0,
@@ -378,8 +379,15 @@ function init() {
if (config.dynamic !== true) {
// Still image
if (config.panorama instanceof Image || config.panorama instanceof ImageData ||
config.panorama instanceof ImageBitmap) {
panoImage = config.panorama;
onImageLoad();
return;
}

p = absoluteURL(config.panorama) ? config.panorama : p + config.panorama;
panoImage.onload = function() {
window.URL.revokeObjectURL(this.src); // Clean up
onImageLoad();
@@ -712,7 +720,7 @@ function onDocumentMouseDown(event) {
container.focus();
// Only do something if the panorama is loaded
if (!loaded || !config.draggable) {
if (!loaded || !config.draggable || config.draggingHotSpot) {
return;
}
@@ -797,7 +805,9 @@ function mouseEventToCoords(event) {
* @param {MouseEvent} event - Document mouse move event.
*/
function onDocumentMouseMove(event) {
if (isUserInteracting && loaded) {
if (draggingHotSpot) {
moveHotSpot(draggingHotSpot, event);
} else if (isUserInteracting && loaded) {
latestInteraction = Date.now();
var canvas = renderer.getCanvas();
var canvasWidth = canvas.clientWidth,
@@ -821,6 +831,10 @@ function onDocumentMouseMove(event) {
* @private
*/
function onDocumentMouseUp(event) {
if (draggingHotSpot && draggingHotSpot.dragHandlerFunc)
draggingHotSpot.dragHandlerFunc(event, draggingHotSpot.dragHandlerArgs);
draggingHotSpot = null;

if (!isUserInteracting) {
return;
}
@@ -845,7 +859,7 @@ function onDocumentMouseUp(event) {
*/
function onDocumentTouchStart(event) {
// Only do something if the panorama is loaded
if (!loaded || !config.draggable) {
if (!loaded || !config.draggable || draggingHotSpot) {
return;
}

@@ -936,6 +950,8 @@ function onDocumentTouchMove(event) {
* @private
*/
function onDocumentTouchEnd() {
draggingHotSpot = null;

isUserInteracting = false;
if (Date.now() - latestInteraction > 150) {
speed.pitch = speed.yaw = 0;
@@ -973,6 +989,11 @@ function onDocumentPointerDown(event) {
*/
function onDocumentPointerMove(event) {
if (event.pointerType == 'touch') {
if (draggingHotSpot) {
moveHotSpot(draggingHotSpot, event);
return;
}

if (!config.draggable)
return;
for (var i = 0; i < pointerIDs.length; i++) {
@@ -994,6 +1015,10 @@ function onDocumentPointerMove(event) {
* @param {PointerEvent} event - Document pointer up event.
*/
function onDocumentPointerUp(event) {
if (draggingHotSpot && draggingHotSpot.dragHandlerFunc)
draggingHotSpot.dragHandlerFunc(event, draggingHotSpot.dragHandlerArgs);
draggingHotSpot = null;

if (event.pointerType == 'touch') {
var defined = false;
for (var i = 0; i < pointerIDs.length; i++) {
@@ -1412,7 +1437,8 @@ function animate() {
} else if (renderer && (renderer.isLoading() || (config.dynamic === true && update))) {
requestAnimationFrame(animate);
} else {
fireEvent('animatefinished', {pitch: _this.getPitch(), yaw: _this.getYaw(), hfov: _this.getHfov()});
if (_this.getPitch && _this.getYaw && _this.getHfov)
fireEvent('animatefinished', {pitch: _this.getPitch(), yaw: _this.getYaw(), hfov: _this.getHfov()});
animating = false;
prevTime = undefined;
var autoRotateStartTime = config.autoRotateInactivityDelay -
@@ -1813,10 +1839,51 @@ function createHotSpot(hs) {
div.className += ' pnlm-pointer';
span.className += ' pnlm-pointer';
}
if (hs.draggable) {
// Handle mouse by container event listeners
div.addEventListener('mousedown', function (e) {
if (hs.dragHandlerFunc)
hs.dragHandlerFunc(e, hs.dragHandlerArgs);
draggingHotSpot = hs;
});

if (document.documentElement.style.pointerAction === '' &&
document.documentElement.style.touchAction === '') {
div.addEventListener('pointerdown', function (e) {
if (hs.dragHandlerFunc)
hs.dragHandlerFunc(e, hs.dragHandlerArgs);
draggingHotSpot = hs;
});
}

// Handle touch events by hotspot event listener
div.addEventListener('touchmove', function(e) {
moveHotSpot(hs, e.targetTouches[0]);
});
div.addEventListener('touchend', function (e) {
if (hs.dragHandlerFunc)
hs.dragHandlerFunc(e, hs.dragHandlerArgs);
draggingHotSpot = null;
})
}
hs.div = div;
}

/**
* Moves a curently displayed hot spot.
* @private
* @param {Object} hs - Hot spot to move.
* @param {MouseEvent} event - Mouse event to get coordinates from.
*/
function moveHotSpot(hs, event){
var coords = mouseEventToCoords(event);
hs.pitch = coords[0];
hs.yaw = coords[1];
renderHotSpot(hs);
};

/**
* Creates hot spot elements for the current scene.
* @private
*/


+ 16
- 0
tests/run_tests.py Целия файл

@@ -27,6 +27,7 @@ import numpy as np
from PIL import Image, ImageChops
from selenium.common.exceptions import TimeoutException
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains


class PannellumServer(SimpleHTTPRequestHandler):
@@ -170,6 +171,21 @@ class PannellumTester(object):
comparator = self.take_screenshot("panorama")
self.equal_images(reference, comparator, "multires")

# Check hotspot dragging - move from (20, 20) to (0, 0)
action = ActionChains(self.browser)
action.drag_and_drop(
self.browser.find_element_by_class_name("pnlm-hotspot"),
self.browser.find_element_by_class_name(
"pnlm-render-container"
), # drops in the middle of the element
)
action.perform()
time.sleep(1)
assert self.browser.execute_script(
"var hs = viewer.getConfig().hotSpots[0]; return Math.abs(hs.yaw) < 0.001 && Math.abs(hs.pitch) < 0.001"
)
print("PASS: hot spot dragging")

self.httpd.server_close()

def get_browser(self, name=None):


+ 11
- 1
tests/tests.html Целия файл

@@ -78,7 +78,17 @@ viewer = pannellum.viewer('panorama', {
"tileResolution": 256,
"maxLevel": 4,
"cubeResolution": 2048
}
},
"hotSpots": [
{
"pitch": 20,
"yaw": 20,
"type": "info",
"text": "drag test",
"draggable": true,
"dragHandlerFunc": console.log
}
]
}
}
});


Зареждане…
Отказ
Запис