Test a Chart.js canvas with Protractor - javascript

I'm fairly new to protractor so sorry if this is a stupid question. I'm looking into testing an application and need test the values inside a Chart.js graph.
Has anyone got any ideas on how to get my protractor program to look inside the canvas.
This is the canvas output in HTML.
<canvas id="test"
class="chart chart-line ng-isolate-scope"
data="test.data"
labels="test.labels"
series="test.series"
legend="true"
options="test.options"
colours="test.colours"
width="1816"
height="800"
style="width: 908px;
height: 400px;">
</canvas>
Thanks in advance.

I think you may get the underlying chart data, by evaluating in the canvas's context. Example:
var canvas = element(by.css("canvas#test[data]"));
canvas.evaluate("test.data").then(function (data) {
console.log(data);
});

Protractor can get attributes of the canvas, but it can't access object created within it. But it depends what you're looking to do. Strategies for canvas testing might include image diffs, and string diffs, and often make use of browser.actions for manipulating them.

Related

Object to canvas javascript

I'm testing javascript on a smart TV,
I try to get an object video to canvas. With html5 video tag it works in my browser, but not my smart TV.
But when I try with an object player, I have this error message :
Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The
provided value is not of type '(HTMLImageElement or HTMLVideoElement
or HTMLCanvasElement or ImageBitmap)'
after multiple test with (id, object id,object src..) the result is same, i don't know how i can get an Object video to a canvas.
here's a simple html test:
<canvas id="test" width="300" height="300"></canvas>
<div id="test" style="left: 0%; top: 0%; width: 25%; height: 25%; position: fixed;">
<object type="application/avplayer" style="width: 480px; height: 270px;"></object>
</div>
and the js:
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const video = document.getElementsByTagName('object');
//const video = document.getElementsById('idVideo');
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
Here's an example of my goal but i can't use video tag : http://jsfiddle.net/on1kh4o0/
Any idea or hack to get the same result with an object?
You can't draw an HTMLObjectElement (<object>) directly on a canvas, it is not defined as a CanvasImageSource.
For info, currently the only objects that are defined as being of this type are
HTMLImageElement
SVGImageElement
HTMLVideoElement
HTMLCanvasElement
ImageBitmap
OffscreenCanvas
And even though it's still only part of a draft specs, it is expected that CSSImageValue also gets added to this list.
But HTMLObjectElement is not part of this list, and certainly will never be.
Indeed, even though you can load a video or an image in an <object>, just like with an <iframe>, you can also load a text or an HTML document or many other document types which can't be drawn on a canvas.
Now to your issue, as has been pointed out in the comments, you are definitely facing an XY problem.
Using a video element is currently the only way to draw a video on a canvas (maybe in the future we'll be able to use the Web-Codecs API too, but that's for the future).
So try to find out why your browser doesn't want to draw this video on the canvas.
Try different videos, from different sources, back in the days some Android browsers were blocking drawing any cross-origin mp4 video on a canvas, maybe you are facing a similar issue, if you can, try to input the video from an <input type="file">.
And if your browser has debugging tools, use them. (For instance if it's based on chromium, you should be able to navigate to chrome://media-internals/ or chrome://inspect which might be bale to lead you to some logs.
But anyway, using an <object> as source here won't help you.

How do you get code like this to run in JsFiddle.net?

I'm looking at sample code on how to draw shapes using only JavaScript.
I'm trying to test this sample code in JSFiddle.net, and while hitting 'Run' doesn't produce any errors, the result is completely blank.
Does anyone know how to make something actually appear on the screen in JsFiddle.net?
draw = function() {
//sky
background(172, 238, 247);
//ground
fill(95, 156, 83);
rect(0, 350, 400, 50);
};
draw();
Link to non-working Fiddle:
https://jsfiddle.net/skdopL1b/
So the way javascript works with HTML to draw things is through the Canvas API. First you have to contextualization and establish interactions between JS code and <canvas> element. This is done with built in function and then a little bit of code to make it short-hand.
<html>
<canvas id="canvas" width="500" height="400"></canvas>
<script>
const c = document.getElementById("canvas"); //Grab canvas element to use as object
const ctx = c.getContext('2d'); //Function that enable the 2d functions of Canvas API
ctx.fillRect(0,0,10,10) //Example of ctx function
<script>
</html>
From the JS Fiddle you gave us, It looks like you probably copied functions from a video that pre-established these function as they are not normal canvas function but custom functions. I can show you example of how to write one of these custom functions
function background(red,green,blue) {
ctx.fillStyle = 'rgb('+red+','+green+','+blue+')';;
ctx.fillRect(0,0,c.width,c.height); //Makes a rectangle the size of the canvas
}
background(172,238,247); //Creates a canvas sized rectangle with rgb(172,238,247)
You will have to either find his function declarations or write your own (or just use the raw canvas functions) to work with the javascript this way. You also need to define a canvas element with an ID. Lucky for you Im working on making a JSFiddle that works for you since you seem fairly new to this whole HTML5/JS thing.
-------EDIT-------
Heres your fiddle link friend, I included comments to help you understand everything https://jsfiddle.net/xwqg1cez/2/

How to manage memory in case of multiple fabric js canvas?

In my application, I have multiple Fabric.js canvases, There is no limit on the number of canvases. I'll render heavy JSON via loadFromJson method of Fabric.js.
So I want to release the fabric object memory if the canvas is not in use. How can I do that?
At a time only one canvas will be visible. But I have to render all the canvases as the page loads. Canvas is actually a page and user can switch between pages via clicking on page number or something else.
Remember user can come back to any canvas any time and try to doodle or use any other Fabric.js functionality.
Here is my HTML structure:
<style>
.fabricCanvas {
border: 1px solid green;
margin: 5px;
}
.canvas-container {
margin: 5px;
}
</style>
<canvas class="fabricCanvas" width="300" height="300"></canvas>
<canvas class="fabricCanvas" width="300" height="300"></canvas>
<canvas class="fabricCanvas" width="300" height="300"></canvas>
<canvas class="fabricCanvas" width="300" height="300"></canvas>
My JS code to store fabric instances
var canvasInstances = [];
$('canvas.fabricCanvas').each(function () {
var fabricCanvasObj = new fabric.Canvas(this, {
isDrawingMode: true
});
canvasInstances.push(fabricCanvasObj);
fabricCanvasObj.renderAll();
});
console.log(canvasInstances[0]);
I am storing instances so that I can use them later. I want this for better memory management, basically loading and unloading instances as and when needed.
Sample situation DEMO is here. In this demo consider that the canvases are over each other using z-indexes but they are the part of DOM and has already been rendered on page load.
Let me know in case of any doubt, I can explain further.
When ever there are more than 5 canvases iPad browser crashes which I think is the memory issue.
You might be interested in 3 things (in the order of significance/destruction):
canvas.clear() — removes all canvas objects from it.
canvas.dispose() — removes all canvas objects AND removes all event listeners
$(canvas.wrapperEl).remove() (using jQuery for illustrative purposes) — to remove canvas wrapper element (which contains upper and lower canvases used by Fabric). This can be done AFTER you call dispose, if the goal is to completely remove Fabric canvas from a document.

best practice for creating a canvas element

I've been experimenting with creating a canvas element in a few different ways and was wondering if anyone knows which of these (or some other) ways is the most efficient.
the most basic seems to be placing a canvas element in the html like this:
<canvas id="myCanvas" width="500", height="500"></canvas>
and then in the javascript:
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
there are times I need to keep all my canvas biznass in a .js file (ex when I want to dynamically change the width/height of the element) and I'll do it like this:
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.height = '500';
canvas.width = '500';
var ctx = canvas.getContext('2d');
or when I get lazy, something like this:
document.write("<canvas id='myCanvas' width='500', height='500'></canvas>");
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
Pros? Cons? Edits? Other options?
The first one is the best by far.
The first one wins on efficiency (slightly) because the second and third ones cause the page to re-layout unnecessarily. Also, if there's an error in the JavaScript that halts subsequent execution the page will look awfully weird.
Furthermore, you should always choose the first one for accessibility purposes. If someone has JavaScript disabled you will still want them to see the fallback content. Even if it is just to say "turn on JavaScript!" or "Get a modern browser!"
If you use the second or third method, the user might never know, and they will continue on merely thinking that you suck at page layouts because there's a strange space where fallback content (or a canvas for that matter) ought to be.
Even aside from all that, methods 2 and 3 break the order of things a little bit. When are you adding the canvas? after onload fires? Well by firing onload the page just said that the DOM was done doing it's dance and its all ready! And then you go and change the DOM!
...How rude!
Of course you probably won't be using any libraries that rely on the the implicit promise made in onload that you are sorta breaking by using 2 or 3, but it's an unnecessary break of convention if you can avoid it.
By the way for the start of simple apps or examples I have this fiddle bookmarked:
http://jsfiddle.net/eAVMs/
Which uses the first method. If you use canvas a lot, you should bookmark this fiddle too!
document.write("<canvas id='myCanvas' width='500', height='500'></canvas>");
Is the only method Id caution against. Using document.write is generally considered bad practice for arbitrarily creating elements.
I could just repeat why here, but this answer explains it well enough.
The other two methods are perfectly valid and fine. Its really just a matter of preference. Generally I create a canvas tag, unless I need a temp canvas to do something, in which Ill use the createElement method.
Other than that its really just a matter of preference and overall doesn't affect performance in any way.

arbor.js for annotated illustration

I'm hoping to use arbor.js as a way of creating annotated illustrations.
The plan:
Fixed size canvas
Draw image to canvas – as an example i've used the silhouette of head.
Then have a mixture of fixed and floating nodes.
var data = {
nodes:{
brain-position:{},
brain-text:{'color':'green','shape':'dot','label':'brain'},
mouth-position:{},
mouth-text{'color':'green','shape':'dot','label':'mouth'},
},
edges:{
brain-position:{ brain-text },
mouth-position:{mouth-text}
}
};
sys.graft(data);
The problems i'm having is that when I try to create a statically positioned nodeBox eg.
nodeBoxes[node.name] = [50,50, w,w] it breaks the link to other linked nodes.
I'm tinkering with halfvis/src/renderer.js file from the downloaded arbor file.
Many thanks
EDIT
Below is an additional image that hopefully visualises the functionality I'm attempting. Probably should have done this first :)
nodeBoxes, in the halfvis example, is an array used to work out where to start drawing edges so the arrows don't overlap with the boxes - is that what you're using it for?
Are you trying to find a way of forcing the 'brain-position' node inside an area?
Please provide a bit more detail of what you're planning and we can probably do this.

Categories