I have the path as described in the attached image 1, and I want to drag and drop the another element (as rounded red) on the edges of the drawn path, so at the end I want to drag the red marked element on the black line that is edge of the path, not inside the path,and now i can move inside and outside the path, but I want only to be on the border of the path
So here I have the customized the code as below on the mouseMove function and on the select case svgedit.compiled.js
if (path_child == 'path') {
var line_rotate = 90;
if (group_w_d == "drag_drop_D") {
var test = 'rotate(' + line_rotate + ',' + line_pt.x + ',' + line_pt.y + ') translate(' + trans_x + ',' + line_pt.y + ') scale(' + width + ',' + height + ')';
} else {
var test = 'rotate(' + line_rotate + ',' + line_pt.x + ',' + line_pt.y + ') translate(' + line_pt.x + ',' + line_pt.y + ') scale(' + width + ',' + height + ')';
}
selectedElements[0].setAttribute('transform', test);
var cls = selectedElements[0].getAttribute('class');
//alert(cls);
$('.' + cls).each(function() {
$(this).attr('transform', test)
});
}
For example here is the fiddle link example, which I want exactly, here we can move the ellipse on the path wherever we want, but I want it to be on the edges of my path elements
Edited:
For example just imagine that we are creating a room using rectangle and in this room we have to fix a door or window,like marked as rounded red, so we can move the path along all the position of the rectangle but it should only on the edges not inside the rect or outside the rect, there is no problem about it we done it,
But now we want split the wall to extended wall so we converted the rect into path after converting this the doors or windows are not moving along with the edges of the path instead of this the doors are moving anywhere on the working area of the SVG-EDIT
and here my doors and windows are the g not ellipse, so i know ellipse only have the cx,cy and g may have the transform so am not clear how to do it
i hope this will make sense
You need to tweak my SO answer, see the comment section for triangle fiddle (SO wont let me post fiddle link w/o code). Basically extend line from the centroid of triangle and calculate the intersection path.
Edit: In native SVG, you need an intersection library for line with line
Do post the updated code here for future readers.
Related
I want to display a specific icon in different boxes using d3.
I have a data as an array of [x0, y0, x1, y1, vx, vy] where:
x0, y0 is the first corner of a box,
x1, y1 the second corner and
vx, vy two parameters (velocity)
that will be used to generate a SVG path.
I am using:
var boxes = nodeSVGGroup.selectAll("rect").data(nodes).enter().append("rect");
to generate my boxes and this is working well
My problem comes when I want to create the SVG path (icon) and properly render it in each box (it needs to be generated, translated and rotated to fit the center of each box.
I am using a similar pattern i.e.
var selection = nodeSVGGroup.selectAll(".barb").data(nodes);
selection.enter()
.append('g')
.each(function(node, i) {
var vx = node[4];
var vy = node[5];
var speed = Math.sqrt(vx*vx + vy*vy);
var angle = Math.atan2(vx, vy);
// generate a path based on speed. it looks like
// M2 L8 2 M0 0 L1 2 Z
var path = ...
var scale = 0.5*(node[1]-node[0])/8;
var g = d3.select(this).data([path,angle,scale]).enter().append('g');
// still need to add following transforms
// translate(' + node[2] + ', ' + node[3] + ')
// scale(' + scale + ')
// rotate(' + angle + ' ' + 0 + ' ' + 0 + ')
// translate(-8, -2)',
g.append('path').attr('d', function(d){console.log(d); return d[0];})
.attr('vector-effect', 'non-scaling-stroke');
})
.attr('class', 'wind-arrow');
I get the error Uncaught TypeError: Cannot read property 'ownerDocument' of null(…) which seems to be related to this line
.each(function(node, i) {
What am I doing wrong?
The full code is here
It's not entirely clear why are you trying to create an "enter" selection inside an each. I'm not sure if I understand your goals, but you can simply use d3.select(this) to append the path to each group:
d3.select(this).append('path')
.attr('d', path)
Here is the updated fiddle: https://jsfiddle.net/9x169eL1/
I have an svg country map and I'm trying to achieve the effect when you click on a district and then see an animated scaling relative to selected district, i.e. scaling with transform-origin point in the center of a clicked district. And I would prefer not to use any libraries.
First of all, why here, when we have svg viewBox attribute setted, polygons drawn with getBoundingClientRect() points don't match their actual elements svg, map, e.target?
If we add some coefficients like here, then what viewBoxMapCoefX1 and viewBoxMapCoefX1 we need so the mapPolygon drawn with getBoundingClientRect() points matches actual map element?
When I try to scale map by adding:
// ANIMATION HERE
map.style.transformOrigin = transformOriginX + "px " + transformOriginY + "px";
map.style.transform = "scale(" + scale + ")";
it looks like transformOrigin value is wrong. If I try to change viewBox value by adding:
// ANIMATION HERE
svg.viewBox.baseVal.x = bounding.left;
svg.viewBox.baseVal.y = bounding.top;
svg.viewBox.baseVal.width = bounding.width;
svg.viewBox.baseVal.height = bounding.height;
then how can I make scaling animation with CSS (no SMIL)?
Any help or advice on this is greatly appreciated.
1) You should be using .getBBox() instead of BoundingClientRect to get the coordinates, as this will be based on the SVG itself and not the screen.
3) You are applying the transforms to the group tag, whereas it makes sense for these to be applied to the SVG element itself instead. You may have tried this already, but the transform origin value will all be based on the co-ordinates you're getting previously? So long as the animation works as intended, there is no issue with the animation front from what I can see.
// ANIMATION HERE
var svg = document.querySelector("svg");
svg.style.transformOrigin = '50% 50%';
svg.style.transform = 'scale(4)';
Thanks to #OwenAyres's answer 1 part of question has been solved.
Instead of scaling map straight relative to the selected district center we can find district's center in % insted of px and then move district's center to map's center and then make scale:
// ANIMATION HERE
var transformOriginXPercent = (50 - transformOriginX * 100 / mapBounding.width) * scale;
var transformOriginYPercent = (50 - transformOriginY * 100 / mapBounding.height) * scale;
var scaleText = "scale(" + scale + ")";
var translateText = "translate(" + transformOriginXPercent + "%," + transformOriginYPercent + "%)";
map.style.transformOrigin = "50% 50%";
map.style.transform = translateText + " " + scaleText;
and get expected result.
But there is still a question what coefficients for transformOriginX and transformOriginY are correct to get the result in the following form:
map.style.transformOrigin = (transformOriginX) + "px " + (transformOriginY) + "px";
map.style.transform = "scale(" + scale + ")";
With a d3.js sankey diagram, how can I make a link flow out of a node and off the diagram towards either the bottom or top? This necessitates a 90deg turn in the link and for it to not end at a node (or at least not one in the diagram) and symbolizes a flow going out of the modeled system.
I want it to look something like the 'Finished Petroleum Products' link in this diagram.
Specifically I'm using this boilerplate, but a more generic answer is fine I'm stuck on which methods I can use to make this happen but once I know what to use and how to use them I can implement it.
Update: Basically, what I'm wondering is how to re-write one of the d3 functions (which?) to make a link terminate with a horizontal line (ie flush with the SVG ceiling or floor) instead of a vertical line (ie another node's side face).
The code below is a function I used to create a link path which leaves a node on its right, goes horizontally briefly, bends upwards with a quarter-circle and exits the ceiling of the diagram. I was naive in that the solution had nothing to do with re-writing a D3 function..it just took learning how to use the SVG path language.
function drawPathLeavingDiagram(link) {
var x0 = link.source.x + link.source.width,
x1 = x0 + link.source.width / 4,
x2 = x1 + link.source.width / 2,
y0 = link.source.y + link.sourceY + link.thickness / 2,
y1 = y0 - link.source.width / 2,
rx = link.source.width / 2,
ry = link.source.width / 2;
return "M" + x0 + "," + y0 + "L" + x1 + "," + y0 +
"A" + rx + "," + ry + "," + 0 + "," + 0 + "," + 0 + "," + x2 + "," + y1 +
"V" + 0;
}
What i need
Current example : http://jsfiddle.net/2ecsjomz/5/
Notes:
a specific left/right pair will never change places, "left drag" will always stay on the left or the "right drag"
a single angle point needs to be formed between two points
the line starting from the "left drag" needs to be horizontal
if it helps i do not need the points to be draggable, its ok to have specific coordinates.
it needs to generate lines between two html elements ( same as example )
Change the path coding to this one below:
// Build the path decription
p = "M" + pt1x + "," + pt1y +
" L" + (pt1x+pt2x)/2 + "," + pt1y +
" L" + pt2x + "," + pt2y ;
I'm using Leaflet 0.7.1 and want to draw a radial menu (like openstreetmap's iD editor) on top using d3.
Some examples I found use Leaflet's overlayPane to append the svg element to:
var svgContainer= d3.select(map.getPanes().overlayPane).append("svg");
On mouseclick, I add the menu and reposition it to the screen xy coords:
map.on('contextmenu', function(e) {
console.log('contextmenu()');
var tooltip;
var center = [e.layerPoint.x, e.layerPoint.y];
var menu = svgContainer.append('g')
.attr("class", 'leaflet-zoom-hide')
.attr('class', 'radial-menu')
.attr('transform', 'translate(' + center + ')')
.attr('opacity', 0);
menu.transition()
.attr('opacity', 1);
menu.append('path')
.attr('class', 'radial-menu-background')
.attr('d', 'M' + r * Math.sin(a0) + ',' +
r * Math.cos(a0) +
' A' + r + ',' + r + ' 0 ' + 0 + ',0 ' +
(r * Math.sin(a1) + 1e-3) + ',' +
(r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
.attr('stroke-width', 50)
.attr('stroke-linecap', 'round');
});
Somehow, the SVG paths get drawn (this is visible in the Chrome Inspector) but are behind the map object.
When I 'drag' the SVG element just below the body tag in Inspector, I can see the circle paths.
Any ideas on how I can draw SVG 'menu' elements on top of Leaflet?
Thanks!!
See this fiddle for a demo. Right click or hold to add an invisible element.
ps. I asked this question on gis.stackexchange.com, too.
Solved. A colleague pointed out that the SVG container had no dimensions. Giving it the appropriate width and height proved to be the answer:
svgContainer.attr("width", width).attr("height", height)