I have a resizable div. It has two inner divs. One of the inner divs has an svg element in it.
In the svg element I am adding and removing the content dynamically such that each time I add something in my svg. I increase its height by adding 20px to it and when I remove I subtract the height by 20px. When my svg height become greater than its parent div a scroll bar appears in the parent div. Similarly scroll bar is removed when svg height is less than parent div.
The problem starts when I do the resizing. I have added a viewbox option in my svg for resizing. But when I increase the size some of my svg elements are not visible.
And when I decrease the size my svg get placed at a lower position leaving empty space.
Its all messed up in my mind that how to deal svg position/height with viewbox property.
I have tried to make a fiddle to simulate the behavior somehow. But here elements in svg are not adding dynamically and the svg height is constant.
Link to my code
Any help will be appreciated
LATEST UPDATE:
Most important if you're going to use SVG it is better to be acquainted with spec or read a definite guide like "SVG Essentials" by J. Eisenberg, cause it is not such a trivial thing you might think at first.
Then if I understood you right, there is another approach jsFiddle.
First, set correctly the value of the viewBox attribute. In your current example in should be viewBox="0 0 130 220" so that all you content be visible (you have to specify at least 220 as the last number cause your last group <g> is translated i.e. it's coordinate system moved down to 200 units, if you don't do that your content will be not visible cause it is far beyond the outmost y-point of your viewbox, which in your jsfiddle is set to 70).
Second, specify the correct value for preserveAspectRatio which should be preserveAspectRatio="xMinYMax meet", which means (courtesy of the "SVG Essentials" by J. Eisenberg):
Align minimum x of viewBox with left corner of
viewport.
Align maximum y value of viewBox with bottom
edge of viewport.
meet means meet the content, not slice it, if it doesn't fit.
Third, if you are going to add elements to the bottom of your svg you have to change the viewBox value accordingly, cause if you will insert into it smth like:
<g transform="translate(0, 300)">
<text>text 55 </text>
</g>
it will occur beyound your viewBox, which has a max y-point at 220 (if you would set it as I said earlier)
For now hope that helps, let me know.
OLD STUFF
remove style="height:200px" from your svg
Then if you need height, you can dynamically change the height of your svg
var $wrapper = $('#resize'),
$svg = $('#svg2');
$wrapper.resizable({
handles: 'se',
aspectRatio: 400/200,
resize: function(ev, ui) {
$svg.css('height', ui.size.height);
}
});
'#resize' - is the id of the wrapper of the svg
I'm now very confused of what you want. You specified viewbox attr on the svg. That means that only a part of your svg will be visible. Try to remove viewbox and see whether result looks satisfactory for you.
It then be all visible and normally adjusted to parent div
Related
Does anyone know why the behavior displayed in the above images might be occurring? In the first image, the x and y coordinates of the svgArcs container are set to zero so the center is in the top left corner and only the bottom right corner is displayed, as expected. In the second image, I moved the container, but still only the bottom right corner is displayed. I posted the document structure so maybe you can take a look and tell me what's going on.
By default <svg> elements clip their contents.
You could specify overflow="visible" on them or alternatively (and better) use a <g> element as a container rather than an <svg> element. You'll still need to keep the outermost SVG element an <svg> element.
I am placing an angular directive inside a dynamically-sized element. The directive itself consists of an SVG which is computed based on the element size. I am trying to make the SVG auto-resize and redraw based on the size of the container.
I initially tried something like this:
my-directive.js
angular
.module('myModule')
.directive('myDirective', function () {
return {
templateUri: 'path/to/my-directive-template.html',
...
};
});
my-directive-template.html
<svg style="width: 100%; height: 100%; max-width: 100%; max-height: 100%">
...
</svg>
Note the style attributes on that SVG element. This resizes correctly in Chrome, but fails to work in Firefox. Also, I still don't have a hook to recalculate the SVG contents.
I've also tried adding an onresize handler to the element in the link function, However, JQLite supports onresize only on the main window. I cannot use window.onresize, because my window size does not change.
I've tried to use the answers here: AngularJS - bind to directive resize, but they don't give the required results either.
In short, here's what I am trying to do:
Resize the SVG element inside the directive when the parent element resizes.
Re-calculate the SVG contents by calling some handler function when this happens.
I would prefer not to add a JQuery dependency at this point in the project.
This behavior can be achieved using the viewBox and preserveAspectRatio attributes of the <svg> tag.
First, set the viewBox attribute to a normalized bounding box for your SVG image. Your entire drawing should be scaled to fit inside this view box. For example,
viewBox="0 0 100 100"
will set up a coordinate system with the origin at (0, 0) and having the dimensions 100 units x 100 units.
Next, set the resizing behavior using the preserveAspectRatio attribute.
The first part of the value determines the alignment of the SVG with respect to the parent element. This includes left/right/center horizontal alignment and top/bottom/middle vertical alignment. For example,
preserveAspectRatio="xMidYMid ..."
will align the SVG centrally in its container.
The second part of the value determines how the SVG fills the container. For example,
preserveAspectRatio="... meet"
will scale the SVG such that it just fits within the container without cropping.
So the complete example becomes:
<svg viewBox="0 0 64 64" preserveAspectRatio="xMidYMid meet">
...
</svg>
Because the image scales automatically with the container, there is no need to recalculate the positions of the content elements. It is handled automatically by the SVG tag.
my d3.js code generates the following HTML (this was taken from inspect element)
The paths render a circle with text at the bottom of it.
Ultimately I want the text to be UNDER the circle within the bounds of the SVG element. If the SVG element is larger, the G element renders larger. I need to control either the size of the G element or the size of the path elements.
How would I add width and height constraints or padding to the G element? It doesn't respond to width, height, x, y in style
cursory google search was not very helpful
thanks for any insight.
The <g> element doesn't really render at all, it's the <path> and <text> elements you need to adjust.
I have a basic SVG file, that has a fix 50mm x 25mm print size (so if I open it with CorelDraw the document size will be this.)
<svg
width=50mm
height=25mm
xmlns="http://www.w3.org/2000/svg"
version="1.1"
>
<g>
<text
x=0
y=55
font-family="Verdana"
font-size=55
fill="black"
>NOS?</text>
<line
class='v_pos'
stroke="green"
x1=0
y1=55
x2=500
y2=55
stroke-width="1"
/>
</g>
</svg>
How can I achieve 500x250 px size in the browser? The ratio does not change, but I need a fixed canvas size in the web-browser too.
I need reword/extend the problem:
I'd like to export the graphics (created in browser) to CorelDraw, as it can read SVG files. The canvas in browser is for example 500x250px, and every object are measured first in pixel. After the export everything must be resided, started from the canvas (to 50x25mm) followed by the objects:
So the questions are:
witch attribute is responsible for canvas width and height in CorelDraw?
is there any fast way (preserveAspectRatio, viewBox, style media) of resizing containing objects, or I have to convert every object's width,height,x,y, etc. attributes one by one?
Thank you for any advice!
There are two different size aspects of a SVG image: how much do you want to see from the infinite canvas, and how big should the resulting image be. The first one is defined by the viewBox, which contains x and y coordinates for the top-left corner, and a width and a height. The second one is defined using the width and height attributes or style properties.
So, you use the viewBox attribute to say that you're interested in the area inside the (0px, 0px) and (500px, 250px) rectangle, since that is what you see in the browser: viewBox="0 0 500 250"
Then, since you want the image to be displayed as 50mm wide and 25mm high, you set the width and height accordingly. You can do that either setting them as attributes on the root svg element, which means that you have to set them only when exporting, since otherwise they will apply in the browser as well, or you can set them using a style element valid only for print media.
For browsers, if you're defining the viewBox you don't need to specify the width and height explicitly, since by default the area defined in the viewBox is displayed pixel per pixel.
When dealing with different media, use stylesheet media selectors. And SVG has support for that natively, using the media attribute of the <style> element. The basic syntax would be:
<style media="something" type="text/css">
svg:root {
width: 50mm;
height: 25mm;
}
</style>
Now, depending on what you want to do, you can:
Use media="print" to specify the size for print media, letting the default width and height specified in the attributes set on the root <svg> element be used in all other cases
Use media="screen" to specify the target width and height just for browsers when using a screen to display, where screen is defined as: "Intended primarily for color computer screens".
I had been using nested <svg/> and <g/> elements to center an SVG graphic within my browser frame. The outer svg element had width and height of 100%, the inner had x and y set to 50%. An inner g element had negative offset of half image size. This was working fine but I now want to add pan and zoom functionality.
The nested SVG approach seems to be incompatible with SVGPan which gets confused.
SVGPan will only work if I start with the graphic at top-left. I think I'll have to write a script that runs when SCG is loading/loaded to add a transform to center the top-level g in a way that is compatible with SVGPan.
How can I initialize my <g /> with a matrix transformation that translates it thusly?
((viewport.width - g.width)/2, (viewport.width - g.width)/2)
The size of the viewport is not known when the SVG is created but I can drop some script in there to create the transform or translation. Where should the script live and what should it do? It needs to be compatible with SVGPan.
Talos solved this issue for me, see https://github.com/talos/jquery-svgpan/issues/3
Instead of
<svg><svg><g></g></svg></svg>
I'm now using
<svg><g><svg></svg></g></svg>
and that allows a centered graphic to work with [jquery-]svgpan.
To fill an SVG element in any HTML element:
Put position:relative (or position:absolute or position:fixed, if appropriate) on the wrapping HTML element.
Put position:absolute on the SVG element (and top:0; left:0; width:100%; height:100% if necessary).
With this your SVG element will always fill the HTML element. Position/size/center this element as desired.
To get your SVG content centered within the SVG viewport
Set the viewBox on your SVG to be centered around the center of your content.
For example, if your content is a circle of radius 30 centered at 175,300 then set viewBox="145 270 60 60".
Omit the preserveAspectRatio attribute on the SVG element, or ensure that it uses xMidYMid so that the center of the viewbox is always centered in the SVG viewport.
To pan and drag your SVG content
Adjust the viewBox accordingly, or else transform elements.