I am trying to create an interface using PIXI JS where I have one main canvas i.e. the stage. After that I have a graphics element as a child to the stage. On clicking the graphic element I want to be able to zoom in on the element so that it fills up 80% of my canvas. My main goal is to have multiple elements and on clicking each of them the canvas zooms in and only that element is visible.
What I have done so far:
this.renderer = this.PIXI.autoDetectRenderer(window.innerWidth, window.innerHeight, {
transparent: true,
anitalias: true
});
this.stage = new this.PIXI.Container();
this.graphics = new this.PIXI.Graphics();
this.graphics.beginFill(0x2F7455);
this.graphics.drawRect(100, 100, 75, 50);
this.graphics.endFill();
this.graphics.interactive = true;
this.graphics.click = function (){
self.animate = true;
self.grow();
console.log("I WAS CLICKED");
}
this.stage.addChild(this.graphics);
animation() {
requestAnimationFrame(this.animation.bind(this));
this.renderer.render(this.stage);
}
grow() {
this.stage.pivot.x = this.graphics.width / 2;
this.stage.pivot.y = this.graphics.height / 2;
if (this.stage.scale.x < 20) {
this.stage.scale.x = (this.stage.scale.x * 1.25).toFixed(1);
}
if (this.stage.scale.y < 20) {
this.stage.scale.y = (this.stage.scale.y * 1.25).toFixed(1);
}
}
So on clicking the graphics element the canvas zooms in. But it's not what I want and I can't seem to wrap my head around the logic that will help me achieve what I want.
Anyone has any ideas on the approach I should take?
when asking something special like this you should always create a demonstration on plnkr.co or codepen so that the audience can quickly try out what you have done so far. This will lower the barrier for people to help you.
Regarding your problem. You need to know what size you want to achieve (the stage size), you want to know what size your object has (bounding box) and then you can calculate how much you have to resize. This would be the value 1.25 you just have hardcoded.
You also have to think about what you want to do when the object has another ratio (width vs. height) as the stage. Cut off, fit in or stretch ? This is the idiomatic way.
I also recommend you that you read through the sources of the pixi camera js library. You will quickly notice that I worked with matrix multiplications.
Don't let this fear you but encourage you to learn something new. Matrix calculations is the key for being very flexible here and useful in so many other areas of programming.
Good luck.
Related
I've had trouble finding a solution for this in Aframe because I guess it’s an odd use case. I'm wanting to make an embedded Aframe scene as the background of a webpage and have the camera animate along a path as a user scrolls down the page.
I've created a scene, animated the camera movement using the alongpath component and have fixed it as the background of a webpage, but I cannot figure out what I need to do to pair scroll position to the camera path. I'm attaching a video of the scene I currently have with the animation path.
I did manage to connect in to the camera controls from some JS on a demo page here. https://robbiegreen.com/hq/ I honestly have no idea how I pulled that off. It’s only controlling the Z position though. Sorry in advance for the bloat, I’m testing part of it on Elementor + WP install that I need to clean up, but I’m building scenes and such locally. Here is a glitch of what I have:
https://glitch.com/edit/#!/aframe-alongpath-scroll
This is a good example at what I would love to do: https://codepen.io/motionharvest/pen/WNQYJyM <HTML>
I love stuff I’ve seen in three.js but Aframe is so much more approachable even if it’s not the exact use case. I’m in way over my head when it comes to JS or anything programming related. I feel like I’m slowly starting to grasp at a few straws though.
listen to mouse move event and utilize x,y of its position. to apply previous Z, use .getAttribute().
I think this will be much easier if you learn react and react-three-fiber; that's where I decided to settle. implementing interactivity by scratch is way difficult for anyone and not to mention for beginners.
honestly, I applaud your effort. this is really difficult stuff even for veterans.
<!-- Script Used For Moving Camera On Scroll -->
<script>
var el = document.querySelector('#cameraRig');
function moveCamera() {
const t = document.body.getBoundingClientRect().top;
cameraRig.setAttribute('position', { x: 0, y: 1.5, z: t * -0.02});
}
const pointer = new THREE.Vector2();
function onPointerMove(ev) {
pointer.x = ( event.clientX / window.innerWidth ) * 2 - 1;
pointer.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
const prevPos = cameraRig.getAttribute('position');
cameraRig.setAttribute('position', /* ...do something with x, y */);
}
document.body.onscroll = moveCamera;
document.addEventListener('mousemove', onPointerMove);
moveCamera();
</script>
There's a bunch of questions on panning a background image in a canvas (i.e. to simulate a 'camera' in a game with the character in the center) - and most answers suggest using the canvas' translate method.
But since you have to re-draw the image in each frame anyway, why not just clip it? Does it matter in terms of efficiency?
In particular, is panning like this a bad idea? (This example shows a simplified pan of the camera moving in one direction)
let drawing = new Image();
drawing.src = "img_src";
drawing.onload = function () {
ctx.drawImage(drawing, 0, 0);
let pos = 0
setInterval(() => {
pos += 1
ctx.clearRect(0, 0, cnvs.width, cnvs.height);
ctx.drawImage(drawing, -pos, 0 ); // "pans" the image to the left using the option `drawImage` parameters `sx` and `sy`
}, 33);
};
Example result: fiddle
Thanks in advance!
The main advantage of using the transform matrix to control your camera is that you don't have to update all the elements in your world, you just move the world instead.
So yes, if you are willing to move only a single element (be it the background like in your case), moving only that one element might be a better choice.
But if you need several layers of elements to all move relatively to the camera, then using the transformation matrix is a better choice.
As for the perfs, I didn't ran any benchmarks on this, but I'd suspect it's exactly the same, though beware when messing with the cropping features of drawImage, at least Safari doesn't handle cropping from outside of a source canvas correctly.
I am really new to javascript, css, and html, but i want to learn. The problem is, its not clear the direction i should head in. I want to make a game site that can play a few games. Im trying to make a game board that will have a dynamic size based on the height and/or width of the browser while maintaining the aspect ratio of its original. It is going to have elements inside of it which must also decrease their size proportionately to its parent. I have tried using bootstrap 4, with its col, row, and container classes. I am struggling to make it work with the container class. I have recently come across the , which I saw someone use to achieve this. can anyone give me a better idea whats going on here?
one example is this website https://colonist.io/ just click play game, at the top, manipulate the browser height and width, you will see how it resizes, and all child elements. this is the exact effect i am looking for.
thanks.
Well.. maybe this will suit your needs better
var scale = {}, isInitial = true;
window.onresize = function() {
// make sure the ctx variable is global or visible in current scope in your code
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
if (isInitial) {
isInitial = false;
scale.width = ctx.canvas.width;
scale.height = ctx.canvas.height;
} else {
scale.x = window.innerWidth / scale.width, scale.y = window.innerHeight / scale.height;
ctx.scale(scale.x, scale.y);
// redraw your canvas graphics
}
}
Please ensure that:
Your canvas position id fixed
Canvas top and left properties set to 0
ctx variable is globally accessible
I am using Ariutta's svg-pan-zoom with svg.js. I have disabled the native Arriuta doubleclick functionality and have tried adding my own, which ultimately consists of a pan adjustment and an animation.
Usually this works fine, but sometimes when I load my page the doubleclick function acts strangely. According to my debugging, it looks like sometimes when my app loads, the doubleclick function I wrote is called twice for each doubleclick. This causes the animation to behave strangely, and there seems to be no consistent basis for when this issue arises. Restarting my server sometimes works, and sometimes doesn't. I pretty much just have to continue reloading my page until the issue goes away.
My initial thoughts are that maybe there is something off in the load order of my files, and sometimes things load out of order. Currently investigating this. My other thought was that maybe this has something to do with the svg.js animation library or my trying to replace the native double-click function in arriuta's plugin. Thoughts?
myApp.service('AnimatorService', function(){
this.dblClickBehavior = function(svgCanvas, zoom){
$('.node').dblclick(function(){
// get pan
pan = zoom.getPan();
// get screen width and height
var sizes = zoom.getSizes();
var centerX = (sizes.width)/2;
var centerY = (sizes.height)/2;
// get center position of svg object double clicked
var x0 = this.instance.first().attr('cx');
var y0 = this.instance.first().attr('cy');
//determine the correct pan value necessary to center the svg
panAdjustX = centerX - x0*sizes.realZoom;
panAdjustY = centerY - y0*sizes.realZoom;
//center the svg object by adjust pan
zoom.pan({'x' :centerX - x0*sizes.realZoom, 'y' : centerY - y0*sizes.realZoom});
//simple animation on the object
this.instance.first().animate().radius(centerX);
});
}
});
When it behaves correctly, the svg image centers and then grows. When it behaves incorrectly, it centers and then shrinks into nothingness.
You tagged svg.js so I will give an svg.js answer. There is a plugin svg.panZoom.js now which can be used to easily implement the functionality you want:
var canvas = SVG('container').viewbox(0,0,1000,1000)
canvas.image('https://www.zooroyal.de/magazin/wp-content/uploads/2017/05/cat-2783601_1920.jpg', 1000, 1000)
.attr('preserveAspectRatio', 'none')
canvas.on('dblclick', function(e) {
var p = this.point(e.pageX, e.pageY)
var zoomLvl = 3
// zoom into point p to zoomLvl
canvas.animate().zoom(zoomLvl, p)
})
Here is a fiddle: https://jsfiddle.net/Fuzzy/95t6oL8y/5/
When you want to be able to panZoom your svg, too. Just add a call to canvas.panZoom()
Made a 3d cube. When a button is clicked, it rotates 50 deg left or right. I want it rotate an additional 50deg further when I click the same button. How do I achieve this? Here is my code right now:
//code to rotate cube
var rotateCube = document.getElementById('cube');
var moveLeft = document.getElementById('button-one');
var moveRight = document.getElementById('button-two');
moveLeft.onclick = function() {
rotateCube.style.webkitTransform = "rotateY(-50deg)";
}
moveRight.onclick = function() {
rotateCube.style.webkitTransform = "rotateY(50deg)";
}
in full here:
http://jsfiddle.net/camlatimer/6xp2dwe7/1/
I've searched around. There are examples like this one:
http://paulrhayes.com/experiments/cube-3d/
But I'm new to programming (2 months of fiddling with javascript in my free time) and don't understand much. I thought I could complete my objective pretty easily, but I'm stuck. I don't want to use any plugins. Just want to learn to really program things on my own. Any help would be appreciated.
LcSalazar is correct in regards to handling to rotation state of your cube, but my impression is that you're also interested in animating the rotation? If so, you'll want to check out CSS animations to handle those in-between states. This question covers dynamic values in CSS keyframed animations, which might be a bit beyond your current knowledge of CSS/JS, but spend some time with it and you'll be surprised how quickly it starts making sense.
Good luck!
The problem is with your premise:
"When a button is clicked, it rotates 50 deg left or right"
Actually, when a button is clicked, you are setting the rotation to be exactly -50deg or 50deg. It's an absolute assignment, not an increment.
In order to increment (since the rotation property is assigned by a text composed value), you'd need to store the value in a way where you can control it. For example, storing it in an external variable, and use it to increment the final value.
Something like this:
See working example
//Here's where you will store the actual value
var rotationValue = 0;
moveLeft.onclick = function() {
rotationValue -= 50;
rotateCube.style.webkitTransform = "rotateY("+ rotationValue +"deg)";
}
moveRight.onclick = function() {
rotationValue += 50;
rotateCube.style.webkitTransform = "rotateY("+ rotationValue +"deg)";
}