Phaser 3: Finish loading json before Scene.preload() gets called - phaser-framework

I want to describe my scenes in a JSON file, and then preload images etc. according to the contents of that JSON file. So the content of the JSON file needs to have been fully loaded before entering preload. I don't know how to do this. I've created a minimal, reproducible jsfiddle that logs preload: undefined when prepreload = true.
For prepreload = false I get create: [object Object].
var prepreload = true
var config = { scene: { init: init, preload: preload, create: create } }
var game = new Phaser.Game(config)
function init(config) {
if (prepreload) {
this.load.json('scenedata', 'scene.json');
this.load.start();
}
}
function preload () {
if (prepreload)
console.log(this.cache.json.get("scenedata"));
else
this.load.json('scenedata', 'scene.json');
}
function create () {
if (!prepreload)
console.log(this.cache.json.get("scenedata"));
}
Any idea how to preload images according to the contents of a JSON file - ideally all inside the Scene class, rather than doing it externally and passing it into the init method or similar.

SettingsConfig can be used for that - the files listed under pack will already have been loaded when entering the init method.
Here's how it can be done (Phaser 3.55.2):
var config = {
scene: {
init: init,
preload: preload,
create: create,
pack: {
"files": [
{ type: 'json', key: 'scene', url: 'scene.json' }
}
}
}
}
var game = new Phaser.Game(config)
Here's a slightly different variant, using TypeScript:
export class TestScene extends Phaser.Scene {
constructor() {
super({ pack: {
"files": [ { type: 'json', key: 'scene', url: 'scene.json' }

Related

Vite plugin for SvelteKit: Generated files aren't added to the build output

I am currently working on another plugin, that should in the end generate the webmanifest and all images and splash screens needed for a PWA (minus the service worker). I am planning on making this a plugin for vite (rollup), with a special focus on sveltekit, because that's where I plan on using it.
I currently have this setup as a package that exports both mjs and cjs, and should for all I know have a working version to test with. Sadly, the output emitted using this.emitFiles doesn't appear in the build output, even though prior function returns an assetId that resolves to a URL.
Code
index.ts
import { Plugin } from 'vite'
import { PluginOptions } from './types.js'
import { readFileSync } from 'fs'
import { generateResizedWebpIcon, generateResizedJpegIcon } from './utils.js';
export default (options: PluginOptions): Plugin => {
const iconResolutions = [16, 48, 128, 512]
return {
name: 'vite-plugin-pwa',
async transformIndexHtml() {
// add images and manifest to build output
// generate icons and emit them, store the urls
const icon = readFileSync(options.image.src)
let icons = await Promise.all(iconResolutions.map(async res => {
const resolveID = this.emitFile({
type: 'asset',
name: `icon-${res}x${res}.webp`,
source: await generateResizedWebpIcon({...})
})
return {
type: 'image/webp',
sizes: `${res}x${res}`,
src: this.getFileName(resolveID)
}
}, this))
if (options.image.output?.jpeg) {
icons.push(...await Promise.all(iconResolutions.map(async res => {
const resolveID = this.emitFile({
type: 'asset',
name: `icon-${res}x${res}.jpeg`,
source: await generateResizedJpegIcon({...})
})
return {
type: 'image/jpeg',
sizes: `${res}x${res}`,
src: this.getFileName(resolveID)
}
}, this)))
}
const packageInfo = JSON.parse(readFileSync('package.json').toString())
const manifest = {
name: packageInfo.name || 'name',
description: packageInfo.description || 'description',
...options.manifest || {},
icons
};
const manifestUrl = this.getFileName(
this.emitFile({
type: 'asset',
name: 'manifest.json',
source: Buffer.from(JSON.stringify({
manifest
}))
})
)
// generate manifest with icons, save the url
// generate apple splashes and emit them, save the urls
// add links to manifest and apple meta tags
return [
{
tag: 'link',
attrs: {
rel: 'manifest',
href: manifestUrl
},
injectTo: 'head'
}
]
},
}
}
In this example, the <link rel="manifest" href="_app/manifest.webmanifest"> turns up in the html and chrome tries to fetch it. But the server returns a 404 Not Found code. It appears vite emits the file, but it is somehow overwritten by the sveltekit build process?
Does anyone know how to make this emit a file that also turns up in the final build output?

Lottie Animation in fabricjs canvas

Is it possible to load the Lottie animation in fabricjs canvas
I have tried the following samples
bodymovin.loadAnimation({
wrapper: animateElement, // div element
loop: true,
animType: 'canvas', // fabricjs canvas
animationData: dataValue, // AE json
rendererSettings: {
scaleMode: 'noScale',
clearCanvas: true,
progressiveLoad: false,
hideOnTransparent: true,
}
});
canvas.add(bodymovin);
canvas.renderAll();
I cant able to add the animation in the fabric js canvas. if any one overcome this issue kindly do comments on it
I might be late to answer this, but for anyone else looking, this pen could give you some pointers: https://codepen.io/shkaper/pen/oEKEgG
The idea here, first of all, is to extend fabric.Image class overriding its internal render method to render the contents of an arbitrary canvas that you yourself provide:
fabric.AEAnimation = fabric.util.createClass(fabric.Image, {
drawCacheOnCanvas: function(ctx) {
ctx.drawImage(this._AECanvas, -this.width / 2, -this.height / 2);
},
})
You can make this canvas a constructor argument, e.g.
initialize: function (AECanvas, options) {
options = options || {}
this.callSuper('initialize', AECanvas, options)
this._AECanvas = AECanvas
},
Then you'll just need to use lottie's canvas renderer to draw animation on a canvas and pass it to your new fabric.AEAnimation object.
I would assume so, by combining your code with something similar to https://itnext.io/video-element-serialization-and-deserialization-of-canvas-fc5dbf47666d. Depending on your scenario you might be able to get away with using something like http://fabricjs.com/interaction-with-objects-outside-canvas
If of any help, I've created this Lottie class with the support of exporting toObject/JSON
import { fabric } from 'fabric'
import lottie from 'lottie-web'
const Lottie = fabric.util.createClass(fabric.Image, {
type: 'lottie',
lockRotation: true,
lockSkewingX: true,
lockSkewingY: true,
srcFromAttribute: false,
initialize: function (path, options) {
if (!options.width) options.width = 480
if (!options.height) options.height = 480
this.path = path
this.tmpCanvasEl = fabric.util.createCanvasElement()
this.tmpCanvasEl.width = options.width
this.tmpCanvasEl.height = options.height
this.lottieItem = lottie.loadAnimation({
renderer: 'canvas',
loop: true,
autoplay: true,
path,
rendererSettings: {
context: this.tmpCanvasEl.getContext('2d'),
preserveAspectRatio: 'xMidYMid meet',
},
})
// this.lottieItem.addEventListener('DOMLoaded', () => {
// console.log('DOMLoaded')
// })
this.lottieItem.addEventListener('enterFrame', (e) => {
this.canvas?.requestRenderAll()
})
this.callSuper('initialize', this.tmpCanvasEl, options)
},
play: function () {
this.lottieItem.play()
},
stop: function () {
this.lottieItem.stop()
},
getSrc: function () {
return this.path
},
})
Lottie.fromObject = function (_object, callback) {
const object = fabric.util.object.clone(_object)
fabric.Image.prototype._initFilters.call(object, object.filters, function (filters) {
object.filters = filters || []
fabric.Image.prototype._initFilters.call(object, [object.resizeFilter], function (resizeFilters) {
object.resizeFilter = resizeFilters[0]
fabric.util.enlivenObjects([object.clipPath], function (enlivedProps) {
object.clipPath = enlivedProps[0]
const fabricLottie = new fabric.Lottie(object.src, object)
callback(fabricLottie, false)
})
})
})
}
Lottie.async = true
export default Lottie
To create Lottie element just pass JSON
const fabricImage = new fabric.Lottie('https://assets5.lottiefiles.com/private_files/lf30_rttpmsbc.json', {
scaleX: 0.5,
})
canvas.add(fabricImage)

Magento2 Override existing js component

I want to override the existing magento2 JS Component in my theme for some more customization.
Magento_Checkout/js/view/minicart.js
Above JS component i want to override and i want to add some more operation on the remove button event.
You can try "map" of require js. I used this and working for me. following is the requirejs-config.js inside my theme.
var config = {
map: {
'*': {
'Magento_Checkout/js/view/minicart':'js/custom/minicart'
}
}
};
Modified minicart.js file is placed inside "web/js/custom" folder inside my theme.
Just Go to your theme Override Magento_Checkout there, then under web folder make path as same as core module then add your js file & do required changes. It will reflect on frontend.
You can also extend an existing Magento JS without overwriting the whole file in your module add the require-config.js
app/code/MyVendor/MyModule/view/frontend/requirejs-config.js
var config = {
config: {
mixins: {
'Magento_Checkout/js/view/minicart': {
'MyVendor_MyModule/js/minicart': true
}
}
}
};
Then add the minicart.js
app/code/MyVendor/MyModule/view/frontend/web/js/minicart.js
define([], function () {
'use strict';
return function (Component) {
return Component.extend({
/**
* #override
*/
initialize: function () {
var self = this;
return this._super();
},
MyCustomFunction: function () {
return "my function";
}
});
}
});
define(['jquery'],function ($) {
'use strict';
var mixin = {
/**
*
* #param {Column} elem
*/
initSidebar: function () {
var sidebarInitialized = false, miniCart;
miniCart = $('[data-block=\'minicart\']');
if (miniCart.data('mageSidebar')) {
miniCart.sidebar('update');
}
if (!$('[data-role=product-item]').length) {
return false;
}
miniCart.trigger('contentUpdated');
if (sidebarInitialized) {
return false;
}
sidebarInitialized = true;
miniCart.sidebar({
'targetElement': 'div.block.block-minicart',
'url': {
'checkout': window.checkout.checkoutUrl,
'update': window.checkout.updateItemQtyUrl,
'remove': window.checkout.removeItemUrl,
'loginUrl': window.checkout.customerLoginUrl,
'isRedirectRequired': window.checkout.isRedirectRequired
},
'button': {
'checkout': '#top-cart-btn-checkout',
'remove': '#mini-cart a.action.delete',
'increacseqty':'#mini-cart a.action.increase-qty',
'decreaseqty':'#mini-cart a.action.decrease-qty',
'close': '#btn-minicart-close'
},
'showcart': {
'parent': 'span.counter',
'qty': 'span.counter-number',
'label': 'span.counter-label'
},
'minicart': {
'list': '#mini-cart',
'content': '#minicart-content-wrapper',
'qty': 'div.items-total',
'subtotal': 'div.subtotal span.price',
'maxItemsVisible': window.checkout.minicartMaxItemsVisible
},
'item': {
'qty': ':input.cart-item-qty',
'button': ':button.update-cart-item'
},
'confirmMessage': $.mage.__('Are you sure you would like to remove this item from the shopping cart??')
});
return this._super();
}
};
return function (minicart) { // target == Result that Magento_Ui/.../columns returns.
return minicart.extend(mixin); // new result that all other modules receive
};
});

Vuejs - Multiple components use same mixin (only last one gets fired)

I have around four components using the same mixin that I created. In order to get the dimensions of this.$el (the CORRECT ones), I had to implement window.onload = function() mixin. My mixin looks like this:
module.exports = {
methods: {
onPageload: function( callback ) {
window.onload = function() {
callback();
}
}
}
};
Very simple. However, more than one component uses it. I'm creating a slideshow. My Slides component uses it, my Slide component, my Thumb component, and my overall Slider component.
HOWEVER only the very last one to compile fires it.
var pageLoad = require('../../mixins/Pageload');
module.exports = {
template: require('./templates/thumbs.html'),
replace: true,
data: function() {
return {
style: {
width: 800
},
count: 2
}
},
computed: {
styles: function() {
return {
width: this.style.width + 'px'
}
}
},
mixins: [pageLoad],
props: ['count'],
attached: function() {
this.onPageload( this.setDimensions );
},
methods: {
// Set dimensions for the first time
setDimensions: function() {
console.log('setting thumb');
this.style.width = this.$parent.slideWidth;
}
}
};
My other "parent" components do the same thing to set their dimensions. This is the MOST inner child of the entire thing.. it's the ONLY one that fires. If I erase it from here, the next child up is the only one that fires. They are overwriting each other in a way. My vue instance is here:
new Vue({
el: '#slideshow',
components: {
'sliderarrows': require('../../components/slider/SliderArrows'),
'sliderthumb': require('../../components/slider/SliderThumb'),
'sliderslide': require('../../components/slider/SliderSlide'),
'slides': require('../../components/slider/SliderSlides'),
'slider': require('../../components/slider/Slider'),
'thumbnails': require('../../components/slider/SliderThumbs')
}
});
So the thumbnails component is the only one that's firing the mixin method. I feel like it's something to do with the whole compilation of require() but I'm not sure since I'm not that familiar with the Node.js module format.
Thanks for any help on how to get this to work!
I had to change my mixin to this:
module.exports = {
methods: {
onPageload: function( callback ) {
window.onload = callback();
}
}
};
It was something with the window.onload opening a new function.

require.js listener or callback

I am loading a 3rd party script that simply creates an overlay on a site it has been loaded onto. It works fine but sites using require.js seem to have intermittent issues I'm assuming with async loading some js files. Is there any type of callback or way to create a module in the DOM as sort of a listener to see if require.js is done loading?
I tried this but not even close:
define(function() {
alert('test');
return {};
});
and
define('myModule',
function () {
var myModule = {
doStuff:function(){
console.log('Yay! Stuff');
}
};
return myModule;
});
console.log(myModule);
I ended up just creating a secondary require.config file and loading the module with require if require is detected, seems to work fine.
if(typeof require === 'function') {
var base = 'http://' + someDomainVar;
function getJSTreeURL() {
var url = base + '/js/libs/jstree.min';
return url;
}
function getModuleURL() {
var url = base + '/module';
return url;
}
var reqTwo = require.config({
context: "instance2",
baseUrl: "instance2",
paths: {
'jq': 'http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min',
'jqTree': getJSTreeURL(),
'module': getModuleURL()
},
shim: {
'jq': {
exports: 'jq'
},
'jqTree': {
deps: ['jq'],
exports: 'jqTree'
},
'module': {
deps: ['jq', 'jqTree'],
exports: 'module'
}
}
});
reqTwo(['require', 'jq', 'jqTree'],
function(require, jq, jqTree) {
setTimeout(function() {
require(['module'],
function(module) {
console.log('loaded');
}
);
}, 0);
});

Resources