clicking items inside a famo.us scrollview - javascript

I have a scrollview with a number of images.
events are working such that the scrollview can be dragged around.
i want to be able to click on a single image to get a detail view so used a:
surface.on 'click', => #parent.navTo('detail')
however, this has the effect that if i click an image when scrolling the above event will also fire.
i guess this is the whole reason mobile browsers have that 300ms delay - to tell if you're clicking or dragging. does Famous have other events to listen for?
In inputs/FastClick.js i only see 'touchstart' 'touchmove' and 'touchend'
do we have to track if a drag motion happened, in our own code, or does the famous engine assist with this?
FWIW i'm using a GenericSync to pipe the events around, and to make the view also work on the desktop.
constructor: (#parentView, #data) ->
SCROLLDIR = 1 # 0 horiz, 1 vertical
super({
direction: SCROLLDIR
paginated: true
pageStopSpeed: 5
})
#addContent()
#mouseSync = new famous.inputs.MouseSync({direction: SCROLLDIR})
#mouseSync.pipe(this)
addContent: () ->
comics = Comics.find()
surfaces = []
#sequenceFrom(surfaces)
for item in comics.fetch()
div = document.createElement('div')
comp = UI.renderWithData(Template.comicCover, item)
UI.insert(comp, div)
surface = new famous.core.Surface({
content: div
size: [undefined, 400]
properties:
backgroundColor: "#eff"
})
surfaces.push(surface)
surface.pipe(this)
surface.on 'click', => #parentView.navTo('comicPages')
# surface.pipe(#mouseSync)
return #surface

I have encountered a similar issue. To get around it, I simply track when the scrollview is scrolling and then ensure not scrolling on click.
Here is the code that I would add.. Hope it helps!
# In constructor
this.sync.on 'update', () => #scrolling = true
this.sync.on 'end', () => #scrolling = false
# In addContent
surface.on 'click', () =>
if !#scrolling
#parentView.navTo('comicPages')

Related

Drag and Drop with resizing browser window (react-use-gesture)

I used hook useDrag from 'react-use-gesture'.
const drag = useDrag((params) => {},
{
bounds: {...bounds}
}
)
I use bounds in full clientWidth.
It works fine with constant bounds. But after resizing browser window (open devtools panel in my case) hook use previous offset value(I need to drag all width of resizing clientWidth).
How can I use useDrag with document.body.clientWidth?
I found solution. If we need dynamic bounds we can rewrite values in hook callback
const bind = useGesture({
onDrag: (params) => {
params._bounds[0] = [1, smth1];
if (params.offset[0] > smth2) {
params.lastOffset[0] = smth2
params.offset[0] = smth2
}
})

click handler to an individual isolated Sprite

is there a way to bind a click handler to an individual isolated Sprite
sprite.getChildren().forEach(
s => s.setInteractive({ cursor: 'url(./src/games/gewgly/assets/images/pointer.png), pointer' })
);
I used this method to tie isolated sprites, but it hasn't worked yet, is there a better way
A Sprite in Phaser 3 cannot have children, so the sprite.getChildren part of your code worries me a bit. Only Groups have a getChildren method.
At its most simple:
const player = this.add.sprite(x, y, texture);
player.setInteractive();
player.on('pointerdown', () => {
console.log('You clicked the player sprite');
});
// Or, if you have a Group full of Sprites:
const sprites = yourGroup.getChildren();
sprites.forEach((child) => {
child.setInteractive();
child.on('pointerdown', () => {
console.log('You clicked a Group sprite');
});
});

mouseup/down on entire SPA angular

In my component class I have
#HostListener('document:mousedown', ['$event'])
onMouseDown() {
this.holding = true;
}
#HostListener('document:mouseup', ['$event'])
onMouseUp() {
this.holding = false;
}
In this project I'm also using swiper library. My swiper is 200px height and 100% width. Swiper use some own events catching for "grabing" elements to make it actually swipeable.
Now when I have my mouse on top of swiper element and I click above code doesn't catch the event.
This shoudln't happen but it is. Also what make it even weirder is that it doesn't catch only the left mouse click, right click works correctly.
How to make it works even when mouse is on top of swiper?
Edit
For some reason I'm not able to reproduce issue at online code playground, so I've created very basic app with just two components and I pushed it to git.
In this project I'm displaying {{ holding }} and as you can see (if you clone and ng serve this app) when clicking at the top or bottom of page it change from false to true but when clicking on swiper it doesn't catch onMouseDown and the value doesn't change.
because Swiper prevent the dispatching of internal DOM element, you can use Event API from swiper to get what is happening inside Swiper main dom element.
For example on your case you can do something like this :
this.mySwiper = new Swiper('.nav', {
paginationClickable: false,
grabCursor: true,
loop: true,
autoplay: 1000,
slidesPerView: 3,
spaceBetween: 50
});
this.mySwiper.on('touchStart', () => {
this.touchService.triggerTouchStart();
});
this.mySwiper.on('touchEnd', () => {
this.touchService.triggerTouchStop();
});
You can introduce new service on your application to abstract to the rest of your application this trick to be binded on all mousedown | mouseup events. bellow you can find the implementation :
export class TouchService {
private _manualControl$: Subject<boolean>;
constructor() {
this._manualControl$ = new Subject();
// React to the document mouse event.
fromEvent(document, 'mousedown').subscribe(() => this.triggerTouchStart());
fromEvent(document, 'mouseup').subscribe(() => this.triggerTouchStop());
}
// Can be call manually to force new state.
triggerTouchStart(): void {
this._manualControl$.next(true);
}
triggerTouchStop(): void {
this._manualControl$.next(false);
}
get touch$(): Observable<boolean> {
return this._manualControl$.asObservable();
}
}
Now you have observable which react on native mousedown and mouseup events and can also be trigger by manual API call like
this.mySwiper.on('touchStart', () => {
this.touchService.triggerTouchStart();
});
this.mySwiper.on('touchEnd', () => {
this.touchService.triggerTouchStop();
});
Finally you can use this service like following :
constructor(private touchService: TouchService) {
this.touchService.touch$.subscribe(e => this.holding = e);
}
I can't prupose you pull request on your project because i don't have right to do it. You can see it in action here
git remote add fork https://bitbucket.org/yghidouche/ng-hover-issue
git fetch fork issues_1

Not able to make sprite interaction to work

I'm trying to build a simple game menu, containing some clickable sprites, which will be used as buttons to navigate around the menu.
( I'm using the latest pixi.js (v4.3.5) )
Structure of my app:
loader.module ( makes use of the pixi.loaders.Loader )
events.module (basic event sub/pub module)
base.view
menu.view ( extends base.view )
game.main
How it all works now ?
Both all resources and ui elements have to be explicitly defined, before initializing the view.
so in the menu.view, the follwoing attributes have to be defined.
this.resources = [
{ name: 'start', src: 'img/start.png'},
{ name: 'start2', src: 'img/start2.png'}
];
this.ui = [{
name: 'start', /// resource name
type: 'img',
pos: { x: 0, y: 0 }
}];
Now I only need to call view.init() to get it all loaded and drawn. On the visual side, evrything works perfectly, however the 'start' sprite (which has it's interactive and buttonMode set to true) is not reacting to any mouse events.
The below method is responsible for getting the required resource and returning a new sprite. It also enables the actual interaction functionality as part of this process. But the test function is never triggered for some reason.
__getSpriteObject( element ){
let sprite = new PIXI.Sprite( this.loader.loader.resources[ element.name ].texture );
sprite.x = element.pos.x;
sprite.y = element.pos.y;
sprite.interactive = true;
sprite.buttonMode = true;
console.log( sprite )
sprite.on('pointerdown', function(){
console.log("what")
})
return sprite;
}
If the above info isn't sufficient , here is also a working example.
I answered this here: http://www.html5gamedevs.com/topic/28474-not-able-to-make-sprite-interaction-to-work/?do=findComment&comment=163647 in any case anyone else is curious

How to lock slider and prevent updating of values with mouse into dat.GUI menu

I try to implement a way to prevent the updating of values with mouse (actually when the three.js animation has started, launched with a click on button).
For the moment, I have the following dat.GUI menu:
Once "start" button is clicked, I would like to prevent user from modifying with mouse the parameters "Rotation x" and "Rotation y".
Here is the concerned part of code for this menu:
// Create GUI
var gui = new dat.GUI({
autoplace: false,
width: 350,
height: 9 * 32 - 1
});
var params = {
GreatCircle : '',
Rotationx : torusRotationInitX,
Rotationy : torusRotationInitY,
StartingVector : '',
ComponentVectorTheta : 15.0,
ComponentVectorPhi : 15.0,
CovariantDerivativeVector : '',
ComponentCovariantDerivativeTheta : 15.0,
ComponentCovariantDerivativePhi : 15.0
};
// Set parameters for GUI
gui.add(params, 'GreatCircle').name('Great Circle ');
controllerRotationx = gui.add(params, 'Rotationx', 0, 2*Math.PI, 0.001).name('Rotation x ');
controllerRotationy = gui.add(params, 'Rotationy', 0, 2*Math.PI, 0.001).name('Rotation y ');
...
When I click on reset button, I call the following function:
// Reset Button
resetButton.onclick = function ResetParameters() {
...
// Reinitialize parameters into gui
params.Rotationx = torusRotationInitX;
params.Rotationy = torusRotationInitY;
for (var i in gui.__controllers) {
gui.__controllers[i].updateDisplay();
}
render();
}
I don't know if there is an option for controller to lock these sliders which usually change their values. Is it possible?
Update 1
Maybe I could wrapper the dat.GUI menu into a div and make this div not clickable, is it a solution?
Update 2
I tried to apply the method used on Method for disabling a button in dat.gui?
Following this solution, I have added the extension into dat.gui, just after:
dat.controllers.FunctionController = (function (Controller, dom, common) {
...
});
The following added code snippet is:
function blockEvent(event)
{
event.stopPropagation();
}
Object.defineProperty(dat.controllers.FunctionController.prototype, "disabled", {
get: function()
{
return this.domElement.hasAttribute("disabled");
},
set: function(value)
{
if (value)
{
this.domElement.setAttribute("disabled", "disabled");
this.domElement.addEventListener("click", blockEvent, true);
}
else
{
this.domElement.removeAttribute("disabled");
this.domElement.removeEventListener("click", blockEvent, true);
}
},
enumerable: true
});
Is extension code well located into dat.GUI source?
Then, I set the property "disabled" into my code to prevent user from sliding "controllerRotationx" with mouse (once start button is pressed):
if (animation)
controllerRotationx.__li.disabled = true;
Unfortunately, my method doesn't work : when animation is started, I can still move the slider contained into "controllerRotationx".
I saw that above link (Method for disabling a button in dat.gui?), this was about a button and not for a slider, does it change anything for my case?
I didn't find an explicit controller for the slider.
I would do this. The slider is not a form element, there's nothing to disable in the traditional w3c sense. Luckily we can use pointer-events and disable it properly as if it were a form element using just public dat.gui properties.
var speeder = menu.add(text, 'speed', -5, 5);
speeder.domElement.style.pointerEvents = "none"
speeder.domElement.style.opacity = .5;
The solution given by #Radio works pretty well. But, with sliders, the slider is a sibling of the text box's DOM element. We need to disable pointer events on the div which contains all the controls (and which is not exposed directly by dat.gui). So,
var speeder = menu.add(text, 'speed', -5, 5);
// disables the text box
speeder.domElement.style.pointerEvents = "none"
// disables all controller elements related to "speeder"
speeder.domElement.parentElement.style.pointerEvents = 'none'
When the Start button is pressed, set:
controllerRotationx.__li.setAttribute( "style", "display: none" );
thanks for tips
on my side i hack the Common controller
so able to chainning.
gui.add(this, '_screenW').disable(true);
Common.extend(controller, {
disable: function disable(v) {
this.domElement.style.pointerEvents = v?"none":"auto";
this.domElement.style.opacity = v?.5:1;
return controller;
},

Categories

Resources