How do I move Phaser.Game to the center of a browser? - javascript

I'm new to JS/phaser and just create a Phaser.Game with
var game = new Phaser.Game(600, 490);
The game is created top left but I would like to have it placed in the center of a browser.
I checked the API and nothing looks relevant:
new Game(width, height, renderer, parent, state, transparent, antialias, physicsConfig)
Could someone tell me how do I do so?

Using Laravel 8 and phaser#3.24.1
The solution found here worked for me. The other answers provided in this thread did not (but did point me in the correct direction).
canvas {
display : block;
margin : auto;
}

Thanks to this link provided by #FedericoklezCulloca.
add
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
game.scale.refresh();
to function update and the Phaser.Game will be in the middle.

In this example the game will be centered but the logo is at 0,0
var game = new Phaser.Game(640, 480, Phaser.AUTO, 'phaser-example', { preload: preload, create: create });
function preload() {
game.load.crossOrigin = "Anonymous";
game.load.image('logo', 'https://cdn.rawgit.com/photonstorm/phaser-examples/master/examples/assets/sprites/phaser2.png');
}
function create() {
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
var logo = game.add.sprite(0, 0, 'logo');
}
* {
margin: 0;
padding: 0;
}
<meta name="viewport" content="initial-scale=1 user-scalable=no" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser-ce/2.11.0/phaser.js"></script>

Use game config options to work with size and scale
const gameConfig: Phaser.Types.Core.GameConfig = {
parent: 'game',
scale: {
mode: Phaser.Scale.RESIZE, // you can find another types in Phaser.Scale.ScaleModeType: RESIZE | FIT | ENVELOP ...
autoCenter: Phaser.Scale.CENTER_BOTH,
},
...yourRest
}
Also I recommend to add css to your :
#id {
width: 100vw; // you can skip it
height: 100vh; // you can skip it
display: flex;
align-items: center;
justify-content: center;
canvas {
padding: 0 !important;
margin: 0 !important;
}
}

Related

How do I move an element with mouse event movement without changing its size in Javascript?

I am developing a custom element representing a window in an operating system. Like a window, it should be moveable/draggable. I can successfully move the window with this code:
moveVertically(movement) {
const boundingClientRect = this.getBoundingClientRect()
this.setTop(boundingClientRect.top + movement)
this.setBottom(boundingClientRect.bottom + movement)
}
moveHorizontally(movement) {
const boundingClientRect = this.getBoundingClientRect()
this.setLeft(boundingClientRect.left + movement)
this.setRight(boundingClientRect.right + movement)
}
The argument movement is mouse event variable movementY and movementX, respectively. The problem is that, if I move the window to quickly, it resizes as well.
How do I move the window without resizing it?
Edit: With this code:
moveVertically(movement) {
const boundingClientRect = this.getBoundingClientRect()
this.style.transform =
`translateY(${boundingClientRect.top + movement}px)`
}
moveHorizontally(movement) {
const boundingClientRect = this.getBoundingClientRect()
this.style.transform =
`translateX(${boundingClientRect.left + movement}px)`
}
the window kind of just moves up and down, when I try to move it. If I comment one of the methods out, it works perfectly, but I can't get both to work at the same time.
I haven't changed my resizing method yet, but that probably doesn't matter.
The reason why your second attempt doesn't work is because you are overwriting the CSS transform. You will need to persist the values on either axis: this can be done by using CSS custom properties for example.
The example below is an adapted example based on your code. The --translate-x and --translate-y are CSS custom properties that can be adjusted individually and they are simply being assigned to the CSS transform property using transform: translate(var(--translate-x, 0), var(--translate-y, 0)); (the fallback value is set to 0):
const stage = document.querySelector('#stage');
const el = document.querySelector('#el');
function moveVertically(movement) {
el.style.setProperty('--translate-y', `${movement}px`);
}
function moveHorizontally(movement) {
el.style.setProperty('--translate-x', `${movement}px`);
}
stage.addEventListener('mousemove', e => {
moveHorizontally(e.clientX);
moveVertically(e.clientY);
});
body {
margin: 0;
padding: 0;
}
#stage {
position: relative;
width: 100vw;
height: 100vh;
}
#el {
position: absolute;
width: 100px;
height: 100px;
background-color: steelblue;
transform: translate(var(--translate-x, 0), var(--translate-y, 0));
}
<div id="stage">
<div id="el"></div>
</div>
Alternatively you can also store the XY coordinates into a variable:
const stage = document.querySelector('#stage');
const el = document.querySelector('#el');
const elCoords = { x: 0, y: 0 };
function moveVertically(movement) {
elCoords.y = movement;
}
function moveHorizontally(movement) {
elCoords.x = movement;
}
stage.addEventListener('mousemove', e => {
moveHorizontally(e.clientX);
moveVertically(e.clientY);
el.style.transform = `translate(${elCoords.x}px, ${elCoords.y}px)`;
});
body {
margin: 0;
padding: 0;
}
#stage {
position: relative;
width: 100vw;
height: 100vh;
}
#el {
position: absolute;
width: 100px;
height: 100px;
background-color: steelblue;
}
<div id="stage">
<div id="el"></div>
</div>

How to convert a javascript animation to video on the server-side using nodejs?

I have a app where a user can create animations , I want to be able to convert these animations to video on server side, so user can save and share them eg YouTube, etc
Here is what I have so far , animation created using create js and ffmpegserver.js.
ffmpegserver.js.
This is a simple node server and library that sends canvas frames to the server and uses FFmpeg to compress the video. It can be used standalone or with CCapture.js
Test3.html
<!DOCTYPE html>
<html>
<head>
<title>TweenJS: Simple Tween Demo</title>
<style>
canvas {
border: 1px solid #08bf31;
justify-content: center;
display: flex;
align-items: center;
margin: 0px auto;
margin-bottom: 40px;
}
a {
width: 150px;
height: 45px;
background: red;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
border-radius: 300px;
color: white;
}
#container{
flex-direction: column;
justify-content: center;
display: flex;
align-items: center;
margin: 0px auto;
}
#progress{
margin: 30px;
}
#preview{
margin: 40px;
width: 150px;
height: 45px;
background: deepskyblue;
color: white;
border: none;
border-radius: 300px;
}
</style>
</head>
<body onload="init();">
<div>
<div id="container">
<h1>Simple Tween Demo</h1>
<canvas id="testCanvas" width="500" height="400"></canvas>
<div id="progress"></div>
</div>
</div>
<script src="http://localhost:8081/ffmpegserver/CCapture.js"></script>
<script src="http://localhost:8081/ffmpegserver/ffmpegserver.js"></script>
<script src="https://code.createjs.com/1.0.0/createjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.2.0/Tween.js"></script>
<script src="test3.js"></script>
</body>
</html>
Test3.js
/* eslint-disable eol-last */
/* eslint-disable no-undef */
/* eslint-disable quotes */
var canvas, stage;
function init() {
var framesPerSecond = 60;
var numFrames = framesPerSecond * 5; // a 5 second 60fps video
var frameNum = 0;
var progressElem = document.getElementById("progress");
var progressNode = document.createTextNode("");
progressElem.appendChild(progressNode);
function onProgress(progress) {
progressNode.nodeValue = (progress * 100).toFixed(1) + "%";
}
function showVideoLink(url, size) {
size = size ? (" [size: " + (size / 1024 / 1024).toFixed(1) + "meg]") : " [unknown size]";
var a = document.createElement("a");
a.href = url;
var filename = url;
var slashNdx = filename.lastIndexOf("/");
if (slashNdx >= 0) {
filename = filename.substr(slashNdx + 1);
}
a.download = filename;
a.appendChild(document.createTextNode("Download"));
var container = document.getElementById("container").insertBefore(a, progressElem);
}
var capturer = new CCapture( {
format: 'ffmpegserver',
//workersPath: "3rdparty/",
//format: 'gif',
//verbose: true,
framerate: framesPerSecond,
onProgress: onProgress,
//extension: ".mp4",
//codec: "libx264",
} );
capturer.start();
canvas = document.getElementById("testCanvas");
stage = new createjs.Stage(canvas);
var ball = new createjs.Shape();
ball.graphics.setStrokeStyle(5, 'round', 'round');
// eslint-disable-next-line quotes
ball.graphics.beginStroke('#000000');
ball.graphics.beginFill("#FF0000").drawCircle(0, 0, 50);
ball.graphics.setStrokeStyle(1, 'round', 'round');
ball.graphics.beginStroke('#000000');
ball.graphics.moveTo(0, 0);
ball.graphics.lineTo(0, 50);
ball.graphics.endStroke();
ball.x = 200;
ball.y = -50;
createjs.Tween.get(ball, {loop: -1})
.to({x: ball.x, y: canvas.height - 55, rotation: -360}, 1500, createjs.Ease.bounceOut)
.wait(1000)
.to({x: canvas.width - 55, rotation: 360}, 2500, createjs.Ease.bounceOut)
.wait(1000)
.to({scaleX: 2, scaleY: 2}, 2500, createjs.Ease.quadOut)
.wait(1000)
stage.addChild(ball);
createjs.Ticker.addEventListener("tick", stage);
function render() {
requestAnimationFrame(render);
capturer.capture( canvas );
++frameNum;
if (frameNum < numFrames) {
progressNode.nodeValue = "rendered frame# " + frameNum + " of " + numFrames;
} else if (frameNum === numFrames) {
capturer.stop();
capturer.save(showVideoLink);
}
}
render();
}
Everything works fine, you can test it yourself if you want by cloning the repo.
Right now animation rendering happens in client side, I would like this animation rendering to happen in the backend side
What do I need to change to make this animation rendering in backend server side using Nodejs? any help or suggestions will be appreciated.
you will need to build an Rest Api with node.js and express ( or any kind of server api handeler)
. once you have got the outpot animation you will have to make an ajax post method request to the node.js server and let the server handle the CCapture.js ..
the main page in the serverwill look somthing like this .
var app = require('express')();
var bodyParser = require('body-parser');
var upload = multer(); // for parsing multipart/form-data
app.post('/profile', function (req, res, next) {
console.log(req.body);
res.json(req.body);
});
check also NPM for more packages for node.js

Making a fix scaled timeline in HTML/CSS/JS

Sorry, this is going to be a little long...
A bit of context
As part of a larger project I'm trying to make a project timeline to include in a webpage used to remote control a music making program (called Reaper for those who are interested). I'm trying to get it to display the current play position, the project markers, and project regions. These are all served straight from the program's API, no problem getting the info. For starters I'm just trying to display the project markers, however I've been pulling my hair out for over a week now trying to get it to work.
Here's a quick screencap from inside the software to illustrate what I'm trying to emulate: Reaper ruler screencap
Normally I would use a progress bar for something like this, or one of the thousands of examples from the web, however I have no way of knowing the length of the project as the software doesn't limit it. As a result I fell back onto using a fixed scale of 10px per bar. Kind of arbitrary, I chose that as it's the optimal for a 5 minute song at 120 bpm. Not too worried about looks for the moment, I just want to get it to work haha.
The problem I have (code is included at the bottom) is that because I'm using absolute positioning for the markers in order to align them all from the left of the screen, they are pulled from the document flow and so I can't wrap them in the parent div. In the end I intend setting the parent div to an 80% width with a scrollbar to see the rest of the markers, so obviously I'm doing it wrong. However I can't seem to find any coded snippets of anything similar to what I'm trying to achieve.
So here is the actual question:
What sort of display/position/float CSS should I be using to do this instead of position: absolute and float: left? If I need JS to do it, then how to I go about it?
Thanks for any help you can bring me, be it actual code or just a nudge in the right direction!
Here's my (relevant) code:
index.html
<html>
<body>
<div id="timeline">
<div id="labels"></div>
<div id="markers"></div>
</div>
</body>
</html>
script.js:
// hardcoded for debugging purposes
// See section below about the API for info about how I get this data
var markers = [
{label: "Start", pos: "20.00000000000000"},
{label: "First", pos: "50.00000000000000"},
{label: "Second", pos: "200.00000000000000"},
{label: "Last", pos: "576.845412000000000"}
];
function draw_markers(marker_list) {
var label_html = "";
var marker_html = "";
$.each(marker_list, function(index, obj) {
var label = obj.label;
var offset = parseFloat(obj.pos) * 7; // obj.pos is mesured in bars, not px
label_html = label_html +
"<span class='label' style='margin-left:"+offset+"px'>" +
label + "</span>";
marker_html = marker_html +
"<span class='marker' style='margin-left:"+offset+"px'>|</span>";
});
document.getElementById("labels").innerHTML = label_html;
document.getElementById("markers").innerHTML = marker_html;
}
draw_markers(markers);
style.css:
html, body {
background: #eeeeee;
}
#timeline {
height: 4em;
width: 100%;
background-color: #9E9E9E;
}
#labels {
border-bottom: 1px solid black;
height: 50%;
width: 100%;
}
#markers {
height: 50%;
width: 100%;
}
.label {
position: absolute;
float: left;
}
.marker {
position: absolute;
float: left;
}
About the API
We're given a bunch of functions that poll the server at regular intervals and parse the (cleartext) responses. A typical response looks something like this:
MARKERLIST_BEGINMARKER_LIST
MARKER \t label \t ID \t position
...
MARKER_LIST_END
TRANSPORT \t playstate \t position_seconds \t isRepeatOn \t position_string \t position_string_beats
...
Using JS I split each line and use a switch statement to figure out what to do with each line. I then build up a global array containing all the marker in the project with just the info I need.
Alternatively you could use <canvas> to draw the timeline from Javascript (this is what I use for Song Switcher's web interface). Also you can get the project length using the GetProjectLength API function (for example, by calling a script to put the length into a temporary extstate then reading it from the web interface).
function Timeline(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.length = 0;
this.markers = [];
}
Timeline.prototype.resize = function() {
this.canvas.width = this.canvas.clientWidth;
this.canvas.height = this.canvas.clientHeight;
this.scale = this.length / this.canvas.width;
}
Timeline.prototype.update = function() {
this.resize();
this.ctx.fillStyle = '#414141';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.textBaseline = 'hanging';
for(var marker of this.markers)
this.drawMarker(marker);
}
Timeline.prototype.drawMarker = function(marker) {
const MARKER_WIDTH = 2;
const FONT_SIZE = 14;
const PADDING = MARKER_WIDTH * 2;
var xpos = this.timeToPx(marker.pos);
this.ctx.strokeStyle = this.ctx.fillStyle = 'red';
this.ctx.lineWidth = MARKER_WIDTH;
this.ctx.beginPath();
this.ctx.moveTo(xpos, 0);
this.ctx.lineTo(xpos, this.canvas.height);
this.ctx.stroke();
if(marker.name.length > 0) {
this.ctx.font = `bold ${FONT_SIZE}px sans-serif`;
var boxWidth = this.ctx.measureText(marker.name).width + PADDING;
this.ctx.fillRect(xpos, 0, boxWidth, FONT_SIZE + PADDING);
this.ctx.fillStyle = 'white';
this.ctx.fillText(marker.name, xpos + MARKER_WIDTH, PADDING);
}
}
Timeline.prototype.timeToPx = function(time) {
return time / this.scale;
}
var timeline = new Timeline(document.getElementById('timeline'));
timeline.length = 30; // TODO: Fetch using GetProjectLength
timeline.markers = [
{pos: 3, name: "Hello"},
{pos: 15, name: "World!"},
{pos: 29, name: ""},
];
timeline.update();
window.addEventListener('resize', timeline.update.bind(timeline));
#timeline {
height: 50px;
line-height: 50px;
image-rendering: pixelated;
width: 100%;
}
<canvas id="timeline"></canvas>
you can use divs as display: inline-block and set their width as percentages of deltas of the overlaping absolute timeline positions:
function draw_markers(marker_list) {
var label_html = "";
var marker_html = "";
var total = null;
var prev = 0;
$.each(marker_list, function(index, obj) {
var delta = parseFloat(obj.pos) - prev;
obj.delta = delta;
prev += parseFloat(obj.pos);
total += delta;
})
$.each(marker_list, function(index, obj) {
var label = obj.label;
var offset = parseFloat(obj.delta) / (total / 100); // obj.pos is mesured in bars, not px
label_html = label_html +
"<div class='label' style='width:"+offset+"%'>" +
label + "</div>";
marker_html = marker_html +
"<div class='marker' style='width:"+offset+"%'>|</div>";
});
document.getElementById("labels").innerHTML = label_html;
document.getElementById("markers").innerHTML = marker_html;
}
draw_markers(markers);
css:
html, body {
background: #eeeeee;
}
#timeline {
height: 4em;
width: 100%;
background-color: #9E9E9E;
}
#labels {
border-bottom: 1px solid black;
height: 50%;
width: 100%;
}
#markers {
height: 50%;
width: 100%;
}
.label {
position: relative;
display: inline-block;
}
.marker {
position: relative;
display: inline-block;
}

How to resize Phaser's Canvas without changing the pixel value?

I`m looking for a way to sort of zoom in/zoom out on my Phaser app depending on the screen size while keeping the ratio (and not altering the canvas size pixelwise as shown on the sketch), I tried so many snippets but everybody is sort of looking for something else, this is what I'm looking for(also, the code below where the screen gets "full screened" works on desktop but not on mobile):
var game = new Phaser.Game(1100,600, Phaser.Canvas,"gameDiv");
var mainState = {
init: function () {
game.renderer.renderSession.roundPixels = true;
game.physics.startSystem(Phaser.Physics.ARCADE);
game.physics.arcade.gravity.y = 800;
game.physics.arcade.gravity.x = -10850;
},
preload: function(){
//Loads background imagery
game.load.image(`background`, "assets/background_1877_600.png");
},
create: function(){
// function to scale up the game to full screen
// function to scale up the game to full screen
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
game.scale.fullScreenScaleMode = Phaser.ScaleManager.SHOW_ALL;
game.input.onDown.add(gofull, this);
function gofull() {
if (game.scale.isFullScreen)
{
//game.scale.stopFullScreen();
}
else
{
game.scale.startFullScreen(true);
}
}
background = game.add.tileSprite(0,0,1877,600,`background`);
},
update: function(){
background.tilePosition.x -= 0.25;
}
}
game.state.add(`mainState`,mainState);
game.state.start(`mainState`);
<html>
<head>
<title>Agame</title>
<script type="text/javascript" src="phaser.min.js"></script>
<script type="text/javascript" src="main.js"></script>
<style>
html, body{
overflow: hidden;
}
</style>
</head>
<body>
</body>
</html>
If you have any idea on how I could achieve this, let me know
Can you do something like this at the start.
var x = 1100;
var y = 600;
// window.onresize = function(event) {
// }
var w = window.screen.width;
if(w > 900){
//ok
}
else if(w > 600){
x = 600;
y = 400;
}
else {
x = 300;
y = 100;
}
var game = new Phaser.Game(x,y, Phaser.Canvas,"gameDiv");
This will only work when you load a new device but you can add screen change event to resize while screen change its up to you.
I guess the best idea would be like:
html, body{
width: 100vw;
width: 100%; /*FallBack Width */
height: 100vh;
height: 100%; /*Same Here*/
}
.required-element{
font-size: 10vh; /*Or required */
}
/*And this will change according to the screen size
But, be sure add viewport to the html meta tag. */

Selecting a div that are overlaying

I have side tabs that are overlaying. I want to be able to click one and do something with it, but I am having trouble getting my event handlers to register correct div.
<div class="tabs">
<div class="blueTab">
<div class="blueTab__container">
</div>
</div>
<div class="brownTab">
<div class="brownTab__container">
</div>
</div>
</div>
.tabs {
position: relative;
margin-left: 853px;
}
.brownTab {
position: absolute;
.brownTab__container {
background-image: url(https://i.imgur.com/Fd49HkH.png) !important;
background-repeat: no-repeat !important;
width: 400px;
height: 853px;
}
}
.blueTab {
position: absolute;
.blueTab__container {
background-image: url(https://i.imgur.com/F5qg6xo.png) !important;
background-repeat: no-repeat !important;
width: 400px;
height: 873px;
}
}
let brownTabElement = document.getElementsByClassName('brownTab')[0]
let blueTabElement = document.getElementsByClassName('blueTab')[0]
brownTabElement.addEventListener('click', brownTabHandler, false)
blueTabElement.addEventListener('click', blueTabHandler, false)
function brownTabHandler() {
alert('brownTab')
}
function blueTabHandler() {
alert('blueTab')
}
When ever I click both the blue or brown tab, only the event handler for the browntab gets called. How can I fix this?
https://jsfiddle.net/Le80rvL0/3/
Your problem is that, even though you can see both tabs (because their backgrounds are partially transparent), the .brownTab__container element is overlapping the .blueTab__container, as they are in the exact same position, so you always click on that one. You can see that using the developer tools' inspector.
One solution to your problem would be to actually create different, non-overlapping elements that look like tabs. Maybe something like this or like this.
Another solution could be to use a single HTML element with a single background image of all the tabs, get the color of the clicked pixel and use it to distinguish the clicked tab. Something like this:
const message = document.getElementById('message');
// Get the tabs element:
const tabs = document.getElementById('tabs');
// Get its computed styles:
const style = window.getComputedStyle(tabs);
// Extract the background-image's url:
const backgroundImage = style.getPropertyValue('background-image');
const url = backgroundImage.substring(5, backgroundImage.length - 2);
// Create an image with that url:
const img = document.createElement('IMG');
img.src = url;
// Create a canvas with the original size of the image:
const canvas = document.createElement('CANVAS');
const width = canvas.width = 1;
const height = canvas.height = 123;
// Draw that image on it:
canvas.getContext('2d').drawImage(img, 0, 0, width, height);
// Listen for click events:
document.getElementById('tabs').addEventListener('click', (e) => {
// Get clicked pixel's RGBA value, taking into account the image on the tabs element is
// repeated, while the one on the canvas it's not:
const rgba = canvas.getContext('2d').getImageData(e.offsetX % width, e.offsetY % height, 1, 1).data;
// Set color thresholds for each tab (as in your images the colors are not uniform as
// they are here:
if (rgba[2] > 200) {
message.innerText = 'You clicked the blue tab.';
} else if (rgba[2] < 150 && rgba[1] > 50) {
message.innerText = 'You clicked the brown tab.';
} else if (rgba[1] > 200) {
message.innerText = 'You clicked the gold tab.';
} else if (rgba[1] < 50) {
message.innerText = 'You clicked the purple tab.';
} else {
message.innerText = 'Unknown tab clicked.';
}
});
body {
position: relative;
margin: 0;
height: 800px;
}
#message {
position: fixed;
top: 0;
left: 0;
right: 90px;
padding: 16px;
font-size: 32px;
}
#tabs {
position: absolute;
width: 90px;
height: 100%;
top: 0;
right: 0;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAB7CAYAAAC1rOouAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAqSURBVChTYzAOPfN/kBJnGtIGK/H+yYbBSpzRBjkSRNzUTkfmDhyR9h8AMPtPIMUTD3YAAAAASUVORK5CYII=);
}
<div id="message"></div>
<div id="tabs"></div>
Keep in mind that with the first approach it will be way easier to add other effects and features like hover/active/focus styles, add/remove tabs, move tabs, drag tabs...

Categories

Resources