I recently encountered a problem trying to make a div's content horizontaly scrollable, smooth. I achieved the result I want when using a touchpad, sadly its diffrent with a mouse scrollwheel. To get the scroll intensity I use "event.wheelDelta". When logging this to the console and using a touchpad to scroll to the right I will get numbers indicating the intensity, which looks similar to this: 1, 2, 3, 4, 15, 45, 150, 50, 30, 15, 13, 4, 3, 2, 1... But when I use a scrollwheel on a mouse to scroll it looks like this: 150, 150, 150, 150, 150... That in the end causes a non smooth scrolling behavior when using the scrollwheel on a mouse. Here is a good example of the issue: https://developer.mozilla.org/en-US/docs/Web/API/Element/wheel_event. Can someone help me with this? Below you see the logic of the function I use. The function gets called on a wheel event in Vue.js (v-on:wheel="replaceScrollDirection($event)").
replaceScrollDirection() {
event.preventDefault()
this.scrollPosition = document.getElementById("holideWrapper").scrollLeft
this.scrollIntensity = event.wheelDelta
this.scroll = this.scrollPosition + this.scrollIntensity * -1
document.getElementById("holideWrapper").scrollTo({left: this.scroll})
}
Related
The game I'm creating doesn't require any physics, however you are able to interact when hovering over/clicking on the sprite by using sprite.setInteractive({cursor: "pointer"});, sprite.on('pointermove', function(activePointer) {...}); and similar. However I noticed two issues with that:
The sprite has some area which are transparent. The interactive functions will still trigger when clicking on those transparent areas, which is unideal.
When playing a sprite animation, the interactive area doesn't seem to entirely (at all?) change, thus if the sprite ends on a frame bigger than the previous, there end up being small areas I can't interact with.
One option I thought of was to create a polygon over my sprite, which covers the area I want to be interactive. However before I do that, I simply wanted to ask if there are simpler ways to fix these issues.
Was trying to find an answer for this myself just now..
Think Make Pixel Perfect is what you're looking for.
this.add.sprite(x, y, key).setInteractive(this.input.makePixelPerfect());
https://newdocs.phaser.io/docs/3.54.0/focus/Phaser.Input.InputPlugin-makePixelPerfect
This might not be the best solution, but I would solve this problem like this. (If I don't want to use physics, and if it doesn't impact the performance too much)
I would check in the event-handler, if at the mouse-position the pixel is transparent or so, this is more exact and less work, than using bounding-boxes.
You would have to do some minor calculations, but it should work well.
btw.: if the origin is not 0, you would would have to compensate in the calculations for this. (in this example, the origin offset is implemented)
Here is a demo, for the click event:
let Scene = {
preload ()
{
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
},
create ()
{
// Animation set
this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('brawler', { frames: [ 0, 1, 2, 3 ] }),
frameRate: 8,
repeat: -1
});
// create sprite
const cody = this.add.sprite(200, 100).setOrigin(0);
cody.play('walk');
cody.setInteractive();
// just info text
this.mytext = this.add.text(10, 10, 'Click the Sprite, or close to it ...', { fontFamily: 'Arial' });
// event to watch
cody.on('pointerdown', function (pointer) {
// calculate x,y position of the sprite to check
let x = (pointer.x - cody.x) / (cody.displayWidth / cody.width)
let y = (pointer.y - cody.y) / (cody.displayHeight / cody.height);
// just checking if the properties are set
if(cody.anims && cody.anims.currentFrame){
let currentFrame = cody.anims.currentFrame;
let pixelColor = this.textures.getPixel(x, y, currentFrame.textureKey, currentFrame.textureFrame);
// alpha > 0 a visible pixel of the sprite, is clicked
if(pixelColor.a > 0) {
this.mytext.text = 'Hit';
} else {
this.mytext.text = 'No Hit';
}
// just reset the textmessage
setTimeout(_ => this.mytext.text = 'Click the Sprite, or close to it ...' , 1000);
}
}, this);
}
};
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: Scene
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I'm creating a constraint between a body and a point:
var tempConstraint = Constraint.create({pointA: {x: 50, y: 50}, bodyB: body, pointB: {x: x, y: y}, stiffness: 0.1, length: 0, damping: 0.5, });
The point is also being moved around:
tempConstraint.pointA = {x: newX, y: newY};
The issue is that if pointA is moved slowly from left to right, for example, the body its dragging moves the opposite direction to what it should be. For example, if you dangle a pencil by the very tip and start moving the tip to the right, the bottom of the pencil should start to hang slightly to the left of the top as it moves. However, if I were to do that exact thing with the above code, the bottom of the pencil flies over to the right, exactly as it should if the top were being pulled left. Not sure what I'm doing wrong here but my only thought is that changing pointA is a bad idea, but I can't really come up with a better way to move the constraint point. Would creating a collision disabled, static body and attaching it to that, and then moving the body be a better way to go about this?
It's working fine for me, although I'm using a spring constraint. I've also removed the length property in the constraint so the length is auto generated:
var vw = window.innerWidth/100;
var vh = window.innerHeight/100;
var body = Bodies.rectangle(vw*50, vh*50, vw*3, vw*15, {
frictionAir: 0.02,
friction: 1,
render: {
fillStyle: "#FCED08"
}
});
var tempConstraint = Constraint.create({pointA: {x: vw*50, y: vh*50}, bodyB: body, pointB: {x:0,y:vw*7.5}, stiffness: 0.8, damping: 0.5, render: {type: "spring"}});
World.add(world, [body, tempConstraint]);
The full code is here
To clarify my example, I want to simulate a scroll event at the center of an open window. This should affect what is reasonably the main scrolling element on a given page.
Here are some relevant pages
https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/WheelEvent
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent#Values
and here's what I've tried.
scroll_evt = new WheelEvent('wheel', {
deltaY: 10.0,
deltaMode: WheelEvent.DOM_DELTA_LINE,
clientX: content.innerWidth/2,
clientY: content.innerHeight/2
});
-> wheel { target: null, buttons: 0, clientX: 520, clientY: 320, layerX: 0, layerY: 0 }
However, despite no errors, dispatching the event seems not to have any effect.
window.dispatchEvent(scroll_evt);
-> true
So I'm left to wonder: Is there some critical property I'm missing in my initializer? Is window an appropriate target for the event? I'm out of ideas.
Update
This works.
https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIDOMWindowUtils#sendWheelEvent%28%29.
var windowutils = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface (Components.interfaces.nsIDOMWindowUtils);
windowutils.sendWheelEvent(window.innerWidth / 2, window.innerHeight / 2, 0, 10, 0,
WheelEvent.DOM_DELTA_LINE, 0, 0, 0, 0);
I'm still curious what's the matter with dispatchEvent.
You can get an element by position like so:
var elem = document.elementFromPoint(content.innerWidth / 2, content.innerHeight / 2);
and then apply the scroll:
elem.scrollTop += 10;
First of all, I'm pretty new to jQuery but with the help of http://css-tricks.com/examples/Circulate/ I managed to figure out how to create ellipses in my code.
Here's the thing though, I want to create an input field/text box for users to type in their own "speed" value (which is now set at "500") and then click a submit button to start the ellipse.
$("#ball").circulate({
speed: 500,
height: 500,
width: 200,
loop: true,
zIndexValues: [1, 1, 1, 1]
});
I figured out the submit button part, but I keep running in circles when it comes to finding a way for a visitor of my website to manually input the "speed". I would be much obliged if someone could point me in the right direction/could give me a starting point.
Try this:
$('#submitButton').click(function() {
var userSpeed = +$('#inputBox').val();
if (!userSpeed) {userSpeed == 500};
$("#ball").circulate({
speed: userSpeed,
height: 500,
width: 200,
loop: true,
zIndexValues: [1, 1, 1, 1]
});
});
Then, when the user clicks on the submit button, your code gets the new value and sets the speed for the function. If the user clicks the button without having entered a number, a default speed is used.
You have to use .val() function to get the value from an input and then use it to set the speed.
var input = $("#YOUR_INPUT_ID");
$("#ball").circulate({
speed: input.val(),
height: 500,
width: 200,
loop: true,
zIndexValues: [1, 1, 1, 1]
});
It seems to happen only when I try to animate an image on Chrome. All I want to do is make an image to move back an forth in Raphaƫl.js. I created a jsfiddle that illustrates the problem. I'm very sure that it used to work in Chrome since I use it to develop and it seems to be broken in later versions of Chrome. When I change the image to a rect for example it seems to render fine. When you resize the screen that contains the animation it repaints.
http://jsfiddle.net/k69yzz0o/1/
var moveForth = function () {
useControl.animate({x : 38, y: 0}, 900, moveBack);
};
var moveBack = function () {
useControl.animate({x : 0, y: 0}, 600, moveForth);
};
var R = Raphael("holder", 500, 500);
useControl = R.image("http://i.imgur.com/ta8zlD2.png", 0, 0, 189, 18);
moveForth();
It only happens in Chrome and I use latest Raphael.js 2.1.2.
How can I resolve this issue?
Yes, there appears to be an issue with Chrome recognizing the rect as dirty, and refusing to repaint it. You can see that it's working by mousing over the area.
I tried the same animation using a Transform rather than using the actual position. Transforming an object evidently correctly tells modern Chrome to redraw that area.
Here it is working:
var moveForth = function () {
useControl.animate({"transform":"T38,0"}, 900, ">", moveBack);
};
var moveBack = function () {
useControl.animate({"transform":""}, 600, "<", moveForth);
};
var R = Raphael("holder", 500, 500);
useControl = R.image("http://i.imgur.com/ta8zlD2.png", 0, 0, 189, 18);
moveForth();
I also added some easing (">") to give it a more natural bounce.