SVG text element height/width inside of display:none container - d3.js

I've got an SVG that is being drawn inside of a div that has css of display:none. I need to center some of the rendered text elements, and to do this, I need the height and width. Unfortunately, when the containing html element is set to display:none, I always get 0 for height, and width. getBBox(), clientWidth, getComputedTextLength() methods all return zero. My question is: how can text width be calculated under these conditions?
e.g.
<div style='display:none;'>
<svg><g><text>some text</text></g></svg>
</div>

Have you tried setting the <div> to visibility: hidden;?
You may also want to make it position: absolute; so it doesn't affect the layout of other items on the page.

Related

Ensure amCharts bubble chart area is square

When creating a bubble chart, such as https://www.amcharts.com/demos/bubble-chart/, is it possible to ensure the chart area/grid is square without specifying the chart div width and height? I'm hoping it could be somewhat responsive. No matter what the window size, the chart 's grid is square. It would need to take into consideration any axis labels.
I'm using React/TypeScript. Thanks!
After struggling with amchart settings to no avail, the following solution works. However, seems like there should be away to do in with chart settings.
This article explains how to maintain a specific aspect ratio for images. I simply adopted it for the bubble chart.
<div style={{ position: 'relative', paddingTop: '93%' }}>
<div id={chartId} style={{ position: 'absolute', top: 0, left: 0, height: '100%', width: '100%' }}></div>
</div>
Create a container div with relative positioning and the top padding to the correct aspect ratio
Create the chart div as a child with absolute positioning
Render the page
Take a screenshot, paste it in your favorite image editor
Measure the pixels
Recalculate the top padding
For my chart, which has axis text on the left and bottom, 93% was perfect. Now, no matter the page width or device, the grid is always square. HTH.

With canvas, ctx.lineTo draws a longer "Y" line than instructed (160 instead of 120) [duplicate]

I have 2 canvases, one uses HTML attributes width and height to size it, the other uses CSS:
<canvas id="compteur1" width="300" height="300" onmousedown="compteurClick(this.id);"></canvas>
<canvas id="compteur2" style="width: 300px; height: 300px;" onmousedown="compteurClick(this.id);"></canvas>
Compteur1 displays like it should, but not compteur2. The content is drawn using JavaScript on a 300x300 canvas.
Why is there a display difference?
It seems that the width and height attributes determine the width or height of the canvas’s coordinate system, whereas the CSS properties just determine the size of the box in which it will be shown.
This is explained in the HTML specification:
The canvas element has two attributes to control the size of the element’s bitmap: width and height. These attributes, when specified, must have values that are valid non-negative integers. The rules for parsing non-negative integers must be used to obtain their numeric values. If an attribute is missing, or if parsing its value returns an error, then the default value must be used instead. The width attribute defaults to 300, and the height attribute defaults to 150.
To set the width and height on a canvas, you may use:
canvasObject.setAttribute('width', '150');
canvasObject.setAttribute('height', '300');
For <canvas> elements, the CSS rules for width and height set the actual size of the canvas element that will be drawn to the page. On the other hand, the HTML attributes of width and height set the size of the coordinate system or 'grid' that the canvas API will use.
For example, consider this (jsfiddle):
var ctx = document.getElementById('canvas1').getContext('2d');
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 30, 30);
var ctx2 = document.getElementById('canvas2').getContext('2d');
ctx2.fillStyle = "red";
ctx2.fillRect(10, 10, 30, 30);
canvas {
border: 1px solid black;
}
<canvas id="canvas1" style="width: 50px; height: 100px;" height="50" width="100"></canvas>
<canvas id="canvas2" style="width: 100px; height: 100px;" height="50" width="100"></canvas>
Both have had the same thing drawn on them relative to the internal coordinates of the canvas element. But in the second canvas, the red rectangle will be twice as wide because the canvas as a whole is being stretched across a bigger area by the CSS rules.
Note: If the CSS rules for width and/or height aren't specified then the browser will use the HTML attributes to size the element such that 1 unit of these values equals 1px on the page. If these attributes aren't specified then they will default to a width of 300 and a height of 150.
The canvas will be stretched if you set the width and height in your CSS. If you want to dynamically manipulate the dimension of the canvas you have to use JavaScript like so:
canvas = document.getElementById('canv');
canvas.setAttribute('width', '438');
canvas.setAttribute('height', '462');
The browser uses the css width and height, but the canvas element scales based on the canvas width and height. In javascript, read the css width and height and set the canvas width and height to that.
var myCanvas = $('#TheMainCanvas');
myCanvas[0].width = myCanvas.width();
myCanvas[0].height = myCanvas.height();
Shannimal correction
var el = $('#mycanvas');
el.attr('width', parseInt(el.css('width')))
el.attr('height', parseInt(el.css('height')))
Canvas renders image by buffer, so when you specify the width and height HTML attributes the buffer size and length changes, but when you use CSS, the buffer's size is unchanged. Making the image stretched.
Using HTML sizing.
Size of canvas is changed -> buffer size is changed -> rendered
Using CSS sizing
Size of canvas is changed -> rendered
Since the buffer length is kept unchanged, when the context renders the image,
the image is displayed in resized canvas (but rendered in unchanged buffer).
CSS sets the width and height of the canvas element so it affects the coordinate space leaving everything drawn skewed
Here's my way on how to set the width and height with Vanilla JavaScript
canvas.width = numberForWidth
canvas.height = numberForHeight
I believe CSS has much better machinery for specifying the size of the canvas and CSS must decide styling, not JavaScript or HTML. Having said that, setting width and height in HTML is important for working around the issue with canvas.
CSS has !important rule that allows to override other styling rules for the property, including those in HTML. Usually, its usage is frowned upon but here the use is a legitimate hack.
In Rust module for WebAssembly you can do the following:
fn update_buffer(canvas: &HtmlCanvasElement) {
canvas.set_width(canvas.client_width() as u32);
canvas.set_height(canvas.client_height() as u32);
}
//..
#[wasm_bindgen(start)]
pub fn start() -> Result<(), JsValue> {
// ...
let canvas: Rc<_> = document
.query_selector("canvas")
.unwrap()
.unwrap()
.dyn_into::<HtmlCanvasElement>()
.unwrap()
.into();
update_buffer(&canvas);
// ...
// create resizing handler for window
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
}
There we update the canvas buffer once the WASM module is loaded and then whenever the window is resized. We do it by manually specifying width and height of canvas as values of clientWidth and clientHeight. Maybe there are better ways to update the buffer but I believe this solution is better than those suggested by #SamB, #CoderNaveed, #Anthony Gedeon, #Bluerain, #Ben Jackson, #Manolo, #XaviGuardia, #Russel Harkins, and #fermar because
The element is styled by CSS, not HTML.
Unlike elem.style.width & elem.style.height trick used by #Manolo or its JQuery equivalent used by #XaviGuardia, it will work for canvas whose size is specified by usage as flex or grid item.
Unlike the solution by #Russel Harkings, this also handles resizing. Though I like his answer because it is really clean and easy.
WASM is the future! Haha :D
P.S. there's a ton of .unwrap() because Rust explicitly handles possible failures.
P.P.S.
{
let on_resize = Closure::<dyn FnMut(_)>::new(move |_event: Event| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
// ...
window.add_event_listener_with_callback("resize", on_resize.as_ref().unchecked_ref())?;
on_resize.forget();
}
can be done much cleaner with better libraries. E.g.
add_resize_handler(&window, move |e: ResizeEvent| {
let canvas = canvas.clone();
// ...
update_buffer(&canvas);
})
If you want a dynamic behaviour based on, e.g. CSS media queries, don't use canvas width and height attributes. Use CSS rules and then, before getting the canvas rendering context, assign to width and height attributes the CSS width and height styles:
var elem = document.getElementById("mycanvas");
elem.width = elem.style.width;
elem.height = elem.style.height;
var ctx1 = elem.getContext("2d");
...

Making all photos square via css

I'm trying to make a series of photos into square photos. They may be rectangular horizontally (i.e. 600x400) or vertically (400x600), but I want to get them to be 175x175 either way. My thought was to max-height or max-width the smaller side, and not allow overflow beyond 175px on the larger side...however, I'm having problems with it.
Is this possible with css?
Below is my attempt, but it giving rectangles still:
<div style="min-height:175px; overflow:hidden; max-height:175px;">
<img style="min-width:175px; overflow:hidden; max-height:175px;" src="/photo.png">
</div>
You can set the width/height of the parent div then set the child img tag to width:100%; height: auto;
That will scale the image down to try to fit the parent with aspect ratio in mind.
You can also set the image as a background-image on the div
Then if you can use css3 you can mess with the background-size property.
It's attributes are: contain, cover, or a specificed height (50%, 50%) (175px, 175px)
You could also try to center the picture with background-position
<div style="background-image:url(some.png); background-size: cover; background-position: 50%">
Here's an up to date and simple answer.
For instance, if you want a squared image inside of a container.
Let's say you want the image to take 100% of the container height and have a dynamic width equal to the height:
.container {
height: 500px; /* any fixed value for the parent */
}
.img {
width: auto;
height: 100%;
aspect-ratio: 1; /* will make width equal to height (500px container) */
object-fit: cover; /* use the one you need */
}
You can switch width and height values (container & image) if you want to base the 100% on the container's width and have a computed height equal to the width.
You can use object-fit, which is widely supported in all major browsers. When set to cover, the browser will crop the image when you set the width and height properties, rather the stretching it.
<img src="whatever.jpg">
img {
width: 175px;
height: 175px;
object-fit: cover;
}
Okay I got this.
Don't know if it's too late or what, but I've come up with a 100% pure CSS way of creating square thumbnails. It's something that I've been trying to find a solution for for quite a while and have had no luck. With some experimentation, I've got it working. The main two attributes to use are OVERFLOW:HIDDEN and WIDTH/HEIGHT:AUTO.
Okay here's what to do:
Let's say you have a batch of images of varying shapes and sizes, some landscape, some portrait, but all, of course, rectangular. The first thing to do is categorize the image links (thumbnails) by either portrait or landscape, using a class selector. Okay, so let's say you want just to create two thumbnails, to make this simpler. you have:
img1.jpg (portrait) and
img2.jpg (landscape)
For HTML it would look like this:
<a class="portrait" href="yoursite/yourimages/img1.jpg"><img src="yoursite/yourimages/img1.jpg /></a>
<a class="landscape" href="yoursite/yourimages/img2.jpg"><img src="yoursite/yourimages/img2.jpg /></a>
So, at this point since there is no css yet, the above code would give you your full-sized image as a thumbnail which would link to the same full-sized image. Right, so here's the css for both portrait and landscape. There are two declarations for each (the link and the link's image):
.landscape {
float:left;
width:175px;
height:175px;
overflow:hidden;
}
.landscape img{
width:auto;
height: 175px;
}
.portrait {
float:left;
width:175px;
height:175px;
overflow:hidden;
}
.portrait img {
width:175px; <-- notice these
height: auto; <-- have switched
}
The most important things are the width and height and the overflow:hidden. Float left isn't necessary for this to work.
In the landscape thumbnail declaration (.landscape) the bounding box is set to 175 x 175 and the overflow is set to hidden. That means that any visual information larger than that containing 175px square will be hidden from view.
For the landscape image declaration (.landscape img), the height is fixed at 175px, which resizes the original height and the width is set to auto, which resizes the original width, but only to the point of relating to the bounding square, which in this case is 175px. So rather than smush the width down into the square, it simply fills the square and then any extra visual information in the width (i.e. the overflow) is hidden with the overflow:hidden.
It works the same way for portrait, only that the width and height is switched, where height is auto and width is 175px. Basically in each case, whatever dimension exceeds the other is set to auto, because naturally the larger dimension would be the one that would overflow outside of the set thumbnail dimensions (175px x 175x).
And if you want to add margins between thumbs, for instance a 5px white margin, you can use the border property, otherwise there will be no margin where the information is overflowing.
Hope this makes sense.
Determine width and height of image, then active portrait or landscape class of the image. If portrait do {height:175px; width:auto}. If landscape, reverse height and width.
I highly suggestion the NailThumb jquery plugin for anyone that is looking to do this. It allows you to create square thumbnails without distortion. http://www.garralab.com/nailthumb.php
This might help.
CSS:
.image{
-moz-border-radius: 30px; /* FF1+ */
-webkit-border-radius: 30px; /* Saf3-4 */
border-radius: 30px; /* Opera 10.5, IE 9, Saf5, Chrome */
}
HTML:
<div class="image"></div>
This worked for me. Just put the URL to the image inside the div.

Using CSS max-height on an outer div to force scroll on an inner-div

I have an outer div with a variable height (and max-height) that's set with a specific pixel amount by JavaScript, containing two divs within.
The 1st div is intended to hold a variable amount of content, e.g. a list of links. It has no height set.
The 2nd div is intended to hold a fixed amount of content, and has a specific height set.
Right now, the max-height isn't working. The 1st div keeps growing, even with overflow: auto; set, and pushes the 2nd div below it outside the bounds of the outer div. How can I make it so that when the 1st div gets too large for the outer div to contain both it and the fixed-height 2nd div, the 1st div will start to scroll?
Example page: http://thevastdesign.com/scrollTest.html
Thanks for any help. I'd appreciate a CSS solution the most, even if it requires some hacks. It only has to work in Firefox 3+, IE8, and IE7.
Ideas?
You cant really do that without JS. Your max-height on the outer-div isnt going to control the height of one of your inner divs to invoke its scrolling. That inner div is always going to be the height you set (pixels, auto, etc..). You can either make the entire outer div scroll as needed by using overflow: auto or you can set a max height on the first inner div and set the overflow.
Given your setup, I would do the following (class names are implied by your question, not taken from the linked source):
div.outer {
position: relative;
max-height: $length(y);
overflow: hidden;
}
div.innerFixed {
position: absolute;
bottom: 0;
height: $length(y);
overflow: hidden; /* just in case, to keep things from
blowing out into all manner of crazy */
}
div.innerFlex {
max-height: $length(y);
overflow: auto;
}
These rules don't address box properties, which will have an impact on the height values that you apply. The combined height values (with box values included) of .innerFixed and .innerFlex should equal the height value of the container.
If you want to get all Zen and flip the vertical composition, you do that by swapping bottom for top on .innerFixed and assigning margin-top or padding-top to .innerFlex.
Something else I noticed is that you've got
div.outer { float: left; }
...But given what you need from that element (and to set the right content priority) I would instead suggest that you put your big column first in the source order and apply
div.mainContent {
float: right;
width: $length(x);
}
div.outer { /* i.e., the column that started the discussion */
margin-right: length(x);
}
with the understanding that the margin-right of the latter is somewhat greater than the width of the former (greater to account for the gutter between the two elements). Try it, you'll like it.

Fixed positioned div with a fixed height and relative or absolute divs inside it with greater height

I have a problem with IE.
I have a fixed div like this:
#fixed {
position: fixed;
top: 0px;
left: 0px;
z-index: 9998;
width: 100%;
height: 40px;
}
Inside this div I want to place another div that has a height that is higher than its holder (higher than 40px). So I put a relative or an absolute div inside it and it works splendid in all browsers except IE, at least IE8.
But in IE8 the child div gets cut because of the height of 40px specified for it's holder.
Is there any workaround to this problem? I'm starting to get gray hairs..
Quick reply: have you tried setting the clip property of the contained div to it's own size?
Another workaround would be (if, say you have a container div with left/right margins auto and position: relative) to have the second div outside the fixed div in your HTML, then position it fixed within the container div instead - since it's also fixed, you can then set top/bottom and left/right positions to suit.

Resources