tf.browser.fromPixels returns only zeros - tensorflow.js

Here tf.browser.fromPixels returns a tensor with only zeros. image.data contains values as expected (not only zeros). tfjs is loaded using a script tag. tfjs 1.0.0 but changing release does not help.
What can be wrong? Probably something stupid. I am new to Tensorflow.js...
<canvas id="canvas" width="100" height="100" style="border:1px solid #FF0000;"></canvas>
....
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var image = ctx.getImageData(0, 0, canvas.height, canvas.width);
var x = tf.browser.fromPixels(image);

When created, the canvas has all its pixel values set to 0.
var canvas = document.getElementById('canvas');
canvas is an imageData with only 0 values. It is no surprise that the tensor created has its values to 0 since the canvas used to created it does not have any image data except 0 values.
The CSS style does not change the underlying value of canvas. As a result, even if there is a border-color that is set to red, it is not reflected on the imageData.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var image = ctx.getImageData(0, 0, canvas.height, canvas.width);
var x = tf.browser.fromPixels(image);
console.log(x.shape) // height, width, 3
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs#1.0.0"> </script>
</head>
<body>
<canvas id="canvas" width="100" height="100" style="border:1px solid #FF0000;"></canvas>
</body>
</html>

The problem was that I used ctx.strokeStyle = '#000000' (black). But the canvas is already filled with 0 (as edkeveked said). This means that the drawing is not visible. What I saw as data was probably the alpha-channel but the alpha-channel is removed by fromPixels.
The solution is to use another strokeStyle than '#000000' and/or use ctx.fillRect with fillStyle = "#FFFFFF" (white).
So fromPixels is OK...

Related

repeated path at different angle

I am working on a mandala art generator, and want to repeat the same free-drawing path at different angles.
On mouse:move, able to render it on the upper canvas. After mouse:up, it doesn't retain on lower canvas, read tried a few methods from here and on GitHub issues but none worked.
Got one possible solution, cloning the path and adding it to canvas, it's working with vanilla JS, but in react, it just modifies the existing path :(
Any help?
JavaScript solution, Fiddle (by Curtis Rock).
React solution I tried using the fiddle, Replit
var canvas = window._canvas = new fabric.Canvas('c');
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas);
canvas.isDrawingMode = true;
canvas.on({
'path:created': pathHandler
});
function pathHandler(opt) {
var path = opt.path;
path.clone(function(clone) {
canvas.add(clone.set({
left: path.left + 10,
top: path.top + 10,
angle: 90
}));
});
canvas.requestRenderAll();
}
canvas {
border: 1px solid #999;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>

Convert SVG to image in PNG

i am converting angular nvd3 chart to svg using html2canvas and canvg plugings but when i convert pie chart to png then i looks same as chart but when i convert line chart or area chart then its background goes to black and some circle drown on image.
My code is
var svgElements = $("#container").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function () {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function (index, el) {
$(this).css('font-size', getStyle(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
html2canvas($("#container"), {
onrendered: function (canvas) {
var a = document.createElement("a");
a.download = "Dashboard.png";
a.href = canvas.toDataURL("image/png");
a.click();
var imgData = canvas.toDataURL('image/png');
var doc = new jsPDF('p', 'mm','a4');
var width = doc.internal.pageSize.width;
var height = doc.internal.pageSize.height;
doc.addImage(imgData, 'PNG', 0, 0, width, height);
doc.save('Dashboard.pdf');
}
});
$("#container").find('.screenShotTempCanvas').remove();
$("#container").find('.tempHide').show().removeClass('tempHide');
Help me guys.
Thanks In Advance
Your svg elements are being styled by the external stylesheet nv.d3.min.css .
canvg seems unable to access external style sheets, so you need to append it directly in your svg node.
To do so, if your style sheet is hosted on the same domain as your scripts, you can do something like :
var sheets = document.styleSheets;
var styleStr = '';
Array.prototype.forEach.call(sheets, function(sheet){
try{ // we need a try-catch block for external stylesheets that could be there...
styleStr += Array.prototype.reduce.call(sheet.cssRules, function(a, b){
return a + b.cssText; // just concatenate all our cssRules' text
}, "");
}
catch(e){console.log(e);}
});
// create our svg nodes that will hold all these rules
var defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
var style = document.createElementNS('http://www.w3.org/2000/svg', 'style');
style.innerHTML = styleStr;
defs.appendChild(style);
// now append it in your svg node
thesvg[0].insertBefore(defs, thesvg[0].firstElementChild);
So now you can call the XMLSerializer, and canvg will be happy.
(note that this is not only a canvg limitation, the same applies for every way to draw an svg on a canvas).
Forked plunkr, where I copied the nv.d3.min.css's content to a same-origin style.css.
Very late to the conversation but I just wanted to add that the solution as described by Kaiido, put very simply, is to embed the styles into the SVG document directly.
In order to do this, you manipulate the DOM to make the SVG element look like this:
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" version="1.1">
<defs>
<style>
.rectangleStyle{
width:200px;
height:100px;
stroke:black;
stroke-width: 6;
fill: green;
}
</style>
</defs>
<rect class="rectangleStyle"/>
</svg>

How to test three.js tutorial in the View of CakePHP?

I get stuck when try to insert a demo of three.js tutorial into the view of CakePHP,
This demo (creating a scene): enter link description here
Has anybody try it like that ?
Thanks for reading . I hope you share your experiments.
Detail my problems:
I create webgl_test.js and put it into ...webroot/js/, and also put the three.min.js into webroot/js/
//------------- CREATING THE SCENE-----------------------
/* To actually be able to display anything with Three.js, we need three things:
1. A Scene
2. A Camera
3. A Renderer so we can render the scene with the camera
*/
var main=function() {
var CANVAS=document.getElementById("your_canvas");
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera (75, window.innerWidth/window.innerHeight, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({
antialias : true,
canvas : CANVAS
});
renderer.setSize(window.innerWidth, window.innerHeight);
//document.body.appendChild(renderer.domElement); //we add the renderer element to our HTML document
var geometry = new THREE.BoxGeometry (2,1,1);
var material = new THREE.MeshBasicMaterial ({color: 0x00ffff});
var cube = new THREE.Mesh (geometry, material);
scene.add(cube);
camera.position.z = 5;
//-------------RENDERING THE SCENE------------------------
function render(){
requestAnimationFrame(render);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
render();
};
In the header of default.ctp, I call script's library like that
<head>
<script type="text/javascript" src="/js/webgl_test.js"></script>
<script type="text/javascript" src="/js/three.min.js"></script>
</head>
Last step, I write some lines to show <canvas> element as below:
<div>
<ul>
<li onload='main()'>
<canvas id='your_canvas'style='position: absolute;'></canvas>
</li>
</ul>
</div>
Then, It show nothing :((

SMIL animation on SVG ng-repeat'ed element only occurs on page load

I'm generating some <rect>s with <animate> children using the ng-repeat directive.
On page load the animations are correctly triggered and everything happens as expected.
However, when I add a new <rect> the animation does not occur.
The following code snippet demonstrates this behaviour:
function Controller($scope) {
$scope.rects = [];
var spacing = 5;
var width = 10;
var height = 100;
var x = 10;
var y = 10;
$scope.newRect = function() {
$scope.rects.push({
x: x,
y: y,
width: width,
height: height
});
x += spacing + width;
};
for (var i = 0; i < 5; i++) {
$scope.newRect();
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="Controller">
<svg width="1000" height="200">
<rect ng-repeat="rect in rects" x="{{rect.x}}" y="{{rect.y}}" height="{{rect.height}}" width="{{rect.width}}">
<animate attributeName="y" from="{{rect.height}}" to="{{rect.y}}" dur="1s" repeatCount="1" />
<animate attributeName="height" from="0" to="{{rect.height}}" dur="1s" repeatCount="1" />
</rect>
</svg>
<button ng-click="newRect()">One more</button>
</div>
Upon loading the example, 4 <rect> will appear, animating from the bottom to the top. However, when pressing the "One more" button, the new <rect> will be added without animation (behaviour tested on Firefox 35 and Chrome 38).
How can I trigger the animation for the new <rect>s?
The default begin time for an animation element (equivalent to begin="0s") is always measured relative to the SVG load time. This is true even if you create the animation element dynamically after page load.
If you want any other begin time, you will need to either (a) explicitly set a different value for the begin attribute, or (b) use the beginElement() or beginElementAt(offsetTime) methods of the animation element DOM objects. Since you're creating the elements with scripts and you want them to start right after inserting them, the beginElement() method is probably the easiest approach.
Edited to add:
If beginElement isn't working because angular-js doesn't provide you with direct access to the created element, you can make use of the event format for the begin attribute. If the begin attribute contains the name of a DOM event (or a semi-colon separated list of times and event names), the animation will begin when that event occurs. By default, the event will be listened for on the element that the animation will affect—the rectangle in your case. (You can tie the animation to a different element using the elementID.eventName format).
The trick to get the animation to start as soon as it is added is to link it to one of the rarely used DOM-mutation events, specifically DOMNodeInserted. That way, when you add the animation node as a child of the <rect>, or when you add the <rect> to the SVG, the event and then the animation will be triggered immediately.
If you want a delay between inserting the element and triggering the animation, use the eventName + timeOffset format.
Here is the proof of concept with vanilla JS (as a fiddle).
And here is your modified snippet; the JS code is the same, only the angular template has changed:
function Controller($scope) {
$scope.rects = [];
var spacing = 5;
var width = 10;
var height = 100;
var x = 10;
var y = 10;
$scope.newRect = function() {
$scope.rects.push({
x: x,
y: y,
width: width,
height: height
});
x += spacing + width;
};
for (var i = 0; i < 5; i++) {
$scope.newRect();
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="Controller">
<svg width="1000" height="120">
<rect ng-repeat="rect in rects" x="{{rect.x}}" y="{{rect.y}}"
height="{{rect.height}}" width="{{rect.width}}">
<animate attributeName="y" from="{{rect.height}}" to="{{rect.y}}"
dur="1s" repeatCount="1" begin="DOMNodeInserted"/>
<animate attributeName="height" from="0" to="{{rect.height}}"
dur="1s" repeatCount="1" begin="DOMNodeInserted"/>
</rect>
</svg>
<button ng-click="newRect()">One more</button>
</div>
I'm not sure whether you intentionally want to have the bars start 10px offset from the bottom line. If that was accidental you can fix it by setting the from value of the first animation to rect.height + rect.y.
I've tested the fiddle in the latest Chrome and Firefox. If you need to support older browsers, especially if you're supporting older IE with a SMIL polyfill, you'll want to test to make sure the DOM mutation events are being thrown correctly.

Google Map v3 Ground Overlay?

I have spent two days puzzling this and failed. Any assistance will be greatly appreciated.
I need a map centered on -18.975750, 32.669184 in a canvas of 1500px x 900px. I then to need to overlay coverage PNGs (obtained form www.heywhatsthat.com) with set code- transparency.
I have eventually arrived at the following code and it fails. I would like to add more than one PNG bound by it's co-ords, but cant even get one to work.
<script src="http://maps.google.com/maps?file=api&v=3&key=AIzaSyAGbZjXr2wr7dT2P3O5pNo5wvVF3JiaopU&sensor=false"
type="text/javascript"></script>
<script type="text/javascript">
function initialize() {
if (GBrowserIsCompatible()) {
var map = new google.maps.MAP(document.getElementById("map_canvas"));
map.setCenter(new GLatLng(-18.975750, 32.669184), 13);
map.setUIToDefault();
var imageBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-19.000417,30.999583),
new google.maps.LatLng(-17.999583,32.000417));
var oldmap = new google.maps.GroundOverlay(
"http://www.earthstation.mobi/cloakpS19E031.png",imageBounds);
oldmap.setMap(map);
}
</script>
</head>
<body onload="initialize()" onunload="GUnload()">
<div id="map_canvas" style="width: 1500px; height: 900px"></div>
</body>
</html>
What am I mssing and please point me in the right direction add multiple png overlays with transparency in the options.
Thanks
Brian
Zimbabwe
You have a lot of issues with your code. It looks like you're trying to migrate from V2 to V3, and you still have V2 methods and objects in your code. You're also not loading the JS APi correctly when you call in the of your HTML.
Here is functional code that displays the overlay using the V3 API, but it looks like the original center coordinates that you used do not place the map at the center of the overlay (you'll need to figure that out yourself). I've added comments where relevant so that you can see where you went astray. Note the call to the API library in the first script tag.
<script src="http://maps.googleapis.com/maps/api/js?key=AIzaSyAGbZjXr2wr7dT2P3O5pNo5wvVF3JiaopU&sensor=false"
type="text/javascript"></script>
<script type="text/javascript">
function initialize() {
//You don't need to use GBrowserIsCompatible, it's only for V2 of the API
//if (GBrowserIsCompatible()) {
//You need to set up options for the map that you reference when you
//instantiate the map object
var myOptions = {
center: new google.maps.LatLng(-18.975750, 32.669184),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
//Your code references google.maps.MAP; it's google.maps.Map
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var imageBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(-19.000417,30.999583),
new google.maps.LatLng(-17.999583,32.000417));
var oldmap = new google.maps.GroundOverlay(
"http://www.earthstation.mobi/cloakpS19E031.png",imageBounds);
oldmap.setMap(map);
//} <--Your code was missing this closing bracket for the conditional
//But the conditional is not even needed, since GBrowserCompatible is a V2 thing
}
</script>
</head>
<body onload="initialize()">
<div id="map_canvas" style="width: 1500px; height: 900px"></div>
</body>
</html>

Resources