How to stop simultaneous browser and SWF mouse wheel scrolling in AS3? - actionscript-3

Essentially, I have flash content that scrolls on mouse wheel. It works fine, unless there is other content in the browser such that the browser's scrollbar is enabled - when that is the case, both the browser window AND my SWF scroll on mouse wheel. Is there any way to correct this behavior?
Similar question asked here:
disable mouse wheel scrolling while cursor over flex app?
which references the solution blogged about here:
http://www.spikything.com/blog/index.php/2009/11/27/stop-simultaneous-flash-browser-scrolling/
But the solution does not work on all browsers! While it works on some Windows browsers, it doesn't work at all on Mac OS X - it registers mouse wheel events in Firefox, but they are not getting fired at all in Chrome and Safari.
Now I know that (per the official Adobe InteractiveObject docs) mouse wheel is supposedly only supported on Windows systems, but the event is still fired by default on Mac OS X. Is this simultaneous scroll bug the reason it is not supported?
Edit: adding more info on above solution...
Note that the above solution basically uses ExternalInterface to send the following JavaScript to the "eval" function:
var browserScrolling;
function allowBrowserScroll(value) {
browserScrolling = value;
}
function handle(delta) {
if (!browserScrolling) {
return false;
}
return true;
}
function wheel(event) {
var delta = 0;
if (!event) {
event = window.event;
}
if (event.wheelDelta) {
delta = event.wheelDelta / 120;
} else if (event.detail) {
delta = -event.detail / 3;
}
if (delta) {
handle(delta);
}
if (!browserScrolling) {
if (event.preventDefault) {
event.preventDefault();
}
event.returnValue = false;
}
}
if (window.addEventListener) {
window.addEventListener('DOMMouseScroll', wheel, false);
}
window.onmousewheel = document.onmousewheel = wheel;
allowBrowserScroll(true);
Is this cat at least on the right path, or is there a better (i.e. fully functional) solution?

I created a small lib that handles everything for you. It works perfect (as far as I tested) on default flash player plugin, on Pepper flash and on MAC-OS. And you don't need to add any .js files to your HTML folder
GIhub repo

You should be able to do this entirely via javascript ...
First off you need to listen to "wheel", "mousewheel" and also to "DOMMouseScroll". It appears DOMMouseScroll is for Firefox only .....
Secondly -- it might be a little bit better to do this entirely in javascript:
// pseudo-code -- this tests for all "Objects" using not-so-standard elementFromPoint;
// You can also look for the element directly using id
var fn = function(e) {
var element = document.elementFromPoint(e.pageX, e.pageY);
if (element && element.tagName === 'OBJECT') {
e.preventDefault();
e.stopPropagation();
}
}
window.addEventListener('DOMMouseScroll', fn);
window.addEventListener('mousewheel', fn);

You may need to test the variations of scroll and mousewheel to access the Webkit events. See here.

I believe you will have to hook the event in JS on the page, then prevent default, and send the event(delta) to your flash. The code you posted looks like it is setting that up somewhat (preventing default) yet I do not see where the code is hooking the DOM.

Related

MarkupCore - Is it possible to disable rightClick on a hovered markup in ForgeViewer?

Whenever I hover a markup and right click it, it locks the mouse movement to the drawing and makes it impossible to move the mouse without moving the drawing.
Is it possible to disable this behaviour?
Depending on your specific scenario, there's a few things you can try:
If you're trying to enable camera pan while in the markup mode on a 2D drawing, you can simply "enable navigation" for the markup tool:
viewer.toolController.getTool('markups.core').allowNavigation(true);
If that's not sufficient for your case, you could also try and modify the handleButtonDown method that the markup tool uses to decide whether and how it should handle the mouse button down event. Currently the method looks like this:
this.handleButtonDown = function(event, button) {
if (this.allowNav || (this.is2d && (avp.isRightClick(event, this.viewer.navigation) || avp.isMiddleClick(event)))) {
// If pan tool won't handle button down, then pass over the event
if (this.panTool && this.panTool.handleButtonDown) {
return this.panTool.handleButtonDown(event, button);
} else return false;
}
return true; // Consume event
};
Where avp is just a shortcut to the Autodesk.Viewing.Private namespace.
viewer.toolController.getTool('markups.core').handleButtonDown = function (event, button) {
// Return true when you want the measure tool to "capture" the event and process it somehow,
// or false when you want to ignore the event and allow other tools on the stack to handle it
};

browser response on dragover - html5 drag and drop

I am using html5 drag and drop.
When I drag an image or link from any given webpage, the browser-window is recognizing the dragover event.
For example dragging an image over a browser tab, makes the browser switching the window. Same works for example with dragging links to bookmarks.
Now when I drag my custom draggable element, there is no reaction from the browser. Is there a way to change this behavior?
I don't understand what you want to achieve, but it seems that you want to make something happens when you move your custom element outside the document or the window.
You should try binding a handler with a dragleave or something like that. Here is an example from another question:
var dropTarget = $('.dropTarget'),
html = $('html'),
showDrag = false,
timeout = -1;
html.bind('dragenter', function () {
dropTarget.addClass('dragging');
showDrag = true;
});
html.bind('dragover', function(){
showDrag = true;
});
html.bind('dragleave', function (e) {
showDrag = false;
clearTimeout( timeout );
timeout = setTimeout( function(){
if( !showDrag ){ dropTarget.removeClass('dragging'); }
}, 200 );
});
I think that could work for you, but for further help you should extend your issue's description.
Also I ll leave some HTML5 drag and drop docs here

Unity WebGL - Prevent <Canvas> From eating up all Mouse / Keyboard Input? (HTML Input Fields)

Unity 5.4
Building a Unity WebGL application (not a game) that handles all 3D content on the Unity side of things, and all the UI is built using HTML/CSS/JS. By default, WebGLInput.captureAllKeyboardInput is set to true, which causes any input fields that require keyboard (text) input to be broken, as any keyboard controls are automatically being eaten up by Unity rather than going to the input field. Doing
#if !UNITY_EDITOR && UNITY_WEBGL
WebGLInput.captureAllKeyboardInput = false;
#endif
fixes the issue with input fields, but causes unity to ignore ALL keyboard inputs, even after the element is focused, however adding
tabindex="1"
to the fixes it so that keyboard input on HTML input fields works when focused, and keyboard controls inside the Unity WebGL app works when focused as well. (this is all per the docs: https://docs.unity3d.com/ScriptReference/WebGLInput-captureAllKeyboardInput.html). So that's all working fine.
However, the Unity WebGL application is still causing issues with some input fields using MOUSE (not keyboard) controls. Namely I've noticed it on input type="range" fields (HTML5 sliders) and input type="number (using keyboard to type in numbers works, but mouse clicking up and down do not).
Is there any sort of workaround to fix this? I essentially need to prevent the Unity WebGL canvas to not automatically take all mouse inputs, unless the element is clicked/focused first (just like the way the keyboard controls work). Anything to change on the Unity side to fix this? Or do I need to write some custom JavaScript to handle all input and determine whether it's intended for the Unity scene or the HTML UI?
I was having the same issue but I believe I've found a workaround! Originally I was just going to use OnApplicationFocus to toggle WebGLInput.captureAllKeyboardInput. But OnApplicationFocus doesn't work with WebGL builds of Unity so I'm doing this instead.
I have a script named "GameControl" on a GameObject also named "GameControl" in the first scene when the game is loaded.
// In the Start function of this script I call a function on the webpage to let it know that the game has loaded.
void Start () {
#if (UNITY_WEBPLAYER || UNITY_WEBGL) && !UNITY_EDITOR
try {
Application.ExternalCall("GameControlReady");
} catch (System.Exception e) {
Debug.LogError("GameControlReady function not on webpage"+e);
}
#endif
}
// This function will be called from the webpage
public void FocusCanvas (string p_focus) {
#if !UNITY_EDITOR && UNITY_WEBGL
if (p_focus == "0") {
WebGLInput.captureAllKeyboardInput = false;
} else {
WebGLInput.captureAllKeyboardInput = true;
}
#endif
}
On the webpage, I have the following javascript:
var gameReady = false;
// Called by Unity in GameControl's start function
function GameControlReady () {
gameReady = true;
}
function FocusCanvas(focus) {
if (gameReady) {
SendMessage("GameControl", "FocusCanvas", focus);
}
}
And in the head section of the webpage I have the following
<script type='text/javascript'>
document.addEventListener('click', function(e) {
if (e.target.id == "canvas") {
// Clicked on canvas
FocusCanvas("1");
} else {
// Clicked outside of canvas
FocusCanvas("0");
}
});
</script>

HTML5 Audio stop function

I am playing a small audio clip on click of each link in my navigation
HTML Code:
<audio tabindex="0" id="beep-one" controls preload="auto" >
<source src="audio/Output 1-2.mp3">
<source src="audio/Output 1-2.ogg">
</audio>
JS code:
$('#links a').click(function(e) {
e.preventDefault();
var beepOne = $("#beep-one")[0];
beepOne.play();
});
It's working fine so far.
Issue is when a sound clip is already running and i click on any link nothing happens.
I tried to stop the already playing sound on click of link, but there is no direct event for that in HTML5's Audio API
I tried following code but it's not working
$.each($('audio'), function () {
$(this).stop();
});
Any suggestions please?
Instead of stop() you could try with:
sound.pause();
sound.currentTime = 0;
This should have the desired effect.
first you have to set an id for your audio element
in your js :
var ply = document.getElementById('player');
var oldSrc = ply.src;// just to remember the old source
ply.src = "";// to stop the player you have to replace the source with nothing
I was having same issue. A stop should stop the stream and onplay go to live if it is a radio. All solutions I saw had a disadvantage:
player.currentTime = 0 keeps downloading the stream.
player.src = '' raise error event
My solution:
var player = document.getElementById('radio');
player.pause();
player.src = player.src;
And the HTML
<audio src="http://radio-stream" id="radio" class="hidden" preload="none"></audio>
Here is my way of doing stop() method:
Somewhere in code:
audioCh1: document.createElement("audio");
and then in stop():
this.audioCh1.pause()
this.audioCh1.src = 'data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAVFYAAFRWAAABAAgAZGF0YQAAAAA=';
In this way we don`t produce additional request, the old one is cancelled and our audio element is in clean state (tested in Chrome and FF) :>
This method works:
audio.pause();
audio.currentTime = 0;
But if you don't want to have to write these two lines of code every time you stop an audio you could do one of two things. The second I think is the more appropriate one and I'm not sure why the "gods of javascript standards" have not made this standard.
First method: create a function and pass the audio
function stopAudio(audio) {
audio.pause();
audio.currentTime = 0;
}
//then using it:
stopAudio(audio);
Second method (favoured): extend the Audio class:
Audio.prototype.stop = function() {
this.pause();
this.currentTime = 0;
};
I have this in a javascript file I called "AudioPlus.js" which I include in my html before any script that will be dealing with audio.
Then you can call the stop function on audio objects:
audio.stop();
FINALLY CHROME ISSUE WITH "canplaythrough":
I have not tested this in all browsers but this is a problem I came across in Chrome. If you try to set currentTime on an audio that has a "canplaythrough" event listener attached to it then you will trigger that event again which can lead to undesirable results.
So the solution, similar to all cases when you have attached an event listener that you really want to make sure it is not triggered again, is to remove the event listener after the first call. Something like this:
//note using jquery to attach the event. You can use plain javascript as well of course.
$(audio).on("canplaythrough", function() {
$(this).off("canplaythrough");
// rest of the code ...
});
BONUS:
Note that you can add even more custom methods to the Audio class (or any native javascript class for that matter).
For example if you wanted a "restart" method that restarted the audio it could look something like:
Audio.prototype.restart= function() {
this.pause();
this.currentTime = 0;
this.play();
};
It doesn't work sometimes in chrome,
sound.pause();
sound.currentTime = 0;
just change like that,
sound.currentTime = 0;
sound.pause();
From my own javascript function to toggle Play/Pause - since I'm handling a radio stream, I wanted it to clear the buffer so that the listener does not end up coming out of sync with the radio station.
function playStream() {
var player = document.getElementById('player');
(player.paused == true) ? toggle(0) : toggle(1);
}
function toggle(state) {
var player = document.getElementById('player');
var link = document.getElementById('radio-link');
var src = "http://192.81.248.91:8159/;";
switch(state) {
case 0:
player.src = src;
player.load();
player.play();
link.innerHTML = 'Pause';
player_state = 1;
break;
case 1:
player.pause();
player.currentTime = 0;
player.src = '';
link.innerHTML = 'Play';
player_state = 0;
break;
}
}
Turns out, just clearing the currentTime doesn't cut it under Chrome, needed to clear the source too and load it back in. Hope this helps.
As a side note and because I was recently using the stop method provided in the accepted answer, according to this link:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element. In the link it mentions Firefox, but I encountered this event firing after setting currentTime manually on Chrome. So if you have behavior attached to this event you might end up in an audio loop.
shamangeorge wrote:
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element.
This is indeed what will happen, and pausing will also trigger the pause event, both of which make this technique unsuitable for use as a "stop" method. Moreover, setting the src as suggested by zaki will make the player try to load the current page's URL as a media file (and fail) if autoplay is enabled - setting src to null is not allowed; it will always be treated as a URL. Short of destroying the player object there seems to be no good way of providing a "stop" method, so I would suggest just dropping the dedicated stop button and providing pause and skip back buttons instead - a stop button wouldn't really add any functionality.
This approach is "brute force", but it works assuming using jQuery is "allowed". Surround your "player" <audio></audio> tags with a div (here with an id of "plHolder").
<div id="plHolder">
<audio controls id="player">
...
</audio>
<div>
Then this javascript should work:
function stopAudio() {
var savePlayer = $('#plHolder').html(); // Save player code
$('#player').remove(); // Remove player from DOM
$('#FlHolder').html(savePlayer); // Restore it
}
I was looking for something similar due to making an application that could be used to layer sounds with each other for focus. What I ended up doing was - when selecting a sound, create the audio element with Javascript:
const audio = document.createElement('audio') as HTMLAudioElement;
audio.src = getSoundURL(clickedTrackId);
audio.id = `${clickedTrackId}-audio`;
console.log(audio.id);
audio.volume = 20/100;
audio.load();
audio.play();
Then, append child to document to actually surface the audio element
document.body.appendChild(audio);
Finally, when unselecting audio, you can stop and remove the audio element altogether - this will also stop streaming.
const audio = document.getElementById(`${clickedTrackId}-audio`) as HTMLAudioElement;
audio.pause();
audio.remove();
If you have several audio players on your site and you like to pause all of them:
$('audio').each( function() {
$(this)[0].pause();
});
I believe it would be good to check if the audio is playing state and reset the currentTime property.
if (sound.currentTime !== 0 && (sound.currentTime > 0 && sound.currentTime < sound.duration) {
sound.currentTime = 0;
}
sound.play();
for me that code working fine. (IE10+)
var Wmp = document.getElementById("MediaPlayer");
Wmp.controls.stop();
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6"
standby="Loading áudio..." style="width: 100%; height: 170px" id="MediaPlayer">...
Hope this help.
What I like to do is completely remove the control using Angular2 then it's reloaded when the next song has an audio path:
<audio id="audioplayer" *ngIf="song?.audio_path">
Then when I want to unload it in code I do this:
this.song = Object.assign({},this.song,{audio_path: null});
When the next song is assigned, the control gets completely recreated from scratch:
this.song = this.songOnDeck;
The simple way to get around this error is to catch the error.
audioElement.play() returns a promise, so the following code with a .catch() should suffice manage this issue:
function playSound(sound) {
sfx.pause();
sfx.currentTime = 0;
sfx.src = sound;
sfx.play().catch(e => e);
}
Note: You may want to replace the arrow function with an anonymous function for backward compatibility.
In IE 11 I used combined variant:
player.currentTime = 0;
player.pause();
player.currentTime = 0;
Only 2 times repeat prevents IE from continuing loading media stream after pause() and flooding a disk by that.
What's wrong with simply this?
audio.load()
As stated by the spec and on MDN, respectively:
Playback of any previously playing media resource for this element stops.
Calling load() aborts all ongoing operations involving this media element

Kinetic.js don't lose grip on mouse out

When you drag an object and mouse is out of rendering area, dragging stops (firing an event) and user loses a grip.
It's extremelly inconvenient, taking into account that all other technologies (Flash, raw HTML5 Canvas, etc) allows to save the grip even if mouse is out.
Is there a way to solve the problem?
UPDATE: Up to the moment solved the problem by changing library file and binding listeners to the document, not to the container. I know that it's bad to hack into library files, but after inspecting the library's source code I haven't found out way around.
you could check if the element is out of sight and if so bring it back:
shape.on('dragend', function() {
var pos = shape.getPosition();
var layer = pos.getLayer();
if (pos.y < 0) {
pos.y = 0;
}
var maxY = layer.getHeight() - shape.getHeight();
if (pos.y > maxY) {
pos.y = maxY
}
shape.setPosition(pos);
}
Look at element.setCapture(). You can call it from within an event handler for a mouse event, eg. mousedown:
function mouseDown(e) {
e.target.setCapture();
e.target.addEventListener("mousemove", mouseMoved, false);
}
Although browser support is a bit spotty (IE and Firefox support it, not sure about other browsers), for cross browser use you would have to fall back to the binding on the document approach you've already hit upon.