Dynamic canvas, "moving line" Css and/or SVG - javascript

I'm making a UI in Angular6 where I have a list that occupies the left third of the screen with selectable entries that upon selection reveal additional data of that entry.
the additional data does not move but the the selected line in the entries can because the list is scrollable and also selecting it will change which line is highlighted obviously.
I want to make it visually clear to the user that the additional data he is seeing corresponds to the entry selected in the list.
here's what I have now :
as you can see I've already helped out the user visually by highlighting the entry in the list and the whole additional data view in the same light blue
and here's my attempt at sealing the deal in terms of the view's clarity :
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="400" height="180">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.moveTo(0, 20);
ctx.lineTo(400, 180);
ctx.lineTo(400, 40);
ctx.lineTo(0, 0);
ctx.fillStyle = '#9ec7e2';
ctx.fill();
</script>
<p><strong>Note:</strong> The canvas tag is not supported in Internet Explorer 8 and earlier versions.</p>
</body>
</html>
But I'm facing here a challenge I've never faced before : I need it to be dynamic and fluid.
I know I could JQuery-watch both select and scroll and also JQuery get X-Y coordinates of top and bottom corners of relevant divs, then redraw the canvas on every scroll and select call but that sounds extra poor performance-wise, and with a high probability of flashing (re-draws) while I scroll.
not to mention this all sounds extra clunky and poor execution,
Plus I'm fairly certain any resizing of the window or any other easy test would break the illusion.
Isn't there a new more "CSS3-SASS-SVG-Angular6" approach?

Related

How to remove a drawn arch from canvas

I have been trying to print arc in the html page. How can i remove the already drawn arch from the page?. i have written the below code.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="1200" height="1000"
style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
/*ctx.beginPath();
ctx.arc(600,500,20, 0.5*Math.PI,2*Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(600,500,40, 0.5*Math.PI,2*Math.PI);
ctx.stroke();
*/
var radius=20;
for (i=0; i<10; i++)
{
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(600,500,radius, 0.5*Math.PI, 2*Math.PI);
ctx.stroke();
radius= radius+30;
}
</script>
</body>
</html>
How can i achieve this?.
Call clearRect method:
ctx.clearRect(0, 0, 1200, 1000)
The four arguments are:
axis-X of left top corner of the area to wipe
axis-Y of left top corner of the area to wipe
width of the area to wipe
height of the area to wipe
So with this method, you could wipe either the whole canvas or just a certain part of it.
If you want to remove the whole previously drawn image please take a look at the other anwers. In the comments OP made it clear that this is not what he was trying to achieve. So instead I will answer the intended question:
How do I un-stroke a path?
A bitmap is not a vector graphic. You cannot simply remove or modify things you've drawn previously. By drawing on a canvas you modify the pixel color values of its image data. If you need to undo things you have to maintain a separate data structure with the relevant data yourself.
For example you could create a copy of the image data before drawing something. Then you could return to this snapshot afterwards. HTMLCanvasElement#toDataURL returns the complete image as an url which you can use as the src of an image. Later you can draw this image on the canvas to revert all subsequent changes. HTMLCanvasElement#toBlob does about the same but it returns a blob. This might consume less memory but it's a little more inconvenient to use. The most convenient method is CanvasRenderingContext2D#getImageData. You can even use it to copy only a small part of the image. This is useful if you have a big canvas but only modify pixels in a small region.
Another way to make modifications undoable is by maintaining a detailed list of your steps. For example whenever you draw an arc you store the exact parameters as one entry in the list. steps.push({type: 'stroke', style: 'rgb(0,0,0)', shapes: [{type: 'arc', x: 600, y: 500, radius: radius, from: 0.5 * Math.PI, to: 2 * Math.PI}]}) You can remove, rearrange or modify the elements in this list any way you like and have all necessary information to draw the resulting image from scratch. Basically you've implemented just another vector graphic library.

Copy user selection from one canvas to another

I'm trying to implement a simple, select area on canvasA and then copy area to canvasB, I've got the selection part working but the drawing of the copied area doesn't want to work. The idea is that the user will select an area and then that selection will appear on another canvas when they finish the selection, i.e. say mousedown, drag rectangular area, mouseup (copy appears)
I confess I'm not much of a front end developer so fear I'm missing something obvious about how this stuff works as I'm just trying to knock something together to prove a concept and understand the basics at the moment.
JSFiddle is here - http://jsfiddle.net/bw4gw83a/2
HTML
<canvas id="original" width=300 height=300></canvas>
<canvas id="copybit" width=300 height=300></canvas>
Javascript
var original = document.getElementById("original");
var CTXoriginal = original.getContext("2d");
var copybit = document.getElementById("copybit");
var CTXcopybit = copybit.getContext("2d");
var background = new Image();
background.src = "https://i.imgur.com/F1pJYM1.jpg";
background.onload = function(){
CTXoriginal.drawImage(background, 0, 0)
}
var imageData = CTXoriginal.getImageData(10, 10, 100, 100);
CTXcopybit.putImageData(imageData,0,0);
Any pointers appreciated.
Si
The following guide might be helpful.
http://www.i-programmer.info/programming/graphics-and-imaging/2078-canvas-bitmap-operations-bitblt-in-javascript.html
It mentions you can draw a section of the image using
drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh)
Where s is source, and d is destination.
From there you just have to determine the position of the click and drag to work out the co-ordinates and width/heights.
I've updated your fiddle just to demonstrate. It's very crude, so just click once somewhere in the top left of the image, then click again somewhere in the bottom right.
http://jsfiddle.net/treerock/1zpc8fz0/

html canvas-color and images

I'm trying to make a menubar type of thing for my website.
I tried google but idk what I should search on...
I want it to be a kind of rainbow and when the user hovers over it the bar should expand and it should give a short description of the page they will be going to.
I did it with and javascript:
<canvas id="purple" width="50" height="400"></canvas>
js:
var canvas = document.getElementById('purple');
var context = canvas.getContext('2d');
context.beginPath();
context.rect(0, 0, 100, 500);
context.fillStyle = 'purple';
context.fill();
context.lineWidth = 0;
context.strokeStyle = 'none';
context.stroke();
and that with all 6 colors.
No problem so far for me.
But now I want to put in the text... But I keep failing.
This is my JSFiddle:
http://jsfiddle.net/gY9wk/
should I keep using or something else?
O and another question: Can I remove the white spaces between the bars?
This is less important than the first question but just asking...
Thanks in advance!
Robin van der Noord.
Using canvas for something like that might be a little bit too expensive.
There are two ways to create text on them - using canvas to draw text or using another HTML element on top of each canvas and put the text in it. I recommend the latter. Here is an example using a div container and a span inside it (as a canvas sibling) to show the text: http://jsfiddle.net/gY9wk/9/ (added a few effects to make it look nicer)
The new structure is this:
<div class="item">
<canvas id="red" width="50" height="400"></canvas>
<span>Hey there</span>
<p>This is a description</p>
</div>
Again, I'd recommend not to use canvases for backgrounds as they are too heavy. A simple 1px-high horizontal line with repeat-y property would do the trick and would look identical. And I especially don't recommend using canvas to render text, not just for the reasons mentioned above, but for SEO as well (web crawlers won't see the canvas-rendered text).
Of course, if you plan to create some animations, then the canvas is the way to go.
And here's an example how to render text on canvas (see the purple one) if you still want to do it: http://jsfiddle.net/gY9wk/10/.
Bear in mind that CSS resizing will stretch whatever is rendered on canvas, and changing the width or height attributes of the canvas element will clear the canvas and you'd need to rerender whatever was on it.
context.fillStyle = 'red';
context.font = "16px Arial";
context.lineWidth = 4;
context.fillText("Hey, I'm rendered on canvas", 30, 30);
Second question, the white space is coming from canvases being displayed inline by default. The easiest way is to set them to:
canvas {display: block;}
and to remove the line break elements (brs).
Like this: http://jsfiddle.net/gY9wk/5/

Problems clearing canvas when animating a clipping region

I'm trying to accomplish an effect similar to what you might see on the cartoon Chowder (example link) , where shapes serve as masking layers for a texture underneath that stays static. I've begun playing around with this idea by creating a render loop that clears the canvas, saves it's state, then draws a rectangular clipping region, followed by drawing the background texture that occupies the entire width and height of the canvas.
Here's the draw function:
function draw()
{
context.clearRect(0,0, 640, 480);
context.save();
x += velocityX;
y += velocityY;
context.rect(x, y, 40, 40);
context.clip();
context.drawImage(image, 0,0, 640, 480);
context.restore();
}
Basically it just runs at 60 frames per second, updating the position of the rectangle and clipping a background image inside the clipping region. (I know the code isn't structured perfectly, but I was just experimenting to see if this effect was even possible on the canvas).
http://jsfiddle.net/JERje/86/
The problem I seem to be having is that the clipping area from the previous iteration of the loop hangs around creating the weird effect that you see in the fiddle above. I've tried reordering everything in the draw() step of the loop, but the only thing that seems to work is the canvas.width = canvas.width trick for clearing the screen. I'd like to avoid this method of clearing the screen, since it doesn't seem to work in IE, and it also destroys the canvas state. clearRect() should work to clear the screen. What am I doing wrong?
You're using the same HTML5 Canvas paperback I am aren't you.
If you set up an adhoc canvas as I did on your jsfiddle like so:
var newCanvas = document.createElement('canvas');
newCanvas.getContext("2d").drawImage(image,0,0);
A function such as this would be able to hack a section out of that canvas:
context.putImageData(newCanvas.getContext("2d").getImageData(x,y,40,40),x,y);
Thus giving you the chowder effect. Good show man, good luck. Pst me if it doesn't work
EDIT: However this solution will ignore some context scaling transformations. Just be smart about how you handle scale on your own (and you really should be anyways if you want the true "chowder" effect)
So, feel pretty dumb about this, but apparently when you call rect() you also have to make sure to call closePath afterwards in order to close the clipping area. Glad I figured it out finally, now on to adding multiple layers!
Here's the working fiddle: http://jsfiddle.net/JERje/129/

Can canvas context.fillText be made crisp (because context.translate 0.5/0.5 doesn't)

I've tried to search through StackOverflow for a similar question, but I seem to only be able to find questions that are either "how do I draw text in <canvas>" (answer: fillText) or "how do I make crisp lines" (answer, 0.5 coordinate offsets, because canvas isn't an integer pixel grid), neither of which answer my question. Which is the following:
How do I get fillText to render text as crisp as the browser renders text as part of a normal page?
As a demonstration, take the page on http://processingjs.nihongoresources.com/fontreftest/crisptest, which uses the following html+js (using html5 doctype):
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>fillText</title>
<style type="text/css">
canvas { margin: 0px; padding: 0px; display: block; }
</style>
</head>
<body>
<table><tr><td style="font: normal normal 400 12px/14px Arial">
<div>This is some text in Arial.</div><div>This is some text in Arial.</div>
<div>This is some text in Arial.</div><div>This is some text in Arial.</div>
<div>This is some text in Arial.</div><div>This is some text in Arial.</div>
<div>This is some text in Arial.</div><div>This is some text in Arial.</div>
<div>This is some text in Arial.</div><div>This is some text in Arial.</div>
</td><td>
<canvas id="filltext0"></canvas><canvas id="filltext1"></canvas>
<canvas id="filltext2"></canvas><canvas id="filltext3"></canvas>
<canvas id="filltext4"></canvas><canvas id="filltext5"></canvas>
<canvas id="filltext6"></canvas><canvas id="filltext7"></canvas>
<canvas id="filltext8"></canvas><canvas id="filltext9"></canvas>
</td><tr></table>
<script type="text/javascript"><!--
function drawTextIn(which)
{
var tstring = "This is some text in Arial",
canvas = document.getElementById('filltext' + which),
context = canvas.getContext("2d");
var fontCSS = "normal normal 400 12px/14px Arial";
context.font = fontCSS;
canvas.width = context.measureText(tstring).width;
canvas.height = 14;
// setting the width resets the context, so force the font again
context.font = fontCSS;
context.fillText(tstring,0 + i/10,12);
}
for(var i=0; i<10; i++) { drawTextIn(i); }
--></script>
</body>
</html>
This will generate a side-by-side view of ten lines rendered by the browser in Arial at 12px with a lineheight (size+leading) of 14px, in normal style and weight, and ten lines rendered with the same font properties using <canvas> elements, with every line calling fillText with a 0.1 shifted x-coordinate. The first line has x coordinate 0, the second 0.1, the third 0.2, etc.
No current browser that supports <canvas> that I have tried (Chrome 12, Firefox 5, Opera 11.50, Internet Explorer 9, Safari 5) renders the text the same as real text, regardless of x-coordinate shift.
So the main thing I'm now wondering is whether or not there exists a (normal, fast) way to make a browser draw text to a <canvas> with the same crispness as it draws text to the page when it's just placing text.
I've read http://diveintohtml5.ep.io/canvas.html#text, http://blog.thesoftwarefactory.be/2009/04/drawing-crisp-lines-on-html5-canvas.html, http://joubert.posterous.com/crisp-html-5-canvas-text-on-mobile-phones-and, and http://www.bel.fi/~alankila/lcd/ - none of these cover the subject. The last offers an interesting approach, but one that can only be used if the canvas is empty, which is too limited to be of real-world use, neat as it is (it's too expensive to construct a new canvas for every line of text, call fillTExt and then clean it up using scanlines, and then copy the text over with alpha blending).
So.... can this be done? If you know how, I'd really, really like to know how to achieve this. And if you think the answer is no: please, include links to official specs that demonstrate why that answer is the right answer... I need the peace of mind of an official spec saying I can't do what I want, or I'll just keep wondering whether some even smarter person might have answered this question with "yes" =P
So the main thing I'm now wondering is whether or not there exists a (normal, fast) way to make a browser draw text to a with the same crispness as it draws text to the page when it's just placing text.
The short answer is sadly no. Different browsers are currently implementing subpixel rendering/anti-aliasing for text in wildly different ways, which leads to (for some browsers) their rendered HTML page text looking good but their Canvas text looking awful.
One possibility is to pre-render all of your text (Even if that means writing it on an HTML page and taking a screenshot) and using drawImage. This also has the benefit of being much faster than calls to drawText, but of course is not very dynamic at all.
While the question is old, I came across the exact same issue. While digging in FireFox, I found a flag for canvas which did the trick: mozOpaque. When set, the font uses the correct LCD rendering and the text is crisp as other elements on the page. To test it, just put:
canvas.mozOpaque = true;
after your canvas creation. There is a catch: the canvas can't be transparent anymore, but it wasn't an issue for my use. May be Chrome/Safari/IE got something similar. I hope this helps !

Categories