I am working on a project where I have a page that lists job positions and I need to visually show progression (how to get from one job to another) using lines/arrows so the user can follow along. I created a page that contains all the data for this and now I am trying to use SVG paths to create lines on top of the data and draw paths.
I found some code in another answer that I converted to pure JS and removed the jQuery references to be able to use it in my project.
Here is the working fiddle with one path example:
http://jsfiddle.net/x4nmqkLj/
Here is my attempt:
http://jsfiddle.net/szrdb263/
My issue that I am facing is that the SVG and Path appear to be created BUT, I am unable to see the line/path on the DOM. However if I view the elements in the web tools, I can see the SVG element and path element and they appear to be in the correct location to where the path would be drawn from the starting and ending position.
My rendered path is as follows:
<path class="path" id="path1" d="M449.953125 512.34375 V568.03125 A55.6875 55.6875 0 0 0 505.640625 623.71875 H765.515625 A55.6875 55.6875 0 0 1 821.203125 679.40625 V1055.3203125"></path>
Here is the SVG Element:
Here is the Path Element:
The path should be drawing a line from the first box 1A to the bottom row, second box 2D. The path appears to be where its expected, the bottom center of the first box to the top center of the bottom box where the arrow would be drawn.
CSS:
#svgContainer {
z-index: -10;
opacity: 0.5;
margin: 2.5em 2.5em;
position: absolute;
background-color: #999;
}
path {
fill: none !important;
stroke: #000 !important;
stroke-width: 0.7em !important;
}
Is anything angular specific that I am missing causing this to not show up?
I am not terribly familiar with SVG but seeing both the SVG element and Path element in the DOM makes me think its pretty close. I can't imagine the arrow is outside of the DOM anywhere but I may be wrong.
Update:
I pasted my path code in a few "validator" sites for SVG to see if it would draw it and I am not getting any visual indication. This would suggest that there is something wrong with the coordinates that it is using to create the path. However, the same code is being used on the working example so I am wondering if this is an angular quirk after all with manipulating the DOM of sorts.
Update 2:
I believe I have solved the issue. I had to change how I was getting the ending coordinates in the JS.
Before:
// calculate path's end (x,y) coords
var endX = endCoord.offsetLeft + 0.5 * endElem.offsetWidth - svgLeft;
var endY = endCoord.offsetTop - svgTop;
After:
// calculate path's end (x,y) coords
var endX = endCoord.getBoundingClientRect().left + 0.5 * endElem.offsetWidth - svgLeft;
var endY = endCoord.getBoundingClientRect().top - svgTop;
New Fiddle: http://jsfiddle.net/8dumowvt/
I got your example working by doing the following:
Replaced offsetTop and offsetLeft by getBoundingClientRect().top and getBoundingClientRect().left in connectElements()
Adjusted style of svgContainer to give it a positive z-index, so that the svg is drawn over the other elements
Added pointer-events: none; to the svgContainer so that you can still interact with the elements behind it
Here's the updated Fiddle.
Related
Most libraries provide limited customization of the Sankey chart (like node color, width, padding).
Default Sankey chart (d3):
But what if I need to change node heights and center the nodes vertically? How I can do that?
My requirements:
Can anyone help me?
Slightly hacky, but you could override the CSS rules to style the elements however you wish.
For example, if I have a d3-generated Sankey chart within a div named "sankey", I can add these CSS rules to change the rect elements to red, and the path elements that form the links to blue.
From some very brief testing, the rect elements seem to require the "!important" CSS modifier, hence the comment about it seeming a little hacky:
#sankey > svg > g > g > g > rect {
fill: red !important;
}
#sankey > svg > g > g > path {
stroke: blue;
stroke-opacity: 0.7;
}
To make the rects larger, you could possibly set their stroke color to be the same as the fill, and set the stroke width to something large, and then play with the "nodePadding" parameter in the d3 API.
I've attached a screenshot of what I got to work by playing with these:
Without watching your code - it is a guessing game. So, I assume, you've used examples of sankey D3.js in the internet that are pretty much sharing same code. At some point you could see something like this:
var sankey = d3.sankey()
.nodeWidth(12)
.nodePadding(12)
.size([width, height]);
Please, try to fiddle around with nodeWidth (enlarge the value) to get what you're after.
For my website, I want the users to be able to click on various svg elements.
I've coded up a quick function to let users click on enclosed shapes. I basically just run document.elementFromPoint(x, y) on them. This works great for any enclosed shape, since they have clickable area. Open paths, however, are a pain to click because they're only 1-2 pixels in size.
I would like to allow the user to select them by clicking 'close enough' to it, such that if the click is, for example, 10 or fewer pixels away from the path, the path would be selected. I could write a mathematical algorithm for this (using Ray-Casting that only goes 10 pixels out for example, or turn points into 10px-radius circles and check for intersections with the path), but my intuition tells me there must be an easier way, perhaps via CSS.
One idea I was thinking of is if the stroke for this path was 10 pixels thick for selection purposes, but only 1 pixel thick visibly (or having a 'padding' that would apply to the path rather than the bounding box). I've also looked at pointer-events, but aside from bounding box (which I would rather not use to avoid selecting other shapes) I don't see any useful settings there. Is there something I could leverage in JavaScript or CSS that can help me accomplish this without doing the math for the paths myself (since it may get ugly for cubic beziers, etc.)?
I should also mention that this is an HTML5 app, so I don't care about backwards-compatibility.
If the paths have no stroke then you can create an invisible stroke (stroke-opacity="0") and use pointer-events="all" to give the shape an extended hit area.
If the paths do have strokes then you need to create a second invisible path on top of the visible path with the same coordinates but a bigger stroke-width. You can then use pointer-events="all" to make this invisible path the hit target and if it is hit you react in the event handler as if the visible shape was hit.
Robert Longson describes how you can do this, but I wanted to add some more details.
First, you don't need to duplicate or create new geometry if you don't want to. You can also use a <use> element. You can use some css to give shapes a different look even when some other invisible element is hovered.
<style>
g { fill: #ddd; stroke: black; pointer-events: none; }
use { pointer-events: all; stroke-width: 40; fill: none; stroke-opacity: 0; }
use:hover + * { fill: cornflowerblue; }
<g>
<use xlink:href="#c"/>
<circle id="c" cx="50" cy="60" r="20"/>
</g>
See live example.
Problem is in title. It used to do it on the odd occasion. Then i added the jQuery rotate.js plugin to spin my heading 360 degrees and now it is constantly placed to the right of where it should be. It may be interesting to note that i got the offset of the canvas with
var rect = gameController.canvas.getBoundingClientRect();
var offset = {
x: rect.left,
y: rect.top
};
And that still has coordinates of 0,0 in the top left corner of where it should be ( which is correct and how it should be when the canvas has not moved).
#canvas {
z-index: 1;
position: absolute;
margin-top: 52px;
margin-left: 44px;
background-image:url(images/background.jpg);
}
If the position is absolute, it is removed from the document and nothing will make it move. Strange.
getBoundingClientRect() returns the sum of the canvas and its css border-boxes.
Maybe check the canvas with getClientRects() to see exactly where it is.
I'm not sure why it moved, i probably have a css error somewhere..but i had my canvas as position absolute, relative to a div that it was inside. I placed my canvas right at the top of the body tag so it was absolute, relative to the whole page, then changed the placement of it with top and bottom to get it correct. Now nothing will move it. It works fine with the rotate.js plugin. Thanks for having a look at my question.
I have a svg in graph panel. All nodes in the svg are listed in another panel. I hope that by clicking the node in node list, svg can scroll to that node. Each node is a rectangle. But I found that only the upper border is in view, while the rest part of the node are still out of the view. Is there any way to fix this problem? (either Javascript or Extjs)
This is my code:
function selectRectangle(Id){
var ele = Ext.get(Id);
ele.scrollIntoView(Ext.get('graph-panel-body'), true);}
By whatever reason scrollIntoView seems not to work for SVG elements. This is what I do
suppose the svg is in a
<div id="container">
<svg ...>
...
<path id> ...</path>
</svg>
</div>
then suppose in the variable 'element' you have the element you want to scrollIntoView
var bbox = ele.getBBox()
var top = bbox.y + bbox.y2
top = 50 * Math.floor(top/50)
$("#container").get(0).scrollTop=top
I am not sure, but I observe that getBBox is pretty slow. So take care.
The problem is that the SVG element you are trying to scroll the view to probably has a y or dy attribute which offsets it from the top, and the scrollIntoView method in Chrome doesn't take that into account (in Firefox it does), therefor it will scroll to the top, because it thinks the element is there, because this is how SVG elements positioning works.. elements are all rendered from the very top left and then kind of "transformed" to their positions via x, y, dx, dy attributes.
There is an open bug which you can (and should) star:
https://bugs.chromium.org/p/chromium/issues/detail?id=803440
I have a 500x400px container, where I'm working with RaphaelJS to manage some SVG goodies. I've loaded an image with this code:
var img = paper.image("images/image.jpg", 50, 200, 90, 110);
Now I want to draw a path relative to this element. How should I do?
If I write something like:
var c = paper.path("M 18.00,79.75 C 18.00,79.50 52.50,79.75 52.50,79.75...");
The path is being created relative to the parent container, and doesn't take the proper position over my image.
Thanks for your support
--- edit ----
This is my dashboard with its styling:
#canvas {
float: left;
width: 500px;
height: 400px;
border: 1px solid #333;
}
<div id="canvas"></div>
And this is part of the javascript code:
// Creates canvas 500 × 400 inside canvas div
var paper = Raphael(document.getElementById('canvas'), 500, 400);
// Load an image at 50, 200
var img = paper.image("images/image.jpg", 50, 200, 90, 110);
After that, I would like to fill an SVG path, positioning it over my image.
If I write something like:
var c = paper.path("M 18.00,79.75 C 18.00,79.50 52.50,79.75 52.50,79.75...");
This path is created upon the #canvas container, starting from 0,0 coords.
How do I do?
Please look into this fiddle http://jsfiddle.net/XRBRz/. In this fiddle, imagine the black rectangle as your image.
The staircase path is drawn relative to the black rectangle, by translating the path to the origin of the rectangle.
Also the path(staircase) is given a clip-path having the same dimension of the black rectangle, to clip the path outside the black rectangle.
It sounds like you are thinking that Raphael keeps a reference to a current pen position between creation of shapes, etc. I don't think this is true... I believe that when you add a path, the starting position of that path is relative to the canvas 0,0. (Note that the path 'M' command does allow a relative moveTo 'm', but I think this only works after the initial one in a path string... at the beginning, it seems to be absolute, regardless of case)
So, if you want to start the path from the top left corner of the image, start the path string with "M50,200" - for bottom right, start it with "M140,310".
If you want the path to stay attached to the image at that point, add them to a set. But that is another post... :-)