Opacity keeps increasing with each call - javascript

I'm working on a project where I combined KineticJS with SignalR to update the stage on server calls.
So far everything works pretty good, and for the things that didn't work I had great help with the questions and answers on SO.
However this time I can't get it to work I also can't find any questions with a similar problem.
Basically I'm dynamically generating the init script for the KineticJS stage.(this all works perfectly) the code output looks like this:
var stage = new Kinetic.Stage({
id: 1,
container: 'stage-container',
width: self.baseWidth,
height: self.baseHeight
});
And for a shape it looks like this:
var shape129 = new Kinetic.Line({
id: 'shape129',
points: [249,66, 1889,66, 1889,928, 249,928, 249,66],
fill: '#DADADA',
opacity: 1,
stroke: '#3B5A99',
strokeWidth: 0,
closed: true,
draggable: true
});
So far so good.
It all renders perfectly.
Then the magic happens and I use a SignalR method to change the color of the shape
With the following code I get perfect color switches but not the desired opacity:
signal.client.statuschange = function (id, message) {
var shape = Kinetic.stages[0].find('#' + id);
shape.setAttr('fill', message);
shape.setOpacity(0.5);
shape.getLayer().draw();
};
As I said the color changes perfectly but the opacity keeps increasing with each call to the method.
I'm kinda lost here and not sure what is happening and most of all Why it is happening.
Any help would be very much appreciated!

I think problem in find function. Your shape is not a node, but a collection. Try this:
var shape = Kinetic.stages[0].find('#' + id)[0];

Related

The program says "setVisible(false)" is not a function, why is this problem?

Im making a program in Phaser in JavaScript and im using the statement questions.setVisible(false) in my program, but this appears - Uncaught TypeError: question.setVisible is not a function, which clearly is. The statement is in the create function, it doesn't work in the other functions either.
Code:
var Game = new Phaser.Game(800, 600, Phaser.CANVAS, 'phaser-example', {create})
var question;
function create() {
question = Game.add.text(Game.width/2, Game.height/2, 'On which day is Pi celebrated?', {align: 'center'}).anchor.setTo(0.5);
question.setVisible(false);
}
I would recommend to use phaser 3, not phaser 2/CE/... or so. Since the most documentations and informations are for phaser 3. That said, it seems to me, that your problem is two fold:
you cannot chain the all the properties/methods like this, as the comments mention it returns a different object. You would have to do this:
// like this `question` is a Text object
question = game.add.text(game.width/2,game.height/2, 'On which day is Pi celebrated?', {align: 'center', stroke:'white', fill:'white'});
// set the anchor of the `question`
question.anchor.setTo(0.5);
the function setVisible doesn't exist for the text class. (atleast it is not mentioned in the documentation, side note: in phaser3 this function exists). For phaser 2/CE you would have to set the property visible:
question.visible = false;
So the whole function should look something like this:
function create() {
question = game.add.text(game.width/2,game.height/2, '...', {align: 'center'});
question.anchor.setTo(0.5);
question.visible = false;
}

Pattern for using Meteor with advanced SVG or Canvas Ouput

Is it sensible to use Meteor for a reactive data display that isn't primarily HTML based?
To be specific, I want to display a graph database as a set of boxes connected by lines. I'd like to allow live interaction with these boxes, and I'd also like them to be reactive, so if one user edits the data the display of any other users currently viewing the graph will update.
Meteor seems great for the reactivity, but most of the examples I've found focus on either HTML templates or very simple API interactions for doing things like adding a pin to a map.
I am currently thinking about using SVG or Canvas to display the graph database, but I am very unsure how best to integrate that with Meteor and/or some other library like maybe D3.
I found that Meteor works perfectly with canvas, I don't know if what I do is the best practice but I got the best results using Kinetic.js (available for Meteor via "mrt install kineticjs" and I use the template engine to call on functions that set up the elements on my canvas, this is a small example of a code I use to place the players on my map:
the Template:
<template name="canvas_map">
<div id="grid_map" class="grid"></div>
{{#with clear_canvas}}
{{#each human}}
{{handle_member_pos}}
{{/each}}
{{/with}}
the "clear_canvas" helper sets up a new Kinetic.Stage and the "handle_member_pos" helper gets a human object and places it on said canvas.
here are the helpers (coffeescript):
Template.canvas_map.clear_canvas = =>
if Session.get('init')
kinetic_elements.stage = new Kinetic.Stage
container: 'grid_map'
width: 385
height: 375
kinetic_elements.layer = new Kinetic.Layer()
else
false
Template.canvas_map.handle_member_pos = ->
[x, y] = pos_to_str #profile.pos
left = Math.floor(11 * x)
top = Math.floor(11 * y)
name = #profile.name
unless kinetic_elements.avatars[name]?
imageObj = new Image()
imageObj.onload = =>
element = new Kinetic.Image
x: left
y: top
image: imageObj
width: 50
height: 50
element.on 'click', (evt) =>
Session.set 'selected', #profile._id
window.propogation = false
false
kinetic_elements.layer.add element
kinetic_elements.avatars[name] = [element, text]
kinetic_elements.stage.add kinetic_elements.layer
imageObj.src = 'human.png'
else
element = kinetic_elements.avatars[name]
layer = kinetic_elements.layer
element.setX left
element.setY top
layer.draw()
return
as I said, I'm not sure if that is the best practice, but it works great for me, hope this helps in any way.

Fabric.js loadSVGFromUrl not displaying multiple imported SVGS

I'm using fabric.js and loading a number of SVG files into it. I have no problem displaying one of these imported files using this code;
fabric.loadSVGFromURL('ico-svg/drink.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
drink.set({left: 80,
top: 175,
width: 32,
height: 32 });
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
However, when I repeat this code, the page only shows one of the two SVGs, and they actually change upon page refresh - only one icon will show one time, one icon will show the other, on the odd occasion they will both show but one of the SVGs won't display completely.
To load the other SVG, i'm simply copying the above code and changing the required variables;
fabric.loadSVGFromURL('exporttest.svg', function(objects, options) {
var dollars = fabric.util.groupSVGElements(objects, options);
dollars.set({left: 80,
top: 90,
width: 350,
height: 342 });
canvas.add(dollars);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('ico-svg/drink.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
drink.set({left: 80,
top: 175,
width: 32,
height: 32 });
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
Is this something i'm doing wrong? I've read that the library support for loading SVGs from URLs isn't that fantastic - could it be that? Ideally, loading the SVGs from an URL this way or in a similar way is my best option as there are so many, and they are each quite complex and require different positioning.
I think this was a bug that has been fixed in the library.
Current fabricjs.com offer a kitchensink demo where you can try code.
http://fabricjs.com/kitchensink/
copy paste the code below in the execute tab to load 3 svg togheter without any strange issue or taking any precaution.
// clear canvas
canvas.clear();
// remove currently selected object
canvas.remove(canvas.getActiveObject());
fabric.loadSVGFromURL('../assets/1.svg', function(objects, options) {
var dollars = fabric.util.groupSVGElements(objects, options);
canvas.add(dollars);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('../assets/2.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
fabric.loadSVGFromURL('../assets/3.svg', function(objects, options) {
var drink = fabric.util.groupSVGElements(objects, options);
canvas.add(drink);
canvas.calcOffset();
canvas.renderAll();
});
I actually do this as well, where a user can select any number of SVG files to load and later come back to edit their work. When they come back, I had the same issue while trying to reload the multiple files. In my case, I am actually building an array of objects that hold the svg url along with other useful pieces of information. This allowed me to load them into a stack (most suiting for my loading order, though you could easily implement it with a queue) and then pop them off one at a time.
var loadingLayerStack = [url1, url2, url3];
function ProcessLayerLoading()
{
var layerUrl = loadingLayerStack.pop();
DrawSvgToCanvas(layerUrl);
}
function DrawSvgToCanvas(url)
{
fabric.loadSVGFromURL(url, function(objects, options) {
var obj = fabric.util.groupSVGElements(objects, options);
// ...any code for special handling of the loaded object
// put object on the canvas
canvas.add(obj);
// get the next image
ProcessLayerLoading();
});
}
It is noteworthy to point out that I have the setting to enable Rendering when an object is added. So that canvas.add call also takes care of the initial rendering for me.
Hope this helps you somehow. :)
I just ran into this same problem, after seeing your post I decided to dig in to it a bit further myself. It turns out to be due to a scope issue in the onComplete callback within loadSVGFromURL. The problem stems from not isolating the url to a single scope; making multiple back-to-back calls results in the last url always being used when onComplete fires. As a workaround you could either chain your SVG loads or just make an ajax request yourself and load it using loadSVGFromString instead.
I'm learning fabric seems to be full of these bugs, errr, gotchas :(
Edit
I spoke too soon, loadSVGFromString suffers from the same weakness, it does not work asynchronously. That being said chaining is the most obvious work-around.
fabric.loadSVGFromURL() fetches the SVG via XmlHttpRequest. If you wait for each request to complete you can load multiple. Which means you need a tool for making and composing asynchronous promises in JavaScript. Check out q. https://github.com/kriskowal/q

Three.js object definition not defining

I am working my way through a set of tutorials and have come across an error I cant figure out...
I know it is probably me being blind due to my lazy upbringing with IDE's that have red underlines for syntax errors but I kinda need this done soon!
The error is
TypeError: Tetris.boundingBoxConfig is undefined
file:///C:/Users/Timmy/Documents/Emergent%20Tech/Tetris/js/tetris.js
Line 127
here i define Tetris.boundingBoxConfig
var boundingBoxConfig = {
width: 360,
height: 360,
depth: 1200,
splitX: 6,
splitY: 6,
splitZ: 20
};
Tetris.boundingBoxConfig = boundingBoxConfig;
and here is line 127
mesh.position.x = (x - Tetris.boundingBoxConfig.splitX/2)*Tetris.blockSize + Tetris.blockSize/2;
if you need more of the code let me know and I will edit. Any Help would be much appreciated! please only constructive criticism
EDIT Definition of Tetris Object
var Tetris = {};
There was a second suggested way of doing it like this:
window.Tetris = window.Tetris || {};
but i don't really get how that way works
EDIT 2
Not sure if this helps the clarify the issue
var boundingBox = new THREE.Mesh(
new THREE.CubeGeometry(
boundingBoxConfig.width, boundingBoxConfig.height, boundingBoxConfig.depth,
boundingBoxConfig.splitX, boundingBoxConfig.splitY, boundingBoxConfig.splitZ),
new THREE.MeshBasicMaterial( { color: 0xffaa00, wireframe: true } )
);
Tetris.scene.add(boundingBox);
Inside your Tetris function, try changing
Tetris.boundingBoxConfig = boundingBoxConfig;
To
this.boundingBoxConfig = { //your definition };
so that your property becomes public.
Turns out this was due to me using local files in Firefox. I knew that Chrome had security issues when loading the files from a local disk so went with Firefox believing there was not a similar problem due to other projects working. I was wrong.
Lesson: Never use local files always use a server.
Could you please include the code where you have defined the "Tetris" object? (ie var Tetris blah blah blah)

Adding IDs to Fabric.js elements

I am creating a 'map like' application in Canvas using the Fabric.js library. I essentially put an image down and then lay circles on top of the image with the correct coordinates. The dot locations and names come through as JSON data received from an ajax call. I need a way to refer to any individual circle so that I can fetch more information regarding that circle (each circle has a popup with more detailed information).
I can't find anywhere in the documentation that explains how to do this, I have tried adding an ID to an object like this:
tokens.add(new fabric.Circle({ radius: 25, fill: '#f55', top: 100, left: 70, id: "foo" }));
with no luck retrieving it. Any help would be greatly appreciated. Also this is my first interaction with this community, so I apologize if my question isn't detailed enough, or if there is some other problem with it.
You can add an attribute with fabric.object.prototype.
So, add :
fabric.Object.prototype.uid = ... ;
You can Extend fabric.Object class and add your own Property But easiest way would be using fabric.util.Object.extend().
You can add as many as custom property you want and access it using object.toObject().id.
extend(object, prop) {
object.toObject = ((toObject) => {
return function () {
return fabric.util.object.extend(toObject.call(this), prop);
};
})(object.toObject);
}
and then
this.extend(line , {
customType:'ArrowLine',
id:this.randomId(),
CommentId:activeObject.toObject().id, extensionId
});

Categories

Resources