How to use Pixi.js in a Vue.js component? - javascript

I want to add Pixi.js to one of my VueJs components, but it doesn't work. What I want to do for now is to implement one of the basic examples from the Pixi.js website.
The problem is that with the same code as the one on the website, I only see the background color on my screen.
Here is my VueJS component:
<template>
<body>
<div id='change'>
<router-link class="changepage" to='/OrdreCouches'> >Retour </router-link>
</div>
<div id="pixi"></div>
</body>
</template>
<script>
import * as PIXI from 'pixi.js'
export default {
name: 'Visualisation',
data(){
return{
app: new PIXI.Application()
}
},
methods: {
init: function() {
const app = new PIXI.Application({
width: 800, height: 600, backgroundColor: 0x1099bb, resolution: window.devicePixelRatio || 1,
});
document.body.appendChild(app.view);
const container = new PIXI.Container();
app.stage.addChild(container);
// Create a new texture
const texture = PIXI.Texture.from('./assets/blob.png');
// Create a 5x5 grid of bunnies
for (let i = 0; i < 25; i++) {
const bunny = new PIXI.Sprite(texture);
bunny.anchor.set(0.5);
bunny.x = (i % 5) * 40;
bunny.y = Math.floor(i / 5) * 40;
container.addChild(bunny);
}
// Move container to the center
container.x = app.screen.width / 2;
container.y = app.screen.height / 2;
// Center bunny sprite in local container coordinates
container.pivot.x = container.width / 2;
container.pivot.y = container.height / 2;
// Listen for animate update
app.ticker.add((delta) => {
// rotate the container!
// use delta to create frame-independent transform
container.rotation -= 0.01 * delta;
});
}
},
mounted() {
this.init();
}
}
</script>
<style>
.changepage{
position: absolute;
color: rgb(0, 0, 0);
font-size: 30px;
}
.changepage:hover{
position: absolute;
color: rgb(53, 20, 199);
font-size: 30px;
}
</style>
Could you help me with this?
Thank you!!

Related

Set game scale ratio

I'm trying to fit the game to the screen, however I'm unable to scale the stage itself. With libraries like EaselJS from CreateJS I can simply do stage.scaleX = stage.scaleY = r.
In Phaser, I want to scale not only the game, but also together a HTML div (for user interface) that is outside Phaser. As you can see, the drawn rectangle is not scaled according to the current screen size, no matter what properties I change (game.scale.scaleMode, game.scale.displayScale etc.). Is there anything I can do?
const ProjectSettings = {
backgroundColor: 0x333333,
resolution: [100, 100],
};
const SceneContainers = {
sceneContent: null,
sceneCanvas: null,
phaserGame: null,
sceneUIDiv: null,
init() {
SceneContainers.sceneContent = document.getElementById('content');
SceneContainers.phaserGame = new Phaser.Game({
width: ProjectSettings.resolution[0],
height: ProjectSettings.resolution[1],
type: Phaser.AUTO,
parent: SceneContainers.sceneContent,
backgroundColor: ProjectSettings.backgroundColor,
scene: [Preloader],
});
SceneContainers.sceneCanvas = SceneContainers.phaserGame.canvas;
SceneContainers.sceneCanvas.classList.add('scene-canvas');
SceneContainers.sceneUIDiv = document.createElement('div');
SceneContainers.sceneUIDiv.id = 'scene-ui';
SceneContainers.sceneContent.appendChild(SceneContainers.sceneUIDiv);
},
};
const SceneScaler = {
init() {
SceneContainers.phaserGame.scale.scaleMode = Phaser.Scale.ScaleModes.RESIZE;
SceneScaler.fitToScreen();
window.addEventListener('resize', e => {
SceneScaler.fitToScreen();
});
},
fitToScreen() {
const [contentW, contentH] = ProjectSettings.resolution;
const [windowW, windowH] = [innerWidth, innerHeight];
const ratio = contentW / contentH;
const windowRatio = windowW / windowH;
let scale = windowW / contentW;
if (windowRatio > ratio) {
scale = windowH / contentH;
}
//SceneContainers.sceneCanvas.width = contentW * scale;
//SceneContainers.sceneCanvas.height = contentH * scale;
SceneContainers.phaserGame.scale.resize(contentW * scale, contentH * scale);
SceneContainers.sceneUIDiv.style.transform = `scale(${scale})`;
SceneContainers.sceneContent.style.width = `${contentW * scale}px`;
SceneContainers.sceneContent.style.height = `${contentH * scale}px`;
SceneContainers.sceneUIDiv.style.width = `${contentW}px`;
SceneContainers.sceneUIDiv.style.height = `${contentH}px`;
SceneContainers.sceneContent.style.left =
SceneContainers.sceneCanvas.style.left =
SceneContainers.sceneUIDiv.style.left = `${windowW / 2 - (contentW * scale) / 2}px`;
SceneContainers.sceneContent.style.top =
SceneContainers.sceneCanvas.style.top =
SceneContainers.sceneUIDiv.style.top = `${windowH / 2 - (contentH * scale) / 2}px`;
//SceneContainers.phaserGame.scale.displayScale = new Phaser.Math.Vector2(scale, scale);
},
};
class Scene extends Phaser.Scene {
constructor(id) {
super(id);
}
init() {
this.events.on('shutdown', () => {
SceneContainers.sceneUIDiv.innerHTML = '';
});
}
}
class Preloader extends Scene {
constructor() {
super('preloader');
}
preload() {
}
create() {
this.add.rectangle(50, 50, 50, 50, 0xff6666);
}
}
class EntryPoint {
constructor() {
this.init();
}
init() {
SceneContainers.init();
SceneScaler.init();
}
}
new EntryPoint;
html, body {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
html, body {
background: #333333;
}
#content {
position: absolute;
display: inline-block;
}
.scene-canvas {
position: absolute;
}
#scene-ui {
display: inline-block;
position: absolute;
transform-origin: left top;
}
<script src="https://github.com/photonstorm/phaser/releases/download/v3.55.2/phaser.min.js"></script>
<div id="content"></div>
Also, for some reason my snippet is giving undefined for canvas.classList, so I appreciate if someone could fix that. This classList error is not happening with my project.
If you are only looking for automatic scaling, you could use the config parameter scale.mode (of the Phaser Game Object) and set it to Phaser.Scale.FIT, then everything should be scaled.
Here a very simplified demo:
If you resize the window (when you open the snipplet fullsize and change the height), you should see "the scaling"
var Preloader = {
create() {
this.add.rectangle(50, 50, 50, 50, 0xff6666);
}
};
new Phaser.Game({
width:300,
height:300,
scale: {
mode: Phaser.Scale.FIT,
},
type: Phaser.AUTO,
scene: [Preloader],
});
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>

Why some rectangles are disappearing when there is a rectangle that covers the whole area?

I'm facing a problem with css paint worklet and am wondering whether it's a browser bug or there's something that i'm doing wrong.
In a worklet i'm drawing a few rectangles. If one of them covers the whole area, others are starting to disappear when i'm changing zoom level. But when i remove the context.fillRect(0, 0, width, height) everything works like a charm.
Here's sandbox code that i've prepared to better illustrate the problem: https://codesandbox.io/s/magical-villani-py8x2
That indeed looks like a bug in Chrome "experimental" implementation, you might want to let them know on their issue tracker, since that should work.
Now, while you are not doing anything bad per se, note that if instead of the non-standard zoom we do use the transform property, then the bug would not occur:
(()=> {
if( !CSS.paintWorklet ) {
return console.error('CSS Paint API is not supported in this browser, you may have to enable it from chrome://flags/#enable-experimental-web-platform-features');
}
const worklet_script = document.querySelector('[type="paint-worklet"]').textContent;
const worklet_blob = new Blob([worklet_script], { type: 'text/javascript' });
CSS.paintWorklet.addModule(URL.createObjectURL(worklet_blob));
window.addEventListener("DOMContentLoaded", () => {
const slider = document.getElementById("slider");
slider.addEventListener("input", () => {
const el = document.querySelector(".content");
el.style.transform = `scale(${slider.value},${slider.value})`;
});
});
})();
.content {
background: paint(sandbox);
border: 1px solid black;
height: 200px;
width: 200px;
transform-origin: top left;
}
<input type="range" id="slider" min="0.5" max="4" value="1" step="0.1" />
<div class="content"></div>
<script type="paint-worklet">
class SandboxPaintWorklet {
paint(context, geometry, properties) {
const { width, height } = geometry;
// background
context.fillStyle = "#8866aa";
context.fillRect(0, 0, width, height);
context.fillStyle = "#000000";
context.beginPath();
// vertical line
context.fillRect((width * 3) / 4, 0, 1, height);
// horizontal lines
const distance = Math.ceil(height / 20);
for (let i = 0; i < 20; ++i) {
context.fillRect(0, i * distance, width / 2, 1);
}
}
}
registerPaint("sandbox", SandboxPaintWorklet);
</script>
And even with zoom, if instead of that many fillRect, if we do fill a single sub-path by using rect() instead, then that would also work.
(()=> {
if( !CSS.paintWorklet ) {
return console.error('CSS Paint API is not supported in this browser, you may have to enable it from chrome://flags/#enable-experimental-web-platform-features');
}
const worklet_script = document.querySelector('[type="paint-worklet"]').textContent;
const worklet_blob = new Blob([worklet_script], { type: 'text/javascript' });
CSS.paintWorklet.addModule(URL.createObjectURL(worklet_blob));
window.addEventListener("DOMContentLoaded", () => {
const slider = document.getElementById("slider");
slider.addEventListener("input", () => {
const el = document.querySelector(".content");
el.style.zoom = slider.value;
});
});
})();
.content {
background: paint(sandbox);
border: 1px solid black;
height: 200px;
width: 200px;
}
<input type="range" id="slider" min="0.5" max="4" value="1" step="0.1" />
<div class="content"></div>
<script type="paint-worklet">
class SandboxPaintWorklet {
paint(context, geometry, properties) {
const { width, height } = geometry;
// background
context.fillStyle = "#8866aa";
context.fillRect(0, 0, width, height);
context.fillStyle = "#000000";
context.beginPath();
// vertical line
context.rect((width * 3) / 4, 0, 1, height);
// horizontal lines
const distance = Math.ceil(height / 20);
for (let i = 0; i < 20; ++i) {
context.rect(0, i * distance, width / 2, 1);
}
context.fill();
}
}
registerPaint("sandbox", SandboxPaintWorklet);
</script>

How to create responsive background-image with liquid distortion using PIXI.JS

I am trying to replicate the same result as using CSS width: 50vw; and height: 100vh; but in Javascript. My code is not currently creating the desired effect.
const logicalWidth = window.innerWidth / 2;
const logicalHeight = window.innerHeight;
I can see there will be some issues down the line with making this responsive as it will be full-width on ipad/ mobile. What I'm thinking might be the best way to handle this is rendering the image using CSS background-image: and this way I can control width, height and background-position with media query
I tried this but it does not work
.js-canvas {
background-image: url('https://raw.githubusercontent.com/codrops/LiquidDistortion/master/img/13.jpg');
width: 50vw;
height: 100%;
background-position: center center;
}
Can anyone suggest a solution to this? Very happy to do this all with JS but not sure where to begin
// Declare all vars
let bgSprite,
displacementSprite,
displacementFilter,
pointerSprite,
pointerFilter;
// Images used
const images = [
{
name: 'bg',
url: 'https://raw.githubusercontent.com/codrops/LiquidDistortion/master/img/13.jpg'
},
{
name: 'clouds',
url: 'https://raw.githubusercontent.com/pixijs/examples/gh-pages/examples/assets/pixi-filters/displacement_map_repeat.jpg'
}
];
const logicalWidth = 1800;
const logicalHeight = 1080;
// Determine & create the PIXI App instance
const canvasEl = document.querySelector('.js-canvas');
const canvasElOptions = {
autoDensity: true,
backgroundColor: 0xFFFFFF,
resizeTo: window,
resolution: window.devicePixelRatio || 1,
view: canvasEl
};
const resizeHandler = () => {
const scaleFactor = Math.min(
window.innerWidth / logicalWidth,
window.innerHeight / logicalHeight
);
const newWidth = Math.ceil(logicalWidth * scaleFactor);
const newHeight = Math.ceil(logicalHeight * scaleFactor);
app.renderer.view.style.width = `${newWidth}px`;
app.renderer.view.style.height = `${newHeight}px`;
app.renderer.resize(newWidth, newHeight);
mainContainer.scale.set(scaleFactor);
};
let app = new PIXI.Application(canvasElOptions);
let mainContainer = new PIXI.Container();
app.loader
.add(images)
.on('progress', loadProgressHandler)
.load(setup);
app.renderer.plugins.interaction.moveWhenInside = true;
function loadProgressHandler(loader, resource) {
//Display the percentage of files currently loaded
console.log("progress: " + loader.progress + "%");
//If you gave your files names as the first argument
//of the `add` method, you can access them like this
console.log("loading: " + resource.name);
}
function setup(loader, resources){
console.log("All files loaded");
resizeHandler();
app.stage.addChild(mainContainer);
window.addEventListener('resize', resizeHandler);
bgSprite = new PIXI.Sprite(resources.bg.texture);
bgSprite.interactive = true;
displacementSprite = new PIXI.Sprite(resources.clouds.texture);
// Make sure the sprite is wrapping.
displacementSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT;
displacementFilter = new PIXI.filters.DisplacementFilter(displacementSprite);
pointerSprite = new PIXI.Sprite(resources.clouds.texture);
pointerFilter = new PIXI.filters.DisplacementFilter(pointerSprite);
displacementSprite.width = bgSprite.height;
displacementSprite.height = bgSprite.height;
pointerSprite.anchor.set(0.5);
pointerFilter.scale.x = 7;
pointerFilter.scale.y = 7;
mainContainer.addChild(bgSprite);
mainContainer.addChild(displacementSprite);
mainContainer.addChild(pointerSprite);
mainContainer.filters = [displacementFilter, pointerFilter];
pointerSprite.visible = false;
app.ticker.add((delta) => {
// Offset the sprite position to make vFilterCoord update to larger value.
// Repeat wrapping makes sure there's still pixels on the coordinates.
displacementSprite.x += 3.5 * delta;
displacementSprite.y += 3.5 * delta;
// Reset x & y to 0 when x > width to keep values from going to very huge numbers.
if (displacementSprite.x > displacementSprite.width) {
displacementSprite.x = 0;
displacementSprite.y = 0;
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.3/pixi.min.js"></script>
<canvas class="test js-canvas"></canvas>

Konva vue js text slide into stage and then stop

Hi I'm using konva js (https://konvajs.org) with vue and I'm trying to animate the text so that it slides into the screen from off the stage to a certain position, however I'm not 100% sure how this should work, I've been able to get a demo working here;
https://codesandbox.io/s/vue-konva-template-i2em3
Vue;
<v-stage ref="stage" :config="stageSize">
<v-layer ref="layer">
<v-text
ref="text1"
:config="{
text: 'Draggable Text',
x: 50,
y: 50,
draggable: true,
fill: 'black'
}"
/>
</v-layer>
</v-stage>
</template>
<script>
const width = window.innerWidth;
const height = window.innerHeight;
export default {
data() {
return {
stageSize: {
width: width,
height: height
}
};
},
methods: {
changeSize(e) {
// to() is a method of `Konva.Node` instances
e.target.to({
scaleX: Math.random() + 0.8,
scaleY: Math.random() + 0.8,
duration: 0.2
});
}
},
mounted() {
const vm = this;
const amplitude = 100;
const period = 5000;
// in ms
const centerX = vm.$refs.stage.getStage().getWidth() / 2;
const text = this.$refs.text1.getStage();
// example of Konva.Animation
const anim = new Konva.Animation(function(frame) {
text.setX(
amplitude * Math.sin((frame.time * 2 * Math.PI) / period) + centerX
);
}, text.getLayer());
anim.start();
}
};
</script>
any ideas how I can get the text to appear from outside of the stage and then stop at a certain point within the canvas?
You can just use node.to() method to animatio any Konva.Node:
mounted() {
const textNode = this.$refs.text1.getNode();
const endX = width / 2 - textNode.width() / 2;
// run the animation
textNode.to({
x: endX,
onFinish: () => {
// update the state at the end
this.textPos.x = endX;
}
})
}
Demo: https://codesandbox.io/s/vue-konva-animation-demo-lr4qw

How do I create circular hotspots with two.js?

I am trying to make a solar system model. I made it all so far using two.js. I want to make it so when the mouse is over a planet's orbit path, it'll highlight that planet's orbit, and be a link to information about that planet. I'm having trouble finding a way to do this, though.
If you don't have it, here's Two.js.
My file structure looks like this:
css
main.css
js
main.js
two.js
index.html
PS. This will not render with the "Run code snippet" feature. If you wish to see it, you must save this code and put it in the same file structure I have.
//This work was created by the minds of Sam Steele and Devin Fowler of Cryptocosm Developers.
//Cryptocosm ©2014
//cryptocosm.x10.bz
//Initiate the render context
var elem = document.getElementById('canvas');
var two = new Two({
fullscreen: true
}).appendTo(elem);
//Define our planets and their colors
var sun = two.makeCircle(0, 0, 70);
var mercury = two.makeCircle(95, 0, 7);
var venus = two.makeCircle(125, 0, 8.5);
var earth = two.makeCircle(160, 0, 11.4);
var mars = two.makeCircle(200, 0, 9.5);
var jupiter = two.makeCircle(260, 0, 28);
// For Saturn we're going to do something special in order to get the rings
var saturnBody = two.makeCircle(320, 0, 24);
var saturnRings = two.makeCurve(296, 0, 290, 10, 322, 10, 350, -8, 342, -10, true);
saturnRings.rotation = 4.5;
var saturn = two.makeGroup(saturnBody, saturnRings);
var uranus = two.makeCircle(460, 0, 18);
var neptune = two.makeCircle(540, 0, 16);
var asteroid = two.makeCircle(0, 320, 3);
//Try to make some stars
var width = window.innerWidth;
var height = window.innerHeight;
var star;
for (i = 0; i < 200; i++) {
var randX = Math.round(Math.random() * width);
var randY = Math.round(Math.random() * height);
star = two.makeCircle(randX, randY, 2);
}
//Set the color of the planets
sun.fill = '#F7CA18';
mercury.fill = '#9E9E9E';
venus.fill = '#795548';
earth.fill = '#2196F3';
mars.fill = '#FF7043';
jupiter.fill = '#E67E22';
saturnBody.fill = '#A1887F';
saturnRings.stroke = "#F5F5F5";
saturnRings.linewidth = 7;
saturnRings.noFill();
saturn.translation.set(20, 0);
uranus.fill = '#4DB6AC';
neptune.fill = '#3F51B5';
star.fill = '#FAFAFA';
asteroid.fill = '#FAFAFA';
//Group the planets
var Mercury = two.makeGroup(mercury);
var Venus = two.makeGroup(venus);
var Earth = two.makeGroup(earth);
var Mars = two.makeGroup(mars);
var Jupiter = two.makeGroup(jupiter);
var Saturn = two.makeGroup(saturn);
var Uranus = two.makeGroup(uranus);
var Neptune = two.makeGroup(neptune);
var planets = two.makeGroup(sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune);
//Center everything in the center of the element
planets.translation.set(two.width / 2, two.height / 2);
Mercury.rotation = 4;
Venus.rotation = 2.5;
Earth.rotation = 5.5;
Mars.rotation = 1;
Jupiter.rotation = 4.2;
Saturn.rotation = 2.5;
Uranus.rotation = 5.75;
Neptune.rotation = .5;
var counter = document.getElementById('counter');
var count = 0;
var yearsPassed = 0;
// Bind a function to scale and rotate the group to the animation loop.
two.bind('update', function (frameCount) {
//Set the "ZOOM" of the system
planets.scale = .8;
//Rotate all the planets
Mercury.rotation += .01607;
Venus.rotation += .01174;
Earth.rotation += .01;
/* //Earth year counter (not currently accurate at all)
count++;
if (count % 550 == 0) {
yearsPassed++;
counter.innerHTML = "An estimated " + yearsPassed + " Earth years passed";
}; */
Mars.rotation += .00802;
Jupiter.rotation += .00434;
Saturn.rotation += .00323;
Uranus.rotation += .00228;
Neptune.rotation += .00182;
//Rotate Saturn's rings so that it doesn't look dumb
saturnRings.rotation -= .00323;
}).play(); // Finally, start the animation loop
#font-face {
font-family: Roboto-Thin;
font-style: normal;
src: url(Roboto/Roboto-Thin.ttf);
}
html {
background-color: #212121;
}
body {
color: white;
font-family: Roboto-Thin;
}
#counter {
background-color: rgba(0, 0, 0, .4);
width: auto;
height: auto;
font-size: 34px;
float: left;
position: fixed;
padding: 10px;
}
#canvas {}
<html>
<head>
<title>The Solar System</title>
<link href="css/main.css" type="text/css" rel="stylesheet">
<script src="js/two.js"></script>
</head>
<body>
<div id="counter"></div>
<div id="canvas">
</div>
<script src="js/main.js"></script>
</body>
</html>
This is one way to achieve that effect:
This will only work for the svg renderer, but you can add event listeners on mouseover and mouseout as well as touchmove events like so:
// ... After you've created all the planets ...
// This command will create all the dom elements
// which you can bind events to.
two.update();
var highlight = function() { sun.fill = 'red'; };
var ignore = function() { sun.fill = 'yellow'; };
sun._renderer.elem.addEventListener('mousemove', highlight, false);
sun._renderer.elem.addEventListener('mouseout', ignore, false);
There is also an example of how to achieve this here.

Categories

Resources