add hotspot where user clicks? (using AS3)

Using Pano2VR/Object2VR SWF files with your own Flash projects
Post Reply
hfeist
Posts: 25
Joined: Tue Oct 16, 2007 11:21 pm
Contact:

I'm trying to find a way to ask users to click on a pano wherever they'd like to leave a comment. I would add a small dot as a marker where the user clicked. i would also save those coordinates and then in another panorama i would retrieve all the comments and coordinates from a database and create dot hotspots in all the original positions in the pano. clicking on each hotspot would popup a text field with the associated comment.
at the moment i am able to create the dot but don't know how to place it at the mouse click coordinates. how do i specify the x/y?
the api reference says to use something like this:

vr.pano.addHotspot("dot"+count,pan,tilt,dot);
no mention of x/y

any ideas?
hf
hfeist
Posts: 25
Joined: Tue Oct 16, 2007 11:21 pm
Contact:

ok, now I understand that the pan/tilt parameters refer to the spherical coordinates of the hotspot. x/y are from another dimension.

now need to find the pan/tilt coordinates where the user clicks.

doable?
hf
Don
Posts: 143
Joined: Thu Mar 07, 2013 2:59 pm
Location: Southern California

Assuming you are outputting to html? If so, the pano displays in <div id="container">. The <div id="container"> is a rectangle. As the user navigates, the pano spins, then center of the camera lens is always in the center of that rectangle. As described in previous posts on this forum, the current pan, tilt, and fov values can be acquired and displayed. Therefore, we can place an html button on our html web page, and when the button is clicked, we can display the current pan, tilt, and fov values. We could also write those values to fields in the database. You agree so far?

Two known factors are:
1. The top-left corner of <div id="container"> is always equal to zero, zero.
2. The camera lens is always centered on <div id="container">

Now, wherever the user clicks in <div id="container"> get the coordinates of the cursor within <div id="container"> something like this:
3. http://stackoverflow.com/questions/3234 ... et-element

Calculate the distance of the cursor-click to the current pan, tilt and fov values. (This calculation seems simple, except for the part about fov changing when zooming in/out.) Record the coordinates in your database. Save the equations behind your calculations in your code. Now, assign <div id="container" z-index=0>. Then, create another <div id="user_hotspot_001" z-index=99>. The <div id="user_hotspot_001"> will include an image of a hotspot. There will be one <div id="user_hotspot_002">, <div id="user_hotspot_003"> and so on for every custom hotspot the user defines. So, as the pano spins, calculate the location of <div id="user_hotspot_001"> above <div id="container"> in relation to the current pan, tilt and fov values. Move the location of <div id="user_hotspot_001"> across <div id="container"> wherever the current pan, tilt and fov values dictate. When the <div id="user_hotspot_001> goes out of bounds, then turn it off. Turn it on again when the current pan, tilt and fov values so require.

Use #3 above as an example and Google more information about: html5, <div> tags, mouse pointer location, <div> tag z-index, and so on.

Wish I were not swamped at the moment, because this is a cool subject that I would definitely like to experiment with!
hfeist
Posts: 25
Joined: Tue Oct 16, 2007 11:21 pm
Contact:

Thanks for the very generous and thoughtful reply.
No, i'm trying to create the hotspots within Flash, not on the external html page.

With this code a hotspot is created inside the vr.pano at the centre of the current screen:

function getMouseUp(e:Event)
{
var p = vr.pano.getPan();
var t = vr.pano.getTilt();
var dot:Dot=new Dot();
counter++;
vr.pano.addHotspot("d"+counter,p,t,dot);
//What I'm looking for is a way to place the hotspot where the user clicks on the panorama, not at vr.pano centre.
// I'm imagining something like
// var p = vr.pano.getMousePanPosition();
// var t = vr.pano.getMouseTiltPosition();
}
hf
Don
Posts: 143
Joined: Thu Mar 07, 2013 2:59 pm
Location: Southern California

The flash pano displays in <div id="flashcontent">. This is how I would approach it, using #3 in my previous post:

A. The top-left corner of <div id="flashcontent"> equals 0,0.
B. The bottom-right corner of <div id="flashcontent"> varies.
C. The height of <div id="flashcontent"> varies too, but is always = H
D. The width of <div id="flashcontent"> varies too, but is always = W
E. The center of <div id="flashcontent"> varies too, but is always = H/2, W/2
E. The center of the camera lens is always in the center of <div id="flashcontent">.
F. Where the user clicks is equal to: mouse-click X, mouse-click Y
G. If mouse-click X is greater or less than H/2, then the user clicked above/below the horizon. Do math to calculate the percent difference in units above or below the horizon...
H. If mouse-click Y is greater or less than W/2, then user clicked Left/Right vertically from the lens target. Do math to calculate the percent difference in units from the "Verizon"...
I. Multiple those percentages found in 'G' and 'H' to the current pan and tilt values to convert the mouse-click coordinates to pano pan & tilt coordinates.
J. Write the new hotspot pan & tilt values to your database.

Something like that?
hfeist
Posts: 25
Joined: Tue Oct 16, 2007 11:21 pm
Contact:

I'm really flailing with this. I'm hoping someone can take a look at this and guide me toward a better approach.

My thinking is to grab the mouseX as a percentage of the stage width then multiply the fov with that to get a position within it left or right of pan. Then I try to add that to the current pan. If I start off by panning to the right and click the mouse the dots appear somewhat where I'd expect them to, though not accurately. When I start panning randomly they get all messed up. It's clear I don't understand the math behind pan and am over my head with this.

private function getMouseUp(e:Event):void
{
debugFld.text=""; // for debugging

var sw:uint=this.stage.stageWidth;
var mx:int=mouseX;
var pan:Number = vr.pano.getPan();
var tilt:Number=vr.pano.getTilt();
var fov:Number = vr.pano.getFov();

// if(pan<=-360){
// pan+=360
// }
// if(pan>=360){
// pan-=360
// }
// if(pan>=0){
// pan=-1*pan;
// }
// prevent pan from growing

var pcx:Number=(mx/sw);
// percentage mouseX of stage width

var fovp:Number=pcx*(fov);
// use that percentage for position in fov

var dotp:Number =-1*(pan-(fov/2)+fovp);
// fov/2=left side of fov
// subtract left side of fov from pan then add percent of fov

if(dotp>0){
dotp*=-1;
}

var dot:Dot=new Dot();
vr.pano.addHotspot("d"+counter,dotp,tilt,dot);

debug("mx="+mx);
debug("mx/sw="+pcx);
debug("fovp=pcx*(fov)="+fovp);
debug("-1*(pan+(fov/2)+fovp)="+dotp.toString());
debug("pan="+pan);
debug("dotp="+dotp);
}

private var debugFld:TextField;
private function createDebugField():void{
debugFld=new TextField();
addChild(debugFld);
debugFld.defaultTextFormat = new TextFormat("Verdana", 12, 0x000000);
debugFld.autoSize = TextFieldAutoSize.LEFT;
debugFld.multiline=true;
debugFld.mouseEnabled=false;
debugFld.background=true;
this.addChild(debugFld);
}

private function debug(w:String=""):void
{
debugFld.text += w+"\n";
setChildIndex(debugFld,this.numChildren-1);
}
hf
User avatar
Hopki
Gnome
Posts: 12999
Joined: Thu Jan 10, 2008 3:16 pm
Location: Layer de la Haye, Essex UK
Contact:

Hi,
As this is Flash and Action Script related I have moved this topic to a better forum where it may get answered.
Regards,
Hopki
Garden Gnome Support
If you send an e-mail to support please send a link to the forum post for reference.
support@ggnome.com
https://ggnome.com/wiki/documentation/
hfeist
Posts: 25
Joined: Tue Oct 16, 2007 11:21 pm
Contact:

getting closer, at least as far as pan goes.
the dots are close to where the mouse clicks when you're near the center and near the edges but wander away in no man's land between

private function getMouseUp(e:Event):void
{
var sc:uint=this.stage.stageWidth/2;
var mx:int=mouseX;
var pan:Number = vr.pano.getPan();
// var tilt:Number=vr.pano.getTilt();
// var fov:Number = vr.pano.getFov();

if(pan<0){
pan+=360
}
if(pan>360){
pan-=360
}

if(mx<sc){
var pcx:Number=1-(mx/sc); // percent of distance left of centre
var difpc:Number=pcx*120; // 120 as approx amount of 360 view visible
var dotp:Number = (pan+difpc/2);
}else{
pcx=1-(sc/mx);// percent of distance right of centre
difpc=pcx*120;
dotp = (pan-difpc/2);
}

if(dotp>360){
dotp-=360
}

var dot:Dot=new Dot();
vr.pano.addHotspot("d"+counter,dotp,tilt,dot);

debugFld.text="";
debug("sc: "+sc.toFixed(2)+" = stageWidth/2");
debug("mx: "+mx.toFixed(2)+" = mouseX");
debug("pcx: "+pcx.toFixed(2)+"% away from pan");
debug("pan: "+pan+" center of view");
debug("dotp ="+ dotp.toFixed(2)+" dot location");
}

private var debugFld:TextField;
private function createDebugField():void{
debugFld=new TextField();
addChild(debugFld);
debugFld.defaultTextFormat = new TextFormat("Verdana", 12, 0x000000);
debugFld.autoSize = TextFieldAutoSize.LEFT;
debugFld.multiline=true;
debugFld.mouseEnabled=false;
debugFld.background=true;
this.addChild(debugFld);
}

private function debug(w:String=""):void
{
debugFld.text += w+"\n";
setChildIndex(debugFld,this.numChildren-1);
}
hf
Don
Posts: 143
Joined: Thu Mar 07, 2013 2:59 pm
Location: Southern California

All day on this, and found a significant lack of accuracy in my percentage theory above. Struggled, then had an epiphany, and created a quick, highly accurate proof-of-concept. This is the solution I will likely use, unless it leads you to suggest an even better idea?

Step #1. Place a cross-hairs image in the skin editor. Imagine the cross-hairs in a gun scope. Position and anchor the cross-hairs dead center. Provide a separate skin button for the user to toggle the cross-hairs on/off.

Step #2. Place a "Create Hotspot" button on the web page, external to the pano. (Maybe this button only displays when the cross-hairs are ON - if that's possible, and need to research.)

Step #3. User navigates around the pano. Pans, tilts and zooms at-will. Whenever the user clicks "Create Hotspot", then whatever is under the cross-hairs is equal to the current PTZ values, and those coordinates (pan and tilt values) are written to the database, along with other web page field values that provide for a hotspot title, target, unique id and url.

Very simple. Very accurate. My only remaining question is whether or not the pano will need to be reloaded to see the newly created hotspots? ...but I'm out of time for today.
hfeist
Posts: 25
Joined: Tue Oct 16, 2007 11:21 pm
Contact:

yes, that'll work very well. the hotspot is at dead centre. no calculating required at all
my task though is to allow visitors to click willy nilly wherever they'd like to leave a comment while exploring a condo. moving the scene around to line up crosshairs seems to have somewhat of a military flavour to it, no?

here's my very crude addition to the tilt part of the effort

var sc:uint=this.stage.stageWidth/2;
var svc:uint=this.stage.stageHeight/2;
var mx:int=mouseX;
var my:int=mouseY;
var pan:Number = vr.pano.getPan();
var tilt:Number=vr.pano.getTilt();
// var fov:Number = vr.pano.getFov();

//pan
if(pan<0){
pan+=360
}
if(pan>360){
pan-=360
}

if(mx<sc){
var pcx:Number=1-(mx/sc);
var difpc:Number=pcx*100;
dotP = (pan+difpc/2);
}else{
pcx=1-(sc/mx);
difpc=pcx*160;
dotP = (pan-difpc/2);
}

if(dotP<0){
dotP+=360
}
if(dotP>360){
dotP-=360
}

//tilt
if(my<svc){
var pcy:Number=1-(my/svc);
var diftc:Number=pcy*60;
dotT = (tilt+diftc/2);
}else{
pcy=((my-svc)/svc);
diftc=pcy*60;
dotT = -1*(1-(tilt-diftc/2));
}

var dot:Dot=new Dot();
vr.pano.addHotspot("dot"+counter,dotP,dotT,dot);
hf
Don
Posts: 143
Joined: Thu Mar 07, 2013 2:59 pm
Location: Southern California

I plugged a couple of my own mouse X and Y coordinates into your most recent action script above, and sadly, the results were off the mark.

Edited 8/10/2013: In case you are not already using it, in the Pano2VR Viewing Parameters, select "Show Limits", and then, Right-click on the image and select "Fixed Window Size". The Pano2VR Hotspot Editor is also helpful by making it easy to define a few test hotspots and quickly check their official Pan & Tilt values against those hotspots calculated using the equations below.

The following equations "seem" accurate in my brief testing. The equations were developed using the default settings on a Pano2VR v4.1 Html5 640x480 output, however, I believe these equations will apply to a default flash output as well. The default FoV Mode is set to "Vertical" in the Pano2VR Output Editor - that Fov Mode setting is available in Flash outputs too. These equations have not been tested on the other Fov Mode settings, i.e. horizontal or diagonal.

PAN: (Revised 8/10/2013: The default Html5 output is offsetLeft is 8 pixels. Hence, the extra little addition/subtraction of the offsetLeft value from the Hotspot Pan.)

Code: Select all

if mouseX < (StageWidth/2) then
    PercentX = ([0.5 - (mouseX/StageWidth)] * Current Fov)
    Hotspot Pan = Current Pan + PercentX + document.getElementById("container").offsetLeft
else if mouseX > (StageWidth/2)
    PercentX = [(mouseX/StageWidth) - 0.5] * Current Fov
    Hotspot Pan = Current Pan - PercentX - document.getElementById("container").offsetLeft
TILT: (Revised 8/9/2013:)

Code: Select all

if mouseY < (StageHeight/2) then
    PercentY = [0.5 - (mouseY/StageHeight)] * Current Fov
    Hotspot Tilt = Current Tilt + PercentY
else if mouseY > (StageHeight/2) then
    PercentY = [(mouseY/StageHeight) - 0.5] * Current Fov
    Hotspot Tilt = Current Tilt - PercentY
-
hfeist
Posts: 25
Joined: Tue Oct 16, 2007 11:21 pm
Contact:

well the client was happy despite the inexact positioning but now they want it without flash. so i've tried to use your code in js. the values seem to be working but i'm stuck at the insertion of the dot within the panorama

Code: Select all

			$(document).ready(function(e) {
				//alert('started');
				$('#container').click(function(e) {
					if(shiftDown==true){
						var pan=pano.getPan();
						var tilt=pano.getTilt();
						var fov=pano.getFov();
						
						var stageWidth = 1024;	
						var stageHeight = 768;
						
						var dot = new Image();
						dot.src = "images/up.png";
						
						var mouseX=e.pageX;
						var mouseY=e.pageY;
						
						// pan
						if (mouseX < stageWidth/2) {
							var percentX = ([0.5 - (mouseX/stageWidth)] * fov);
							var hspan = pan + percentX;
						} else if (mouseX > stageWidth/2){
							percentX = [(mouseX/stageWidth) - 0.5] * fov;
						 	hspan = pan - percentX;
						}
						//tilt
						if (mouseY < stageHeight/2) {
							var percentY = [0.5 - (mouseY/stageHeight)] *fov;
							var hstilt = tilt + percentY;
						}else if (mouseY > stageHeight/2) {
							percentY = [(mouseY/stageHeight) - 0.5] * fov;
							hstilt =tilt - percentY;
						}
						
						//alert('hspan/hstilt='+hspan+' /'+hstilt);
						pano.addHotspot('hs',hspan,hstilt,dot)  //  <<< i get an error here 
                                                                                                         //TypeError: 'undefined' is not a function (evaluating 'pano.addHotspot('hs',hspan,hstilt,dot)')
                                                                                                         //sounds like there's no addHotspot function in js
					}
				});  	
			});  
		
			var shiftDown = false;
			var setShiftDown = function(event){
				if(event.keyCode === 16 || event.charCode === 16){
					shiftDown = true;
				}
			};
			
			var setShiftUp = function(event){
				if(event.keyCode === 16 || event.charCode === 16){
					shiftDown = false;
				}
			};

			window.addEventListener? document.addEventListener('keydown', setShiftDown) : document.attachEvent('keydown', setShiftDown);
			window.addEventListener? document.addEventListener('keyup', setShiftUp) : document.attachEvent('keyup', setShiftUp);
hf
Don
Posts: 143
Joined: Thu Mar 07, 2013 2:59 pm
Location: Southern California

Yes, agreed an error will display there, because the pano2vr html5 javascript API does not include the same "addHotSpot" function that the pano2vr flash API provides. Compare the javascript API:
http://gardengnomesoftware.com/wiki/Pan ... Script_API

With the flash API:
http://gardengnomesoftware.com/wiki/Pano2VR_-_Flash_API

The best html5 javascript method I can think of at the moment is:
1. With each user click, write the Pan & Tilt coordinates to the database.
2. Reload the pano.

Reloading is not a very friendly experience for the user to see, but it gets the job done. If a better method comes to mind, I will post it. (For example, there might be a way to reload only the underlying xml file. That being the xml file in which the hotspot coordinates are stored. And then reload only the hotspots without reloading the entire pano. Just a thought.)
hfeist
Posts: 25
Joined: Tue Oct 16, 2007 11:21 pm
Contact:

I got it working only to discover the HTML5 version gets very sluggish after only a small number of hotspots generated this way. Such is life...
hf
Post Reply