Plot path that overlaps itself marking overlappings - javascript

I'm trying to plot the trefoil knot parametrized like in its wiki, using svg.js (but I can change the tool if it's necessary). The problem is that I can't achieve marking the zones where it overlaps like is done here.
I want to think the person that did that example plotted it in a smart way avoiding to deal with each of those spaces one by one, because otherwise doing something like that svg would be a bit expensive (in relation of time) if you need to change of model (or just another knot).
Does anyone know how was it done or was it solved by hand dealing with each space one by one?

The basic idea would be to mask the interruptions. For DRY code, define the rendered path first as templates for reuse.
path {
fill: none;
stroke: black;
}
mask rect {
fill: white;
}
.shadow {
stroke-width: 20;
}
.knot {
stroke-width: 10;
}
<svg style="width:100px;" viewBox="0 0 100 100">
<defs>
<!-- path templates for multiple use -->
<path id="lower" d="M10 10 90 90" />
<path id="higher" d="M10 90 90 10" />
<mask id="mask">
<!-- white background: everything is visible -->
<rect width="100%" height="100%" />
<!-- black line: masked out space for higher path -->
<use href="#higher" class="shadow" />
</mask>
</defs>
<!-- lower path with masked-out gap -->
<use href="#lower" mask="url(#mask)" class="knot" />
<!-- higher path uninterrupted -->
<use href="#higher" class="knot" />
</svg>

Related

Centering icon inside SVG circle chart

I'm trying to put an icon inside an SVG circular graph so that it will display like this: SVG graph example.
No matter what I do, there's always a slight gap between one side of the inner icon and the SVG path that displays like this. I think the issue has to do w/the fact that the arc degree for the SVG circular graph isn't a perfect circle
Here's everything I've already tried:
Created a static png of the inner icon image so that it wasn't a perfect circle + then wrapped the SVG around it
Created SVG in illustrator with the inner icon as a png with two outer paths: one for the grey fill all around and one for the green fill to represent 50%. When I export the file, the d parameter is displaying based on coordinates, not percentages.
<path d="M82,153.53C122.23,153.41,153.2,121,153.46,82,153.69,43.3,122.59,10.94,82,10.49"
fill="none" stroke="#7aef93"
stroke-miterlimit="10" stroke-width="15" />
I started playing around w/this on CodePen, but didn't get very far.
Is this even possible to achieve? I'd really appreciate any and all help/feedback!
This is a fast solution, I don't know is it good. You should add class circle to the second svg like this:
<svg class="circle" width="120" height="120" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="60" cy="60" r="59" fill="#F07C7C" stroke="#D0CFCF" stroke-width="2"/>
<rect x="22" y="22" width="75" height="75" fill="url(#pattern2)"/>
<defs>
<pattern id="pattern2" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image2" transform="scale(0.00390625)"/>
</pattern>
<image id="image2" width="256" height="256"
xlink:href="data:image/png;base64,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"/>
</defs>
</svg>
And then you should add this css:
.circle {
position: absolute;
top: 25px;
left: calc(50% - 108px);
}
This should make a second svg inside first svg.

Creating bidirectional graphs in D3.js

I am building a web app that allows a user to interact with a bidirectional graph and play games to explore graph theory.
I am working off of this Graph Editor:
http://bl.ocks.org/rkirsling/5001347
Two problems:
I've found no information on how to display a bidirectional arrow
with SVG
I want to be able to run computations on these nodes and reference their adjacent nodes and change attributes of them. Therefore, I don't just want it to appear that the edges are bidirectional, I want them represented as bi/undirectional in their code so I can manipulate them.
I want this functionality to be accessible from the web. I first started this project using Python with NetworkX and Bokeh, but ran into some display problems and found it much less intuitive to deploy as a web app.
D3.js is powerful, pretty, and well documented. But for some reason, no one has done anything with undirectional force graphs. Is this because it isn't possible?
P.S. I've thought about just adding an arrow in each direction, but this seems inelegant and may have display and referential issues.
Thanks in advance!
You can display a bidirectional arrow using the marker-start and marker-end path attributes. Define one or more marker elements in the defs of your SVG containing the arrow head shape you want to use, give each an ID, and then apply them to your paths using either css or directly using a style attribute. e.g.
<svg width="200" height="200">
<defs>
<marker id="start-arrow" viewBox="0 -5 10 10" refX="4" markerWidth="5" markerHeight="5" orient="auto">
<path d="M10,-5L0,0L10,5" fill="#000"></path>
</marker>
<marker id="end-arrow" viewBox="0 -5 10 10" refX="6" markerWidth="5" markerHeight="5" orient="auto">
<path d="M0,-5L10,0L0,5" fill="#000"></path>
</marker>
</defs>
To use them:
// apply directly using the style attribute
<path style="marker-start: url('#start-arrow'); marker-end: url('#end-arrow');" d="M0,0L100,100" />
or
// in your css
.arrowed {
marker-start: url(#arrow-start);
marker-end: url(#arrow-end);
}
// in your SVG
<path class="arrowed" d="M0,0L100,100" />
There is also a marker-mid to apply shapes to the middle of paths.
Working demo:
.link {
stroke: black;
stroke-width: 3px;
fill: none;
}
.arrowed {
marker-start: url(#start-arrow);
marker-end: url(#end-arrow);
}
<svg width="200" height="200">
<defs>
<marker id="big-arrow" markerWidth="13" markerHeight="13" refX="2" refY="6" orient="auto">
<path d="M2,2 L2,11 L10,6 L2,2" style="fill: #000000;" />
</marker>
<marker id="start-arrow" viewBox="0 -5 10 10" refX="4" markerWidth="5" markerHeight="5" orient="auto">
<path d="M10,-5L0,0L10,5" fill="#000"></path>
</marker>
<marker id="end-arrow" viewBox="0 -5 10 10" refX="6" markerWidth="5" markerHeight="5" orient="auto">
<path d="M0,-5L10,0L0,5" fill="#000"></path>
</marker>
<marker id="blob" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="3" style="stroke: none; fill: #000;" />
</marker>
</defs>
<g>
<path class="link" style="marker-start: url('#blob'); marker-end: url('#big-arrow');" d="M150,50L50,150" markerUnits="strokeWidth"></path>
<path class="link arrowed" d="M150,150L50,50"></path>
</g>
</svg>
As for Q2, d3 allows you to bind data to DOM elements or calculate layouts using established algorithms, but it doesn't really handle much beyond simple graph traversal and it doesn't hold internal representations of networks that can be reasoned over or used for computations. It can't be used for the same kinds of analyses as the likes of networkx. I know of at least one JS library, KeyLines, that can do network analysis, but it is proprietary software; I am sure there are others out there.

How to animate fill in SVG shapes along path? [duplicate]

This question already has answers here:
How to draw a fill svg?
(3 answers)
How to animate handwriting text on the web page using SVG?
(2 answers)
Closed 4 years ago.
This is quite a conundrum for a couple of days now.
I have an SVG shape that I want to animate — namely, I want it to change it's color along a specific path. A simple shape looks like this:
Shapes in my SVGs represent strokes constituting Chinese characters (Hanzi) — the example has been extracted from here:
Here are the highlights:
It has to be done on SVGs (I need scalability).
Each shape is bound by a path and filled with color.
Most SVGs will have multiple shapes, often intersecting each other.
The shapes don’t have a constant width.
Each shape will have a dedicated path/stroke guiding it's direction.
Each of the shapes has to be animated in sequence.
The animations should have a constant speed (makes it a bit tricky with different element sizes, I think).
My research so far indicates that using a fill transform will not work with such shapes:
<html>
<body>
<head>
</head>
<div style="display: flex; align-items: center; justify-content: center; position: absolute; top: 50%; left: 50%; transform: translateX(-50%) translateY(-50%);">
<div style="width: 100%; height: 100%; position: relative;">
<svg
xmlns="http://www.w3.org/2000/svg"
width="38.639015mm"
height="80.743088mm"
viewBox="0 0 38.639015 80.743087"
id="svg831">
<defs>
<linearGradient id="left-to-right">
<stop offset="0" stop-color="#4DAF4C">
<animate dur="2s" attributeName="offset" fill="freeze" from="0" to="1" />
</stop>
<stop offset="0" stop-color="#fff">
<animate dur="2s" attributeName="offset" fill="freeze" from="0" to="1" />
</stop>
</linearGradient>
</defs>
<g
id="layer1"
transform="translate(-103.9336,-77.49032)">
<g
transform="matrix(0.35277777,0,0,-0.35277777,55.696164,149.58928)"
id="g823">
<path
style="fill:url(#left-to-right);stroke:none;stroke-width:0.99999994"
d="m 139.73604,123.37501 c 1.33299,-40.000002 5.667,-67.333302 12.99999,-82.000002 2.06847,-4.338361 2.99033,-6.799913 6,-12.000001 16.66701,-25.999995 36.667,-42.333293 60,-48.999998 23.33301,-6.66669 31.83301,-6.499995 25.50001,0.50001 -6.333,6.99999 -8.5,26.499998 -6.50001,58.499986 h -3.99999 l -8.00001,-43.999988 c -22,7.33332 -40.66699,21.99999 -55.99999,43.999988 -1.77033,3.225113 -4.43601,9.376455 -6,15 -4.66701,11.333303 -7.66701,34.333306 -9,69.000005 v 5 c -0.667,21.333 -1,40.333 -1,57 l 9,7 -26,12 c 0.66699,-14 1.667,-39.333 3,-76"
id="my_path" />
</g>
</g>
</svg>
</div>
</div>
</body>
</html>
I also considered clipping path, but I an not sure how to clip/unclip one object along another object realiably so that neighboring strokes are not clipped. Some other solutions need a lot of manual tinkering, which I need to avoid due to the volume of data I want to process.
EDIT: I had to edit this question as it has been — in my opinion wrongly — marked as a duplicate, as I clearly stated my restrictions (the other question has been solved by converting everything into strokes).
There is, however, a potential solution that came to my mind, but I am not sure how to proceed: I could make my red stroke so thick that it's wider than my shape, and then apply a clipping path with the exact same coordinates as my shape — then it would suffice to just animate the red stroke. But can separate objects have non-summing clipping paths?

Cutting out a text shape from background that can be resized dynamically

I'm trying to create a box that is opaque, but has a block of text in it that you can see through (to like the background image of the page or some element underneath).
It's hard to explain so I've made some crude diagrams:
I am attempting to use SVG files to do this and use Javascript/jquery to modify the rectangle width and height but I'm not proficient at the SVG format... I've managed to piece this together using the evenodd filter:
https://jsfiddle.net/PhoenixFieryn/sqvLgqbq/
<svg id="coverimage" width="80pcm" height="30cm" viewBox="0 0 2000 2000" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<desc>Example fillrule-evenodd - demonstrates fill-rule:evenodd</desc>
<defs>
<rect x="1" y="1" width="2000" height="1000"
fill="white" stroke="blue" />
</defs>
<g fill-rule="evenodd" fill="white" >
<path d="M0 0 h1000 v1000 h-1000z M841,396.8c-2.4-4-1.6-8.8,2.4-11.2c68-44,95.2-105.6,95.2-172.8c0-116-96.8-205.6-211.2-205.6H610.6H469.8
h-6.4c-4,0-5.6,1.6-8.8,6.4L315.4,320c-4,6.4-8,6.4-11.2,0l-140-306.4c-2.4-4.8-4.8-6.4-8.8-6.4H9c-5.6,0-8.8,4-6.4,9.6l264,554.4
c1.6,4,5.6,6.4,9.6,6.4h66.4c4,0,7.2-1.6,8.8-5.6l110.4-230.8v228.4c0,4.8,3.2,8,8,8h146.4c4.8,0,8-3.2,8-8V426.4c0-4.8,3.2-8,8-8
h42.4c4,0,8,1.6,9.6,5.6l76,148c1.6,4,5.6,5.6,9.6,5.6h158.4c5.6,0,8.8-4,5.6-9.6L841,396.8z M701.8,276h-69.6c-4.8,0-8-3.2-8-8
V158.4c0-4.8,3.2-8,8-8h75.2c36.8,0,68,28.8,68,62.4C775.4,244,750.6,276,701.8,276z"/>
</g>
I don't know how to modify the size/position of the text and rectangle independently well. I can barely understand what I wrote and why the margin is so big.
If anyone could help me, through this or any other method, thank you!
Edit: someone pointed out that there may be a duplicate, but that solution does not work in Firefox unfortunately. I am looking for a cross “platform” solution. But thanks for the link, it’s very helpful nonetheless.
My suggestion is to create a mask using the text. We then create a blue rectangle that we mask with the our text mask.
We can postion the SVG and have it size the way we want using SVG width and height. But we also make the blue rectangle very large and have the SVG set to overflow: visible. This allows us to easily have the SVG size be responsive and also have the blue extend to all the way to the edges of the screen.
body {
background-image: url('http://austinhou.com/img/cover.jpg');
background-size: cover;
margin: 0;
padding: 0;
}
#coverimage {
width: 40%;
height: 100vh;
overflow: visible;
}
<body>
<svg id="coverimage" viewBox="0 0 950 600" preserveAspectRatio="xMinYMid meet">
<defs>
<mask id="vr">
<rect x="0" y="-1000%" width="1000%" height="3000%" fill="white"/>
<path fill="black" d="M841,396.8c-2.4-4-1.6-8.8,2.4-11.2c68-44,95.2-105.6,95.2-172.8c0-116-96.8-205.6-211.2-205.6H610.6H469.8
h-6.4c-4,0-5.6,1.6-8.8,6.4L315.4,320c-4,6.4-8,6.4-11.2,0l-140-306.4c-2.4-4.8-4.8-6.4-8.8-6.4H9c-5.6,0-8.8,4-6.4,9.6l264,554.4
c1.6,4,5.6,6.4,9.6,6.4h66.4c4,0,7.2-1.6,8.8-5.6l110.4-230.8v228.4c0,4.8,3.2,8,8,8h146.4c4.8,0,8-3.2,8-8V426.4c0-4.8,3.2-8,8-8
h42.4c4,0,8,1.6,9.6,5.6l76,148c1.6,4,5.6,5.6,9.6,5.6h158.4c5.6,0,8.8-4,5.6-9.6L841,396.8z M701.8,276h-69.6c-4.8,0-8-3.2-8-8
V158.4c0-4.8,3.2-8,8-8h75.2c36.8,0,68,28.8,68,62.4C775.4,244,750.6,276,701.8,276z" transform="translate(-210 0)"/>
</mask>
</defs>
<rect x="0" y="-1000%" width="1000%" height="3000%" fill="#09f" mask="url(#vr)"/>
</svg>
</body>
JSFiddle version

How to draw from point in one SVG element to point in another?

I have a situation where there are multiple SVG elements in an HTML document. The elements are laid out using HTML rules, box model, flexbox, and now I'm told grid will start being used soon. This jsfiddle is an example, showing a pair of filled parabolas drawn with common endpoints and slightly different control points using a Quadratic path operation. Other cases may be simple horizontal or diagonal lines of various thickness.
In the first SVG in the fiddle, the two endpoints are in the same SVG block, and dimensions (in SVG units) are well known, and it is straightforward to draw the parabola. (the control points are also shown here)
However, the next two SVG demonstrate the problem. The endpoints are in separate SVGs, separated by unknown amounts of "stuff" here represented by a bit of text. It is clear that javascript will be required to rewrite the coordinates of the endpoints and control points, so that the parabola (or whatever) can connect the two.
How do I obtain the SVG unit coordinates of the endpoint in the second SVG relative to the coordinate system of the third SVG, so that I can connect the parabola to its left endpoint?
One possibly simplifying assumption can be made: the SVG unit to pixel coordinate ratio will be consistent for any drawing, although for added complexity that ratio may change from time to time (triggering the need to recalculate and re-draw the cross-SVG items).
A possibly complicating issue is that most of the endpoints will be nested in two layers of nested SVG elements: the outer SVG will have its SVG unit be the same size as the CSS pixel, but the inner SVG will have this different unit size that may change from time to time.
IDs or CLASSes can be added as necessary to the solution.
/**CSS*/
svg { overflow: visible; }
<!--HTML -->
<svg width="12cm" height="6cm" viewBox="0 0 1200 600"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Example quad01 - quadratic Bézier commands in path data</title>
<desc>Picture showing a "Q" a "T" command,
along with annotations showing the control points
and end points</desc>
<rect x="1" y="1" width="1198" height="598"
fill="none" stroke="blue" stroke-width="1" />
<path d="M500,300 Q300,50 100,300 Q300,75 500,300"
fill="green" stroke="green" stroke-width="1" />
<!-- End points -->
<g fill="black" >
<circle cx="100" cy="300" r="3"/>
<circle cx="500" cy="300" r="3"/>
</g>
<!-- Control points and lines from end points to control points -->
<g fill="#888888" >
<circle cx="300" cy="50" r="3"/>
<circle cx="300" cy="75" r="3"/>
</g>
<path d="M100,300 L300,50 L500,300
L300,75 L100,300"
fill="none" stroke="#888888" stroke-width="1" />
</svg>
<br>
<svg width="2cm" height="6cm" viewBox="0 0 200 600"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Example quad01 - quadratic Bézier commands in path data</title>
<desc>SVG left endpoint</desc>
<rect x="1" y="1" width="198" height="598"
fill="none" stroke="blue" stroke-width="1" />
<!-- End points -->
<g fill="black" >
<circle cx="100" cy="300" r="3"/>
</g>
</svg>
some stuff here
<svg width="2cm" height="6cm" viewBox="0 0 200 600"
xmlns="http://www.w3.org/2000/svg" version="1.1">
<title>Example quad01 - quadratic Bézier commands in path data</title>
<desc>SVG right endpoint</desc>
<rect x="1" y="1" width="198" height="598"
fill="none" stroke="blue" stroke-width="1" />
<path d="M100,300 Q-100,50 -300,300 Q-100,75 100,300"
fill="green" stroke="green" stroke-width="1" />
<!-- End points -->
<g fill="black" >
<circle cx="100" cy="300" r="3"/>
</g>
</svg>
(In general, the coordinates will not have the same Y position, this example is simplistic: but all I need is a way to determine the position of the endpoint in the proper coordinate system.)
This was hard for me to figure out, but a co-worker helped, and we finally puzzled through it. The solution turns out to be fairly straightforward.
The way we puzzled things out, it seems that there is a coordinate transformation matrix that can be used to convert from SVG user coordinates to browser pixels... and, via its inverse, back to SVG user coordinates. This is obtained for each starting and ending elements by:
start = document.getElementById('startSVGElement');
spt = start.createSVGPoint();
sCTM = start.getScreenCTM();
end = document.getElementById('endSVGElement');
ept = end.createSVGPoint();
eCTM = end.getScreenCTM();
Then, to draw from a point ( 100, 400 ) in the starting element, to a point ( 50, 60 ) in the ending element, you fill in the points:
spt.x = 100;
spt.y = 400;
ept.x = 50;
ept.y = 60;
Now the transformation magic: transform the ending point from SVG space to browser pixel space based on its CTM, and then transform back to SVG space using the starting element CTM inverse:
ept_in_start = ept.matrixTransform( eCTM ).matrixTransform( sCTM.inverse())
Now spt and ept_in_start have coordinates relative to the same element (the starting element) and in the same coordinate system (the SVG space of the starting element), and you can use those coordinates to draw anything you wish, based on the coordinates.
Of course, if the page reflows, you have to recalculate and redraw. And you have to be sure to get the right CTM for the (x,y) coordinates of each endpoint... there are lots of overlaid coordinate systems if you have nested SVGs and transformations.

Categories

Resources