I tried to add a spritesheet to my Phaser game the same way I've done it a few times before, however this time it seems to not load the images correctly, causing it to display a black & green square instead and causing it to throw an error when trying to play an animation.
Can anyone tell what is causing this issue?
(Warning: Playing the Code here seems to freeze up your browser for a few seconds, alternatively view on JSFiddle: https://jsfiddle.net/cak3goru/4/ )
// Configs and Constants
const gameState = {
gameWidth: 800,
gameHeight: 800,
textStyle: {
fontFamily: "'Comic Sans MS'",
fill: "#fff",
align: "center",
boundsAlignH: "left",
boundsAlignV: "top"
},
mouseDown: false,
menu: {
options: [
"Feed", "Clean", "Play"
],
barColor: "0x123456",
items: [],
itemText: [],
itemColor: "0x654321",
}
};
function preload() {
// Clean Tools
this.load.atlas('clean', 'https://gaylie.neocities.org/game/assets/clean.png', 'https://gaylie.neocities.org/game/assets/clean.json');
}
function create () {
this.anims.create({
key: "shower_cursor",
framerate: 12,
frames: this.anims.generateFrameNumbers("clean", {
prefix: "showerhead_000",
start: 0,
end: 7}),
repeat: -1
});
gameState.shower_cursor = this.add.sprite(400,400,'shower_cursor');
console.log(gameState.shower_cursor.frame);
//gameState.shower_cursor.playAfterDelay('shower_cursor', 100);
//gameState.shower_cursor.alpha = 0;
}
var config = {
backgroundColor: "0xf0f0f0",
scale: {
width: gameState.gameWidth,
height: gameState.gameHeight,
autoCenter: Phaser.Scale.CENTER_BOTH
},
scene: {
preload, create
}
};
var game = new Phaser.Game(config);
<head>
<title>Pet Simulator</title>
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
</head>
<body style="height: 100%; width: 100%; margin: 0;">
</body>
The problem is, that you are using the wrong function, you should use this.anims.generateFrameNames, and not this.anims.generateFrameNumbers.
And set the correct key clean for the sprite.
the line should be:
gameState.shower_cursor = this.add.sprite(200, 100, 'clean');
because shower_cursor, is only the key of the animation, not the key of the sprite.
P.s.: the posted code doesn't run on jsfiddler or Stackoverflow due to CORS-Error, but if all assets are on the same server, it should not be a problem.
What the real meaning of randomize=false using cose-bilkent layout ?
I can only read such a simple comment to describe this feature in this extension wiki page.
// Whether to enable incremental mode
randomize: true,
I also find another description for randomize in cytoscape.js-expand-collapse wiki page.
// recommended usage: use cose-bilkent layout with randomize: false to preserve mental map upon expand/collapse
So I have learned that randomize: false is to preserve mental map. But what is the real behavior ?
Suppose that I have run a topology graph using cose-bilkent layout, then call the following snippet to append new nodes and edges to the graph with randomize: false. What will be the expected result on incremental mode ? Should the old nodes and edges keep the relative position as so called mental map , while new nodes and edges should be positioned to a resonable coordinate?
var demoId = 10000;
document.getElementById("append").addEventListener("click", function() {
var tid = cy.nodes()[Math.floor(Math.random()*cy.nodes().length)].data().id;
var sid = ++demoId;
var data = {
nodes : [
{data:{"id":"id"+source, "name":"name"+source}}
],
edges :[
{data:{"id":"id"+source+"-"+target, "source":"id"+source, "target":target}}
]
};
cy.add(data);
cy.layout({
name: 'cose-bilkent',
animate: false,
randomize : false,
fit : false
}).run();
});
See my demo. My test result is that all nodes and edges will be relayout. You could watch some nodes and their neighborhood. The neighborhood will be changed after each layout. I can't get a clear mental map. So could the experts explain how incremental layout task effect here.
document.addEventListener("DOMContentLoaded", function() {
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
ready: function() {
this.layout({
name: "cose-bilkent",
animationDuration: 1000
}).run();
},
style: [{
selector: "node",
style: {
'content': 'data(id)',
'text-valign': 'center',
'text-halign': 'center',
'background-color': 'blue',
'color':'red',
'width':'10px',
'height':'10px'
}
},
{
selector: ":parent",
style: {
"background-opacity": 0.333
}
},
{
selector: "edge",
style: {
width: 3,
"line-color": "#ad1a66"
}
}
],
elements: [{"group":"nodes","data":{"id":"p_1","parent":"n_72"}},{"group":"nodes","data":{"id":"p_298","parent":"n_72"}},{"group":"nodes","data":{"id":"p_4","parent":"n_72"}},{"group":"nodes","data":{"id":"p_5","parent":"n_72"}},{"group":"nodes","data":{"id":"p_9","parent":"n_72"}},{"group":"nodes","data":{"id":"p_32","parent":"n_72"}},{"group":"nodes","data":{"id":"p_607","parent":"n_72"}},{"group":"nodes","data":{"id":"p_57","parent":"n_72"}},{"group":"nodes","data":{"id":"p_242","parent":"n_72"}},{"group":"nodes","data":{"id":"p_64","parent":"n_72"}},{"group":"nodes","data":{"id":"p_77","parent":"n_72"}},{"group":"nodes","data":{"id":"p_81","parent":"n_72"}},{"group":"nodes","data":{"id":"p_82","parent":"n_72"}},{"group":"nodes","data":{"id":"p_289","parent":"n_72"}},{"group":"nodes","data":{"id":"p_803","parent":"n_72"}},{"group":"nodes","data":{"id":"n_0"}},{"group":"nodes","data":{"id":"n_72"}},{"group":"edges","data":{"source":"n_0","target":"n_0","id":"n_0-n_0"}},{"group":"edges","data":{"source":"n_0","target":"p_81","id":"n_0-p_81"}},{"group":"edges","data":{"source":"n_0","target":"p_4","id":"n_0-p_4"}},{"group":"edges","data":{"source":"n_0","target":"p_298","id":"n_0-p_298"}},{"group":"edges","data":{"source":"n_0","target":"p_803","id":"n_0-p_803"}},{"group":"edges","data":{"source":"n_0","target":"p_607","id":"n_0-p_607"}},{"group":"edges","data":{"source":"n_0","target":"p_1","id":"n_0-p_1"}},{"group":"edges","data":{"source":"n_0","target":"p_289","id":"n_0-p_289"}},{"group":"edges","data":{"source":"n_0","target":"p_57","id":"n_0-p_57"}},{"group":"edges","data":{"source":"n_0","target":"p_82","id":"n_0-p_82"}},{"group":"edges","data":{"source":"n_0","target":"p_32","id":"n_0-p_32"}},{"group":"edges","data":{"source":"p_77","target":"n_0","id":"p_77-n_0"}},{"group":"edges","data":{"source":"p_64","target":"n_0","id":"p_64-n_0"}},{"group":"edges","data":{"source":"p_607","target":"n_0","id":"p_607-n_0"}},{"group":"edges","data":{"source":"p_5","target":"n_0","id":"p_5-n_0"}},{"group":"edges","data":{"source":"p_9","target":"n_0","id":"p_9-n_0"}},{"group":"edges","data":{"source":"p_9","target":"p_803","id":"p_9-p_803"}},{"group":"edges","data":{"source":"p_242","target":"n_0","id":"p_242-n_0"}}],
}));
var demoId = 10000;
document.getElementById("append").addEventListener("click", function() {
var tid = cy.nodes()[Math.floor(Math.random()*cy.nodes().length)].data().id;
var sid = ++demoId;
var data = {
nodes : [
{data:{"id":sid}}
],
edges :[
{data:{"id":sid+"-"+tid, "source":sid, "target":tid}}
]
};
cy.add(data);
cy.layout({
name: 'cose-bilkent',
animate: false,
randomize : false,
fit : true
}).run();
});
});
body {
font-family: helvetica;
font-size: 14px;
}
#cy {
height: 100%;
width: 90%;
position: absolute;
}
h1 {
opacity: 0.5;
font-size: 1em;
}
button {
margin-right: 10px;
}
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<!--polyfills are needed for this extension for old browsers like IE -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.5.7/shim.min.js"></script>
<script src="https://unpkg.com/layout-base/layout-base.js"></script>
<script src="https://unpkg.com/cose-base/cose-base.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-cose-bilkent#4.1.0/cytoscape-cose-bilkent.min.js"></script>
<body>
<button id="append" class="button">Append</button>
<div id="cy"></div>
</body>
fabricjs_2.3.6
I am working on an editor that will allow the user to create textboxes images and rectangles dynamically and that portion of the project works great. All objects on the canvas will pre-existing before creating groups therefore I do not want to hard-code any fabrics. I also want to preserve the positional relation between the grouped items.
I am having a problem with creating groups by selecting 2 or more existing objects on the canvas to create a group. My code works with one exception, if the selected items are not in the upper left corner of the canvas when I create the group the grouped objects remain in the original location as desired but the move handle is in the upper left corner of the canvas. If you click the move cursor handle ghost and then click a blank area on the canvas the problem goes away and everything works fine after that.
I have had no luck searching for a solution possibly because I'm not sure what controls the move cursor's location on the canvas or if it is actually called the "move cursor".
Here is a picture from my jsfiddle after clicking the group button:
Here is a jsfiddle link to demonstrate the problem: https://jsfiddle.net/Larry_Robertson/xfrd278a/
Here is my code:
HTML
<span> Test 1: select both the line and the text objects with the mouse then click group, works great.</span>
<br/>
<span> Test 2: select both the line and the text objects with the mouse, move the selction to the center of the canvas then click group. This creates the problem where a ghost move handle is left behind in the upper left corner of the canvas. The move handle did not update to the correct position when the group was created. If you hover the mouse in the upper left of canvas you will see the move cursor. Click on the move cursor then click any blank part of the canvas then you can reselect the group and it moves properly. What am I doing wrong???</span>
<br/>
<button id="group">group</button>
<canvas id="c" height="300" width="500"></canvas>
JS
var canvas = new fabric.Canvas('c');
var text = new fabric.Text('hello world', {
fontSize: 30,
originX: 'left',
originY: 'top',
left: 0,
top: 0
});
var line = new fabric.Line([10, 10, 100, 100], {
stroke: 'green',
strokeWidth: 2
});
canvas.add(line);
canvas.add(text);
canvas.renderAll();
$('#group').on(("click"), function(el) {
var activeObject = canvas.getActiveObject();
var selectionTop = activeObject.get('top');
var selectionLeft = activeObject.get('left');
var selectionHeight = activeObject.get('height');
var selectionWidth = activeObject.get('width');
if (activeObject.type === 'activeSelection') {
var group = new fabric.Group([activeObject], {
left: 0,
top: 0,
originX: 'center',
originY: 'center'
});
canvas.add(group);
deleteSelectedObjectsFromCanvas();
canvas.setActiveObject(group);
group = canvas.getActiveObject();
group.set('top', selectionTop + (selectionHeight / 2));
group.set('left', selectionLeft + (selectionWidth / 2));
group.set('originX', 'center');
group.set('originY', 'center');
canvas.renderAll();
}
});
function deleteSelectedObjectsFromCanvas() {
var selection = canvas.getActiveObject();
var editModeDected = false;
if (selection.type === 'activeSelection') {
selection.forEachObject(function(element) {
console.log(element);
if (element.type == 'textbox') {
if (element.isEditing == true) {
//alert('At least one textbox is currently being edited. No objects were deleted');
editModeDected = true;
}
}
});
if (editModeDected == true) {
return false;
}
// Its okay to delete all selected objects
selection.forEachObject(function(element) {
console.log('removing: ' + element.type);
//element.set('originX',null);
//element.set('originY',null);
canvas.remove(element);
canvas.discardActiveObject();
canvas.requestRenderAll();
});
} else {
if (selection.isEditing == true && selection.type == 'textbox') {
//alert('Textbox is currently being edited. No objects were deleted');
} else {
canvas.remove(selection);
canvas.discardActiveObject();
canvas.requestRenderAll();
}
}
}
CSS
#c {
margin: 10px;
padding: 10px;
border: 1px solid black;
}
After making changes on code always do a setCoords on the object(s) that got changed.
Here is a one liner you can add after the renderAll to fix your issue:
...
group.set('originY', 'center');
canvas.renderAll();
canvas.forEachObject(function(o) {o.setCoords()});
I have the following situation: I draw the canvas with a background image and this works:
var canvasSection = new fabric.Canvas('buildSection', {
selectionColor: 'rgba(94,213,94,0.2)',
width: widthS,
height: heightS,
hoverCursor: 'pointer',
backgroundColor: ({
source: 'image/bordenconfigurator/background/background1.png',
repeat: 'repeat'
})
});
But then I need to clear canvas and to redraw it. at this point when I try to set background, instead of an image I see a black screen. In console I can see that the background image is set however. This is the code I'm trying:
$('#cForm').on('change', function() {
if ($(this).val() == 'rectLandsc') {
widthS = 600;
heightS = 400;
} else if ($(this).val() == 'rectPortr') {
....
}
canvasSection.clear();
canvasSection.set({
fill: 'rgba(0,0,0,0)',
// backgroundColor: ({source: 'image/bordenconfigurator/background/background1.png', repeat: 'repeat'})
});
//canvasSection.backgroundColor({source: 'image/bordenconfigurator/background/background.png', repeat:'repeat'});
canvasSection.setBackgroundColor({
source: 'image/bordenconfigurator/background/background.png'
}),
canvasSection.renderAll.bind(canvas);
drawBaseForm();
canvasSection.renderAll();
console.log(canvasSection);
});
Is it a kind of a bug? Or am I doing something wrong? Could anyone help me out here?
canvas.setBackgroundColor({
source: 'image/bordenconfigurator/background/background1.png',
repeat: 'repeat'
}, canvas.renderAll.bind(canvas));
setBackgroundColor first parameter is color/pattern and second parameter is callback function.
DEMO
var canvas = new fabric.Canvas('c');
canvas.setBackgroundColor({
source: 'http://fabricjs.com/assets/pug_small.jpg'
}, canvas.renderAll.bind(canvas));
function clearCanvas(){
var background = canvas.backgroundColor;
canvas.clear();
setTimeout(function(){
canvas.setBackgroundColor(background,canvas.renderAll.bind(canvas));
},2000)
}
canvas{
border: 2px dotted black;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<button onclick='clearCanvas()'>clear</button>
<canvas id="c" width="500" height="500"></canvas>
How to set non pixels position?
I try this
var stack = { "dir1": "down", "dir2": "right", "firstpos1": 50, "firstpos2": 50 };
But I this it is bad because of different screen resolution.
Necroposting, but may help to other searchers. My solution without js recalculations:
js:
new PNotify({
...
addclass: 'pnotify-center'
});
css:
.pnotify-center {
right: calc(50% - 150px) !important;
}
there's a similar question with an answer here. As per the first example in the stacks documentation, you can center the initial position of the notification by setting the top/left css propreties in before_open. You also need to reposition the notification everytime the window is resized.
function get_center_pos(width, top) {
// top is empty when creating a new notification and is set when recentering
if (!top) {
top = 30;
// this part is needed to avoid notification stacking on top of each other
$('.ui-pnotify').each(function() {
top += $(this).outerHeight() + 20;
});
}
return {
"top": top,
"left": ($(window).width() / 2) - (width / 2)
}
}
$(document).ready(function() {
new PNotify({
title: "this is center",
text: "blablabla",
opacity: 0.90,
type: "info",
width: "390px",
before_open: function(PNotify) {
PNotify.get().css(get_center_pos(PNotify.get().width()));
}
});
$(window).resize(function() {
$(".ui-pnotify").each(function() {
$(this).css(get_center_pos($(this).width(), $(this).position().top))
});
});
});