How to Style Canvas Elements with CSS

How to style canvas elements with CSS

I'm a bit late for the party but I just had the same scenario and I solved it like this:

// "Cache"
var classColors = {};

function getColor(className) {
// Check for the color
if (!classColors[className]) {

// Create an element with the class name and add it to the dom
$c = $('<div class="' + className + '"></div>').css('display', 'none');
$(document.body).append($c);

// Get color from dom and put it in the color cache
classColors[className] = $c.css('color');

// Remove the element from the dom again
$c.remove();
}

// Return color
return classColors[className];
}

I only needed the color but you can extend the cache object to hold more than color if you want. The you'd return a full object from the function. The below code is not tested at all:

var classProperties = {};

function getPropeties(className) {
// Check for the properties object
if (!classProperties[className]) {

// Create an element with the class name and add it to the dom
$c = $('<div class="' + className + '"></div>').css('display', 'none');
$(document.body).append($c);

// Get needed stuff from the dom and put it in the cache
// P.S. Didn't test if canvas names are the same as css names.
// If not you'll have to translate it
classProperties[className] = {
fillStyle: $c.css('color'),
lineWidth: $c.css('border-width'),
strokeStyle: $c.css('border-style')
}

// Remove the element from the dom again
$c.remove();
}

// Return properties
return classProperties[className];
}

Using CSS to style elements drawn to a canvas

Warning

This answer should be removed but as it has been accepted I am unable to. Below is the answer as is, but there are a host of problems and browser compatibility issues, making this answer impractical.

SVG markup for canvas

If you use SVG images to render to the canvas you can add CSS style rules to the elements within the SVG and as long as you continue to render the SVG it will reflect all the rules, including animations and other time based FX.

SVG markup with CSS

<!-- within the SVG element -->
<svg>
<style>
/* CSS */
#buttonWhite { /* ID name */
fill:white;
font-size:12px;
}
#buttonBlue {
fill:blue;
font-size:16px;
}
</style>
<text id="buttonWhite" x="100" y="100">I am white</text>
<text id="buttonBlue" x="100" y="200">I am blue</text>
</svg>

Script

// within the script
var svg = new Image();
svg.src = "SVG_URL.svg";

// once svg has loaded then display it on the canvas
ctx.drawImage(svg,0,0);

If you make changes to the CSS or SVG you need to rerender it to see the changes.

UPDATE

For more information on linking in CSS see MDN SVG & CSS

I had made a mistake in the CSS forgetting that SVG has its own styles. I have corrected it by replacing color with fill.

Applying CSS on drawn Canvas Elements

You can't apply CSS to elements drawn in the canvas, because they don't exist on the DOM. It's just as if they were a bitmap image.

You could use an SVG circle though, which will allow you to style the circle with CSS and use animations:

<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>

How to make canvas responsive

To change width is not that hard. Just remove the width attribute from the tag and add width: 100%; in the css for #canvas

#canvas{
border: solid 1px blue;
width: 100%;
}

Changing height is a bit harder: you need javascript. I have used jQuery because i'm more comfortable with.

you need to remove the height attribute from the canvas tag and add this script:

  <script>
function resize(){
$("#canvas").outerHeight($(window).height()-$("#canvas").offset().top- Math.abs($("#canvas").outerHeight(true) - $("#canvas").outerHeight()));
}
$(document).ready(function(){
resize();
$(window).on("resize", function(){
resize();
});
});
</script>

You can see this fiddle: https://jsfiddle.net/1a11p3ng/3/

EDIT:

To answer your second question. You need javascript

0) First of all i changed your #border id into a class since ids must be unique for an element inside an html page (you can't have 2 tags with the same id)

.border{
border: solid 1px black;
}

#canvas{
border: solid 1px blue;
width: 100%;
}

1) Changed your HTML to add ids where needed, two inputs and a button to set the values

<div class="row">
<div class="col-xs-2 col-sm-2 border">content left</div>
<div class="col-xs-6 col-sm-6 border" id="main-content">
<div class="row">
<div class="col-xs-6">
Width <input id="w-input" type="number" class="form-control">
</div>
<div class="col-xs-6">
Height <input id="h-input" type="number" class="form-control">
</div>
<div class="col-xs-12 text-right" style="padding: 3px;">
<button id="set-size" class="btn btn-primary">Set</button>
</div>
</div>
canvas
<canvas id="canvas"></canvas>

</div>
<div class="col-xs-2 col-sm-2 border">content right</div>
</div>

2) Set the canvas height and width so that it fits inside the container

$("#canvas").outerHeight($(window).height()-$("#canvas").offset().top-Math.abs( $("#canvas").outerHeight(true) - $("#canvas").outerHeight()));

3) Set the values of the width and height forms

$("#h-input").val($("#canvas").outerHeight());
$("#w-input").val($("#canvas").outerWidth());

4) Finally, whenever you click on the button you set the canvas width and height to the values set. If the width value is bigger than the container's width then it will resize the canvas to the container's width instead (otherwise it will break your layout)

    $("#set-size").click(function(){
$("#canvas").outerHeight($("#h-input").val());
$("#canvas").outerWidth(Math.min($("#w-input").val(), $("#main-content").width()));
});

See a full example here https://jsfiddle.net/1a11p3ng/7/

UPDATE 2:

To have full control over the width you can use this:

<div class="container-fluid">
<div class="row">
<div class="col-xs-2 border">content left</div>
<div class="col-xs-8 border" id="main-content">
<div class="row">
<div class="col-xs-6">
Width <input id="w-input" type="number" class="form-control">
</div>
<div class="col-xs-6">
Height <input id="h-input" type="number" class="form-control">
</div>
<div class="col-xs-12 text-right" style="padding: 3px;">
<button id="set-size" class="btn btn-primary">Set</button>
</div>
</div>
canvas
<canvas id="canvas">

</canvas>

</div>
<div class="col-xs-2 border">content right</div>
</div>
</div>
<script>
$(document).ready(function(){
$("#canvas").outerHeight($(window).height()-$("#canvas").offset().top-Math.abs( $("#canvas").outerHeight(true) - $("#canvas").outerHeight()));
$("#h-input").val($("#canvas").outerHeight());
$("#w-input").val($("#canvas").outerWidth());
$("#set-size").click(function(){
$("#canvas").outerHeight($("#h-input").val());
$("#main-content").width($("#w-input").val());
$("#canvas").outerWidth($("#main-content").width());
});
});
</script>

https://jsfiddle.net/1a11p3ng/8/

the content left and content right columns will move above and belove the central div if the width is too high, but this can't be helped if you are using bootstrap. This is not, however, what responsive means. a truly responsive site will adapt its size to the user screen to keep the layout as you have intended without any external input, letting the user set any size which may break your layout does not mean making a responsive site.

Add style to elements inside HTML5 canvas

Setting CSS styles only affects elements, here the image element.

When you draw the image to canvas you don't draw the element but the image's bitmap. Canvas is just that, a bitmap and is not related to CSS or DOM per-SE (it's a DOM element but everything that happens inside it is "low-level" bitmap manipulation).

To simulate border for an image drawn to canvas you can draw it on top:

context.drawImage(image, 5, 5);
context.lineWidth = 3;
context.strokeStyle = '#00f';
context.strokeRect(5, 5, image.width, image.height);

(offset the x and y position by 0.5 pixel to make the border sharp).

Modified fiddle

PS: Also remember to handle image loading properly using the onload handler as loading images is asynchronous (updated fiddle with this as well).

Giving maximum height and width equally to canvas in HTML/CSS

The easiest solution is to use display:flex; on the preview container and set the height using vh (view height) units. The defaults will cause the children canvases to stretch to fill the height, and you can then choose how to align them. They are set to justify-content: space-around; in the below snippet which evenly divides any free space on both sides of the children elements.

#previewWrapper {
height: 85vh;
display: flex;
justify-content:space-around;
}

canvas {
width: 46vw;
}

body {
margin: 0;
}

header {
margin: 0;
background-color: #DC0A2F;
height: 50px;
}

header img.logo {
width: 150px;
height: auto;
padding: 13px 13px 0px 13px;
}

header a {
color: white;
text-decoration: none;
float: right;
padding: 15px;
font-family: Consolas;
font-weight: revert;
}

header a:hover {
padding-top: 16px;
}

html,
body {
height: 100%;
}

main {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
height: 90vh;
}

main.index {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
color: #888888;
}

main img.menu {
width: 250px;
height: auto;
padding: 50px;
}

table {
font-size: 130%;
}

th {
background-color: #888888;
border-color: white;
}

td {
background-color: white;
border-bottom: solid 1px #888888;
border-right: solid 1px #888888;
}

img.index {
width: 400px;
height: auto;
}

.ergebniss {
margin: 50px;
}

svg.header {
width: 125px;
height: 30px;
margin-top: 10px;
}

.vorschau {
margin: 100px;
}

canvas{ border: 1px solid black; background-color: red;}

.footPreviewContainer {
height: 800px;
text-align: center;
}

#previewWrapper {
height: 85vh;
display: flex;
justify-content:space-around;
}

canvas {
width: 46vw;
}
<html>

<head>
<title>WebSocket Echo Client</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
<div class="fitToPage" id="canvas"></div>
<header>
<img class="logo" src="./content/GUI/logo_weiss.svg" alt="Elten Logo" onclick="goHome();" />
<a href="#Herunterfahren">Herunterfahren</a>
<a href="#Neustart">Neustart</a>
</header>

<!-- HERE IS THE ISSURE -->

<div id="previewWrapper" class="footPreviewContainer">
<canvas id="leftCanvas"></canvas>
<canvas id="rightCanvas"></canvas>
</div>

<div class="previewButtons">
<img id="actionButtonPreview" class="logo" src="./content/GUI/button_preview.svg" alt="Vermessungsbutton" onclick="initWebSocket();">
<img id="actionButtonStop" class="logo" src="./content/GUI/button_messen.svg" alt="Vermessungsbutton" onclick="stopWebSocket();">
<img id="actionButtonMeasure" class="logo" src="./content/GUI/button_messen.svg" alt="Vermessungsbutton" onclick="checkSocket();">
<img id="actionButtonSendMessage" class="logo" src="./content/GUI/button_messen.svg" alt="Vermessungsbutton" onclick="sendMessage();">
</div>

</body>

</html>


Related Topics



Leave a reply



Submit