Matter.js doesn't update body properties if Pixi.js renderer is used - pixi.js

I want to update certain body properties if user clicks on it, e.g. body.render.lineWidth = 5;
It works just fine if the default canvas renderer is used. If I switch to Pixi.js renderer it stops working and doesn't seem to reflect any properties at all.
I also tried with the Matter.Body.set function but with no luck either. Properties are set actually to a body but the body keeps showing the initial style which was provided at the construction time.
What is the proper way to set those properties?
EDIT:
sample.js
var Engine = Matter.Engine,
World = Matter.World,
Bodies = Matter.Bodies,
Common = Matter.Common,
MouseConstraint = Matter.MouseConstraint;
var createOptions = function(options) {
var defaults = {
isManual: false,
sceneName: 'mixed',
sceneEvents: []
};
return Common.extend(defaults, options);
};
var options = {
positionIterations: 6,
velocityIterations: 4,
enableSleeping: false,
metrics: { extended: true },
render: {
controller: Matter.RenderPixi
}
};
var engine = Engine.create(document.getElementById('canvas-container'), createOptions(options));
var world = engine.world;
var mouseConstraint = MouseConstraint.create(engine, {
constraint: {
render: {
visible: false
}
}
});
World.add(engine.world, mouseConstraint);
World.add(world, [
Bodies.rectangle(400, 0, 800, 1, { isStatic: true }),
Bodies.rectangle(400, 600, 800, 1, { isStatic: true }),
Bodies.rectangle(800, 300, 1, 600, { isStatic: true }),
Bodies.rectangle(0, 300, 1, 600, { isStatic: true })
]);
var body = Bodies.polygon(200, 200, 4, Common.random(50, 60), {
isStatic: true,
friction: 1,
render: {
fillStyle: '#f0f0f0',
strokeStyle: 'black',
lineWidth: 1
}
});
World.add(world, body);
Matter.Events.on(mouseConstraint, 'mousedown', function(e) {
body.render.lineWidth = 5;
});
var renderOptions = engine.render.options;
renderOptions.wireframes = false;
renderOptions.hasBounds = false;
renderOptions.showDebug = false;
renderOptions.showBroadphase = false;
renderOptions.showBounds = false;
renderOptions.showVelocity = false;
renderOptions.showCollisions = false;
renderOptions.showAxes = false;
renderOptions.showPositions = false;
renderOptions.showAngleIndicator = false;
renderOptions.showIds = false;
renderOptions.showShadows = false;
renderOptions.showVertexNumbers = false;
renderOptions.showConvexHulls = false;
renderOptions.showInternalEdges = false;
renderOptions.showSeparations = false;
renderOptions.background = '#fff';
Engine.run(engine);
sample.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
</head>
<body>
<div id="canvas-container"></div>
<script src="pixi.min.v3.0.10.js" type="text/javascript"></script>
<script src="matter.min.v0.9.1.js" type="text/javascript"></script>
<script src="sample.js" type="text/javascript"></script>
</body>
</html>
If I comment out controller: Matter.RenderPixi everything works OK.

RenderPixi creates primitives only once when the body first gets rendered and this gets cached.
To remove it from the cache, you should be able to do something like:
engine.render.primitives['b-' + body.id] = null;
Then it should get created again.

Related

Lasso tool in html5 canvas - replacing the clipTo function with clipPath

The code shown below is from this post. It works fine when using fabric.js/1.4.0, but when I update fabric.js to 2.4.3, it fails to run. The issue is that the clipTo funtion has been replaced by a new function called clipPath. Does anyone know how to update this code so it works with clipPath? I've gone through the docs for clipPath and have been searching Google and Stackoverflow for almost 2 days, but I'm still lost.
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = document.createElement('IMG');
img.onload = function() {
var OwnCanv = new fabric.Canvas('c', {
isDrawingMode: true
});
var imgInstance = new fabric.Image(img, {
left: 0,
top: 0,
});
OwnCanv.add(imgInstance);
OwnCanv.freeDrawingBrush.color = "purple"
OwnCanv.freeDrawingBrush.width = 4
OwnCanv.on('path:created', function(options) {
var path = options.path;
OwnCanv.isDrawingMode = false;
OwnCanv.remove(imgInstance);
OwnCanv.remove(path);
OwnCanv.clipTo = function(ctx) {
path.render(ctx);
};
OwnCanv.add(imgInstance);
});
}
img.src = "http://upload.wikimedia.org/wikipedia/commons/3/33/Jbassette4.jpg?uselang=fi";
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>
<canvas id="c" width="500" height="500"></canvas>
Ok, so the path, right after being created is already cached.
What you need to do is set the fill to a color that is not null, using the 'set' method.
Then set the path as clipPath for the canvas, or the Object itself.
If you want to set it just for the object, you need to recalculate its correct position.
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = document.createElement('IMG');
img.onload = function() {
var OwnCanv = new fabric.Canvas('c', {
isDrawingMode: true
});
var imgInstance = new fabric.Image(img, {
left: 0,
top: 0,
});
OwnCanv.add(imgInstance);
OwnCanv.controlsAboveOverlay = true;
OwnCanv.freeDrawingBrush.color = "purple"
OwnCanv.freeDrawingBrush.width = 4
OwnCanv.on('path:created', function(options) {
var path = options.path;
path.set('fill', 'black');
console.log(path)
OwnCanv.isDrawingMode = false;
OwnCanv.remove(path);
OwnCanv.clipPath = path;
});
}
img.src = "http://upload.wikimedia.org/wikipedia/commons/3/33/Jbassette4.jpg?uselang=fi";
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.min.js"></script>
<canvas id="c" width="500" height="500"></canvas>
You need to have objectCaching on false on the path.
Check here:https://jsfiddle.net/jw6rLx5f/2/
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = document.createElement('IMG');
img.onload = function() {
var OwnCanv = new fabric.Canvas('c', {
isDrawingMode: true
});
var imgInstance = new fabric.Image(img, {
left: 0,
top: 0,
});
OwnCanv.add(imgInstance);
OwnCanv.freeDrawingBrush.color = "purple"
OwnCanv.freeDrawingBrush.width = 4
OwnCanv.on('path:created', function(options) {
var path = options.path;
path.objectCaching= false;
OwnCanv.isDrawingMode = false;
OwnCanv.remove(imgInstance);
OwnCanv.remove(path);
OwnCanv.clipTo = function(ctx) {
ctx.save();
path.render(ctx);
ctx.restore();
};
OwnCanv.add(imgInstance);
});
}
img.src = "http://upload.wikimedia.org/wikipedia/commons/3/33/Jbassette4.jpg?uselang=fi";
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.6/fabric.js"></script>
<canvas id="c" width="500" height="500"></canvas>

Phantom html-to-pdf Document broken

I am using Phantom-html-to-pdf to create documents. In my node application I create an HTML string with EJS templating then I save the documents into a folder.
In my EJS file I import css file, but it seems like for 20% of the PDF generated the css is not loaded.
So the error is that the font is not loaded and i got blank PDF even with fallback font
My function:
function createPdf (data, template, directory) {
var options = {};
var type = template.indexOf('avoir') >= 0 ? true : false
var tva = [];
var items = listeItem(data);
var list = calculeTva(data.Liste_item, type);
Societe.findOne({}, (err, doc) => {
data.Liste_tva = list ;
data.societe = doc ;
data.items = items ;
var html = ejs.renderFile(__dirname + `/template/${template}.ejs`, {data: data}, options, function(err, str){
if(err){
return err
}
return str
});
var option = {
html : html,
}
var filename = directory === 'archive' ? data.Référence + '-' + Date.now() : data.Référence;
var conversion = require("phantom-html-to-pdf")();
// var conversion = require("phantom-html-to-pdf")({
// phantomPath: require("phantomjs-prebuilt").path
// });
conversion({
html: html,
paperSize: {
format: 'A4',
orientation: 'portrait',
margin: {bottom: '0cm', left: '0.5cm', right: '0.5cm', top: '0.5cm'},
}
}, function(err, pdf) {
console.log('ERR', err)
var output = fs.createWriteStream(`documents/${directory}/${filename}.pdf`)
pdf.stream.pipe(output);
response = {success: false, err: err}
return response
});
});
}
My EJS :
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://mywebsite.com/css/uikitx.css" />
<link href="https://mywebsite.com/css/custom.css" rel="stylesheet"/>
</head>
<body style="font-family: 'AvenirNext', Helvetica, sans-serif;">
I really stuck on this, any idea ?
Thanks

Use Socket.io to fill google Area Chart - 'google.visualization.DataTable is not a constructor'

I use NodeJS and Socket.io to get data from a database. I now want to fill a google area chart with these data but i kind of fail at doing it.
The data is transmitted as Objects. Each Object contains two values (datetime and value). I append these values to an array and then store them in a DataTable:
google.load('visualization', '1', {
packages: ['corechart']
});
google.setOnLoadCallback(drawChart);
var socket = io();
getData();
function drawChart(dataArray) {
var data = new google.visualization.DataTable();
data.addColumn('string', 'DateTime');
data.addColumn('number', 'Value');
for (var i = 0; i < dataArray.length; i += 2) {
console.log(dataArray[0]);
data.addRow([dataArray[i], dataArray[i + 1]]);
}
var chart = new google.visualization.AreaChart(document.getElementById('chart'));
chart.draw(data, {
title: "Data Visualization",
isStacked: true,
width: '50%',
height: '50%',
vAxis: {
title: 'Data v-Axis'
},
hAxis: {
title: 'Data h-Axis'
}
})
}
function getData() {
socket.emit('GET');
socket.on('serverSent', function (data) {
var processedData = processData(data);
drawChart(processedData);
})
}
function processData(data) {
var arr = new Array();
jQuery.each(data, function (index, object) {
arr.push(object['datetime'], parseInt(object['value']));
})
return arr;
}
If i call my website i see the chart but without any values and the error message `google.visualization.DataTable is not a constructor´. So what am i doing wrong?
The problem is drawChart is being called twice.
From both google.setOnLoadCallback and getData.
If getData is called before google.setOnLoadCallback,
then google.visualization.DataTable will not be recognized.
In addition, it is recommended to use loader.js vs. jsapi.
See Load the Libraries for more info...
As such, please try the following...
Replace...
<script src="https://www.google.com/jsapi"></script>
With...
<script src="https://www.gstatic.com/charts/loader.js"></script>
And try something like...
google.charts.load('current', {
callback: init,
packages: ['corechart']
});
function init() {
var socket = io();
socket.emit('GET');
socket.on('serverSent', function (data) {
var processedData = processData(data);
drawChart(processedData);
});
}
function drawChart(dataArray) {
var data = new google.visualization.DataTable();
data.addColumn('string', 'DateTime');
data.addColumn('number', 'Value');
for (var i = 0; i < dataArray.length; i += 2) {
console.log(dataArray[0]);
data.addRow([dataArray[i], dataArray[i + 1]]);
}
var chart = new google.visualization.AreaChart(document.getElementById('chart'));
chart.draw(data, {
title: "Data Visualization",
isStacked: true,
width: '50%',
height: '50%',
vAxis: {
title: 'Data v-Axis'
},
hAxis: {
title: 'Data h-Axis'
}
})
}

Why does my sprite disappear when I call shiftHSL?

If I uncomment the shiftHSL line below, the sprite does not appear.
<script src='https://rawgit.com/photonstorm/phaser/master/build/phaser.js'></script>
<script>
var game = new Phaser.Game(800, 400, Phaser.AUTO, '', {
preload: function() { this.game.load.image('dwarf', 'res/dwarf.png') },
create: function() {
var bmd = game.make.bitmapData()
bmd.width = 80
bmd.height = 80
bmd.circle(bmd.width / 2, bmd.width / 2, bmd.width / 2, '#ffffff')
bmd.alphaMask('dwarf', bmd)
// bmd.shiftHSL(0, -.5, 0)
var sprite = game.add.sprite(100, 100, bmd)
}
});
</script>
Ok, I got it working. Looks like you need to call bmd.update() before calling shiftHSL.

Save and Restore rectangles with connections in Draw2D.js touch via JSON

How do I create rectangles with 4 ports (each side) in a correct way, so I can save and restore them via JSON?
I tried this one, but only the rectangles are been saved. The connections and labels got lost.
JSFiddle: http://jsfiddle.net/xfvf4/36/
Create two elements (Add) - move them and connect them
Write: This gives the content as JSON-Array
Read: Should make the grafic out of the JSON-Array
The last point doesn't work.
JS:
var LabelRectangle = draw2d.shape.basic.Rectangle.extend({
NAME: "draw2d.shape.basic.Rectangle",
init: function (attr) {
this._super(attr);
this.label = new draw2d.shape.basic.Label({
text: "Text",
fontColor: "#0d0d0d",
stroke: 0
});
this.add(this.label, new draw2d.layout.locator.CenterLocator(this));
this.label.installEditor(new draw2d.ui.LabelInplaceEditor());
this.createPort("hybrid", new draw2d.layout.locator.BottomLocator(this));
},
getPersistentAttributes: function () {
var memento = this._super();
memento.labels = [];
var ports = [];
ports = this.getPorts();
memento.ports = [];
console.log(ports);
this.children.each(function (i, e) {
console.log(e);
memento.labels.push({
id: e.figure.getId(),
label: e.figure.getText(),
locator: e.locator.NAME
});
ports.each(function (i, e) {
memento.ports.push({
//id: e.id,
name: e.name,
locator: e.locator.NAME
});
});
});
return memento;
},
setPersistentAttributes: function (memento) {
this._super(memento);
this.resetChildren();
$.each(memento.labels, $.proxy(function (i, e) {
var label = new draw2d.shape.basic.Label(e.label);
var locator = eval("new " + e.locator + "()");
locator.setParent(this);
this.add(label, locator);
}, this));
}
});
$(window).load(function () {
var canvas = new draw2d.Canvas("gfx_holder");
$("#add").click(function (e) { // Add a new rectangle
var rect = new LabelRectangle({
width: 200,
height: 40,
radius: 3,
bgColor: '#ffffff',
stroke: 0
});
rect.createPort("hybrid", new draw2d.layout.locator.OutputPortLocator(rect));
rect.createPort("hybrid", new draw2d.layout.locator.InputPortLocator(rect));
rect.createPort("hybrid", new draw2d.layout.locator.TopLocator(rect));
canvas.add(rect, 150, 200);
});
$("#write").click(function (e) { // Write to pre-Element (JSON)
var writer = new draw2d.io.json.Writer();
writer.marshal(canvas, function(json){
$("#json").text(JSON.stringify(json,null,2));
$('#gfx_holder').empty();
});
});
$("#read").click(function (e) { // Read from pre-Element (JSON)
var canvas = new draw2d.Canvas("gfx_holder");
var jsonDocument = $('#json').text();
var reader = new draw2d.io.json.Reader();
reader.unmarshal(canvas, jsonDocument);
});
});
HTML:
<ul class="toolbar">
<li>Add</li>
<li>Write</li>
<li>Read</li>
</ul>
<div id="container" class="boxed">
<div onselectstart="javascript:/*IE8 hack*/return false" id="gfx_holder" style="width:100%; height:100%; ">
</div>
<pre id="json" style="overflow:auto;position:absolute; top:10px; right:10px; width:350; height:500;background:white;border:1px solid gray">
</pre>
</div>
Just use the write.js and Reader.js in the "json"-Folder of Draw2D.js 5.0.4 and this code:
$(window).load(function () {
var canvas = new draw2d.Canvas("gfx_holder");
// unmarshal the JSON document into the canvas
// (load)
var reader = new draw2d.io.json.Reader();
reader.unmarshal(canvas, jsonDocument);
// display the JSON document in the preview DIV
//
displayJSON(canvas);
// add an event listener to the Canvas for change notifications.
// We just dump the current canvas document into the DIV
//
canvas.getCommandStack().addEventListener(function(e){
if(e.isPostChangeEvent()){
displayJSON(canvas);
}
});
});
function displayJSON(canvas){
var writer = new draw2d.io.json.Writer();
writer.marshal(canvas,function(json){
$("#json").text(JSON.stringify(json, null, 2));
});
}
This should work:
var LabelRectangle = draw2d.shape.basic.Rectangle.extend({
NAME: "draw2d.shape.basic.Rectangle",
init: function (attr) {
this._super(attr);
this.label = new draw2d.shape.basic.Label({
text: "Text",
fontColor: "#0d0d0d",
stroke: 0
});
this.add(this.label, new draw2d.layout.locator.CenterLocator(this));
this.label.installEditor(new draw2d.ui.LabelInplaceEditor());
},
getPersistentAttributes: function () {
var memento = this._super();
memento.labels = [];
memento.ports = [];
this.getPorts().each(function(i,port){
memento.ports.push({
name : port.getName(),
port : port.NAME,
locator: port.getLocator().NAME
});
});
this.children.each(function (i, e) {
memento.labels.push({
id: e.figure.getId(),
label: e.figure.getText(),
locator: e.locator.NAME
});
});
return memento;
},
setPersistentAttributes: function (memento) {
this._super(memento);
this.resetChildren();
if(typeof memento.ports !=="undefined"){
this.resetPorts();
$.each(memento.ports, $.proxy(function(i,e){
var port = eval("new "+e.port+"()");
var locator = eval("new "+e.locator+"()");
this.add(port, locator);
port.setName(e.name);
},this));
}
$.each(memento.labels, $.proxy(function (i, e) {
var label = new draw2d.shape.basic.Label(e.label);
var locator = eval("new " + e.locator + "()");
locator.setParent(this);
this.add(label, locator);
}, this));
}
});

Resources