Introduction
When making this blog I wanted to add interactive images to various articles to illustrate ideas. Such as in this blog post about how to find where two lines intersect. So I built this simple JS library (plus optional CSS file) so I could easily add inline interactive SVGs.
DISCLAIMER: this library was written (and is still being written) so I could add interactive images as quickly as I could to my blog, so the code doesn't have much in the way of error handling, may not be all that consistent, and is liable to change at any moment.
Set up
First you add a link to the file, which you can download and host locally or get from rawgit. You will also need to use JQuery (for now at least).
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/petercollingridge/InteractiveSVG.js@db2890b4ae093f85cd1149b94d5be11bae6092a4/interactiveSVG.js"></script>
You will need the CSS file. Or you can style it how you like, but the file is useful to see what classes are used.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/petercollingridge/InteractiveSVG.js@db2890b4ae093f85cd1149b94d5be11bae6092a4/interactiveSVG.css">
Then add an element (it can be any element, most likely a div) where you want your SVG to be and give it an id. The SVG will be inserted into this element when it is created.
<div id="svg"></div>
Finally, you create the interactive SVG using InteractiveSVG.create(). This function takes three parameters. The first is the id for the target element, the next two are the height and width. For example, this will create 300 x 200 pixel SVG inside the element with id "svg".
InteractiveSVG.create('svg', 300, 200);
Adding points
The fundamental interactive element for these SVGs is a point that be be dragged. The interactiveSVG.create() method makes an SVG and returns an InteractiveSVG object. This object has an addPoint() method to add points.
For example, this is how to create an SVG with a draggable point at (100, 80):
var svg = InteractiveSVG.create('svg', 200, 200);
svg.addPoint({x: 100, y: 80});
If you don't want the point to be draggable then you can add a static attribute or use the addStaticPoint() method.
svg.addPoint({x: 80, y: 100, static: true});
svg.addStaticPoint({x: 120, y: 100});
Referring to points
The addPoint() method returns an object which you can then manipulate (or use as a control point for another shape). Alternatively, you can give the point a label attribute, and then use the getElement method.
var A = svg.addPoint({ x: 80, y: 100 });
svg.addPoint({ label: 'B', x: 120, y: 100 });
var B = svg.getElement('B');
You can update InteractivePoint objects attributes by passing an object to the update method(). Alternatively you can access the JQuery object representing the DOM element in $element.
A.update({r: 20});
B.$element.addClass("highlight-point");
Lines
Add a line (technically a line segment) with the addLine() method. This method takes an object with properties p1 and p2, or an array of two items. It uses this to define the end points of the line.
Points can be passed directly (as in p1: A), or referred to using its label (as in p2: 'B').
var svg = InteractiveSVG.create('svg', 200, 200);
// Define points A and B in different ways
var A = svg.addPoint({ x: 40, y: 75 });
svg.addPoint({ label: 'B', x: 160, y: 75 });
// Add line from A to B
svg.addLine({p1: A, p2: 'B' });
Instead of passing a point, you can pass in a coordinate, in which case the line won't end in a draggable point. If neither end of a line ends in a draggable point, the line will be drawn as static (grey and thinner).
svg.addLine({ p1: A, p2: {x: 40, y: 160} });
You can also pass in (x1, y1) or (x2, y2) coordinates instead of points.
svg.addLine({ x1: 160, y1: 160, p2: 'B' });
svg.addLine({ x1: 30, y1: 175, x2: 170, y2: 175 });
Instead of passing in an object you can also pass in an array of two or more points, which can be object, labels or coordinates. Lines will be added between each neighbouring pair of points (i.e. between the first and second, the second and third, and so on).
svg.addLine([A, {x: 100, y: 25}, 'B'])
Circles
Add a circle with the addCircle method. Circles are defined by a center point and a radius. The radius can be a number or it can be another point, which will allow the radius to be controlled. As with lines, control points can be given as object, labels, or a set of coordinates. You can also directly set the center of a circle with cx and cy properties.
var svg = InteractiveSVG.create('svg', 200, 200);
var A = svg.addPoint({ x: 50, y: 50 });
var B = svg.addPoint({ x: 80, y: 50 });
svg.addCircle({ center: A, r: B });
svg.addCircle({ center: {x: 150, y: 50}, r: 30 });
svg.addCircle({ cx: 50, cy: 150, r: 30 });
svg.addPoint({ label: 'C', x: 120, y: 150 });
svg.addCircle({ cx: 150, cy: 150, r: 'C' });
Bezier curves
Add a bezier curve using the addBezier method. Beziers can be quadratic (three control points) or cubic (four control points). Control points are specified by passing in a object with properties, p1, p2, p3 , (and p4 for a cubic bezier). Alternatively, you can pass in an array of three or four items.
var svg = InteractiveSVG.create('svg', 240, 200);
var A = svg.addPoint({ x: 40, y: 160 });
svg.addPoint({ label: 'B', x: 120, y: 25 });
svg.addBezier({ p1: A, p2: 'B', p3: { x: 200, y: 160 } });
svg.addBezier([A, {x: 25, y: 50}, {x: 175, y: 100}, 'B' ]);
Creating a dependent element
Often you want to create an element whose position or properties depend on other elements. For this use the element's addDependency method. This method takes two parameters. The first is an element or array of elements. The second is a function that takes those elements as an input and returns a hash of properties that the dependent object should take.
For example, if we make two points A and B, we can make a third point with the same x-coordinate as A and the same y-coordinate as B.
var svg = InteractiveSVG.create('svg11', 200, 200);
// Create control points
var A = svg.addPoint({ x: 100, y: 20 });
var B = svg.addPoint({ x: 160, y: 160 });
// Create dependent point
svg.addStaticPoint({
x: 160, y: 20, class: 'generated-point'
}).addDependency(
[A, B],
function(A, B) {
return { cx: A.x, cy: B.y };
}
);
Using JSON
To be added...
Comments (4)
Norbee on 8 Mar 2019, 7:12 p.m.
Great job. Keep it up
Jakobsen on 25 Aug 2019, 11:44 p.m.
Yes very cool - and good inspiration on even more interactive and intuitive UX
/J
Telefisch on 1 Oct 2019, 10:10 a.m.
now only dragging of a line is missing.
Very good work!
Montee on 15 Mar 2020, 12:46 a.m.
As a slow learner, This is one of the best helpful tutorials I found. Thank you. Maryland