I'm trying to generate a sprite-sheet dynamically in easeljs after triggering a event from the ipcMain to a window.
The problem i'm having is that preloadjs/easeljs trigger this error in the console:
Cannot read property "getContext" of undefined
It only happen after i package the app, not in dev mode, where everything works as expected.
here my code from the window
import { ipcRenderer } from "electron";
let canvasEl, stage, queue;
ipcRenderer.on("render-spritesheets", (_, data) => {
const files = data.previewFiles;
const info = data.info;
canvasEl = document.getElementById("stage");
canvasEl.width = info.width;
canvasEl.height = info.height;
canvasEl.style.backgroundColor = "black";
stage = new createjs.Stage("stage");
createjs.Ticker.timingMode = createjs.Ticker.RAF_SYNCHED;
createjs.Ticker.framerate = info.framerate;
function handleTick() {
stage.update();
}
createjs.Ticker.addEventListener("tick", handleTick);
function onError(err) {
console.log(err);
}
function onComplete(event) {
const spritesheets = files
.map(f => f.path)
.map((_, i) => queue.getResult(`spr_${i}`));
console.log(spritesheets);
const spritesheetData = {
images: spritesheets,
frames: {
width: +info.width,
height: +info.height,
count: +info.frames,
regX: 0,
regY: 0
}
};
const spriteSheet = new createjs.SpriteSheet(spritesheetData);
const animation = new createjs.Sprite(spriteSheet);
stage.addChild(animation);
animation.play();
}
function loadSpritesheets() {
const manifest = [];
files.forEach((file, index) => {
manifest.push({ src: file.path, id: `spr_${index}` });
});
queue = new createjs.LoadQueue(false);
queue.addEventListener("complete", onComplete);
queue.addEventListener("error", onError);
queue.loadManifest(manifest, true);
}
loadSpritesheets();
});
and here my electron.js code.
import { app, BrowserWindow, ipcMain } from 'electron';
import installExtension, { REACT_DEVELOPER_TOOLS } from 'electron-devtools-installer';
import { enableLiveReload } from 'electron-compile';
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
let previewWindow;
const isDevMode = process.execPath.match(/[\\/]electron/);
if (isDevMode) enableLiveReload({ strategy: 'react-hmr' });
const createWindow = async () => {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 400,
height: 650,
minWidth: 400,
minHeight: 650,
maxHeight: 650,
maxWidth: 400,
frame: false
});
// and load the index.html of the app.
mainWindow.loadURL(`file://${__dirname}/index.html`);
// Open the DevTools.
if (isDevMode) {
await installExtension(REACT_DEVELOPER_TOOLS);
mainWindow.webContents.openDevTools();
}
// Emitted when the window is closed.
mainWindow.on('closed', () => {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
ipcMain.on('close-app', (evt, arg) => {
mainWindow = null;
previewWindow = null;
app.quit();
})
ipcMain.on("open-preview", (evt, data) => {
const mainWinPos = mainWindow.getPosition();
const width = data.info.width;
const height = data.info.height + 56;
previewWindow = new BrowserWindow({
width: width,
height: height,
minWidth: width,
minHeight: height,
maxHeight: height,
maxWidth: width,
frame: false,
parent: mainWindow
});
previewWindow.setPosition(mainWinPos[0] - (width + 20), mainWinPos[1], false);
previewWindow.loadURL(`file://${__dirname}/preview.html`);
previewWindow.webContents.once('did-finish-load', () => {
previewWindow.webContents.openDevTools();
previewWindow.webContents.send('render-spritesheets', data);
});
previewWindow.on("closed", () => previewWindow = null);
ipcMain.on("close-preview", () => {
if (previewWindow) previewWindow.close();
});
});
};
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.
Thanks!
This issue is almost always caused by the canvas element not being in the DOM yet. When you use:
the stage will be looked up using
document.getElementById("stage");. If it is not in the DOM yet, you any access to the context will fail.Does this line work? It does the same thing.
Usually frameworks create a document fragment, and you have to query that instead to get your stage reference.
Hope that helps.