Draw an arrow between two divs - javascript

I'm searching for a solution of the question that I expected to be solved already.
But I saw only big projects with a lot of features but no simple solution.
Actually I need to get something like that:
So to get an arrow drawing over a div containing some squares (divs)
<div id="container">
<div class="white_field"></div>
<div id="1" class="black_field">
<br style="clear:both;">
<div id="2" class="black_field">
<div class="white_field"></div>
<br style="clear:both;">
<div id="3" class="black_field">
<div class="white_field"></div>
</div>
I looked in the canvas direction but stumbled on tha canvas was not visible behind my divs ( maybe some z-index should help )
But still strange that I couldn't find some ready-made solution of a problem that seems to me coming up often.
( to explain some thing on the site arrows are almost a must )

You might consider SVG.
In particular, you can use a line with a marker-end shaped with an arrow-path.
Be sure to set orient=auto so the arrowhead will be rotated to match the slope of the line.
Since SVG is a DOM element, you can control the start/end position of the line in javascript.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/9aCsJ/
<svg width="300" height="100">
<defs>
<marker id="arrow" markerWidth="13" markerHeight="13" refx="2" refy="6" orient="auto">
<path d="M2,2 L2,11 L10,6 L2,2" style="fill:red;" />
</marker>
</defs>
<path d="M30,150 L100,50"
style="stroke:red; stroke-width: 1.25px; fill: none;
marker-end: url(#arrow);"
/>
</svg>

I highly recommended this library: https://anseki.github.io/leader-line/
It's pretty powerful, fast, super easy to use and it worked flawlessly for me.

I have no idea whether anybody looks at this thread anymore but here's the solution i used, it differs only slightly from #markE answer in that this answer makes it much easier to specify exactly where the line needs to start and stop.
<head>
<style>
.arrow{
stroke:rgb(0,0,0);
stroke-width:2;
marker-end:url(#markerArrow)
}
</style>
</head>
<body>
<svg height="210" width="500">
<defs>
<marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6"
orient="auto">
<path d="M2,2 L2,11 L10,6 L2,2" style="fill: #000000;" />
</marker>
</defs>
<line x1="0" y1="0" x2="200" y2="100" class="arrow" />
</svg>
</body>
All you have to do is change the x and y coordinates of the line! I used this answer in my react app and it worked beautifully.
And heres the fiddle.
.arrow {
stroke: rgb(0, 0, 0);
stroke-width: 2;
marker-end: url(#markerArrow)
}
<svg height="210" width="500">
<defs>
<marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6" orient="auto">
<path d="M2,2 L2,11 L10,6 L2,2" style="fill: #000000;" />
</marker>
</defs>
<line x1="0" y1="0" x2="200" y2="100" class="arrow" />
</svg>

Use a library, like JSPlumb: https://jsplumbtoolkit.com/

Its fairly simple to create the arrow head. See this example on CSS Tricks.
Maybe using this inside a container which has the arrow line might do it.

Canvas and jCanvas
Based on your needs, you should definitely check out using Canvas and the jCanvas library. It makes things like this a breeze.
I ventured down the road of doing everything with DIVs and jQuery but it always fell short on interactivity and quality. This really kicks open the doors without adding code complexity.
Hope that helps others, like me.
JP
EDIT 2017 05 20:
I used to have an example here that linked to the jCanvas' sandbox with all the code you needed to draw an arrow between two elements and drag both of those elements around the canvas. However, that link no longer works and I don't have the code anywhere else.
So, I still think you should check out jCanvas but unfortunately I don't have any sample code to start you off.

I recommend using this:
https://www.cssscript.com/connect-elements-directional-arrow/
Very simple to use :)
You can do this then:
<connection from="#id_1" to="#id_2" color="red" tail></connection>
How to include it:
You extract the .zip file to your projects folder.
Either copy over the CSS & JavaScript to your project, or add a reference to those files in your project:
<head>
<!-- Your head-codes here -->
<link rel = "stylesheet" type = "text/css" href = "../plugins/domarrow.js-master/domarrow.css"/>
</head>
<body>
<!-- Your body-codes here -->
<script src="../plugins/domarrow.js-master/domarrow.js"></script>
</body>
In my case the file structure is:
C/MyProject/:.
│
├───css
│ start.css
│
├───html
│ start.html <--- write here
│
├───js
│ start.js
│
└───plugins
│
└───domarrow.js-master
domarrow.css
domarrow.js
That's why I need the "../" in the beginning of the relative path, it means "step out one level", so for example: "../plugins" exits the "html" folders & goes into the "plugins" folder instead.
Adjust the file-path according to your file layouts.

Related

Including an svg element in my html breaks jquery ui

I am having a very weird issue that I have no idea whatsoever how to debug.
I have a html file with a div that has the jquery UI draggable enabled:
$(function() {
$(".ideanode").draggable({ containment: "parent" });
});
this is working fine and dandy until I include this in my html:
<svg id="connectors" height="100%" width="100%">
<defs>
<marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6"
orient="auto">
<path d="M2,2 L2,11 L10,6 L2,2" />
</marker>
</defs>
<line x1="0" y1="0" x2="200" y2="100" class="arrow" />
</svg>
This just completely removes the draggable functionality of my div and I can't even begin to understand why. I will link to a full example as well.
https://codepen.io/ricodon1000/pen/XWmqxeB
If any additional information is needed please ask, I'm still learning how to post really good questions here. Thank you!
add a global style
svg{
background:red;
opacity:.5;
}
and you will see the SVG is covering the whole screen, thus blocking every element underneath

Carving an SVG Path into a Rect, leaving the rect with a "hole"

The idea is pretty simple:
I have an SVG path and an Rect,
I need to make the path carve through the Rect, the resulting "hole" should be see-through.
Here's jsfiddle with a copy of how it's looking right now:
https://jsfiddle.net/9u0jyhr7/embedded/result/
current HTML example:
<div id="container">
<svg id="theSVG" xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect id="theRect" width="100%" height="100%" fill="#ffffff"></rect>
<path id="thePath" d="M7 25.69305419921875L7 25.6875L7.00505256652832 25.6875L293.9971923828125 25.6875L294 25.6875L294 25.709388732910156L294 90.67454528808594L294 90.6875L294.0021667480469 90.6875L321.85845947265625 90.6875L321.8607482910156 90.6875L294 183.69180297851562L294 206.421142578125L294 206.42408752441406L294 206.42701721191406L294 228.93441772460938L294 228.936279296875L294 228.93814086914062L294 248.68634033203125L294 248.6875L294.0007629394531 248.6875L304.7754211425781 248.6875L304.7763671875 248.6875L304.7773132324219 248.6875L306.581298828125 248.6875L306.581298828125 248.6875L306.582275390625 248.6875L306.582275390625 248.6875L306.583251953125 248.6875L306.583251953125 248.6875L324.73028564453125 248.6875L324.7316589355469 248.6875L324.7330017089844 248.6875L330.1683044433594 248.6875L330.1697998046875 248.6875L330.1712951660156 248.6875L357.22027587890625 248.6875L357.22265625 248.6875L357.2250061035156 248.6875L360.99749755859375 248.6875L361 248.6875L507 172.48577880859375L507 342.3311767578125L507 342.3337097167969L502.9844665527344 341.6875L436.00836181640625 341.6875L436 341.6875L436 341.6893615722656L436 378.0494079589844L436 378.051513671875L436 378.0536193847656L436 406.68511962890625L507 448.48748779296875L507 448.4908447265625L507 578.6819458007812L507 578.6875L506.9949951171875 578.6875L479.0045166015625 578.6875L479 578.6875L289.9993591308594 341.6875L279.00048828125 341.6875L279 341.6875L278.99951171875 341.6875L273.92425537109375 341.6875L273.9237976074219 341.6875L273.92333984375 341.6875L270.4071350097656 341.6875L270.4067077636719 341.6875L270.4062805175781 341.6875L265.60040283203125 341.6875L265.6000061035156 341.6875L265.5995788574219 341.6875L264.8004150390625 341.6875L264.79998779296875 341.6875L264.7995910644531 341.6875L263.8423156738281 341.6875L263.8419189453125 341.6875L263.84149169921875 341.6875L263.2403869628906 341.6875L263.239990234375 341.6875L263.2395935058594 341.6875L253.1584930419922 341.6875L253.15809631347656 341.6875L253.15769958496094 341.6875L251.40040588378906 341.6875L251.39999389648438 341.6875L251.39959716796875 341.6875L245.081787109375 341.6875L245.0813446044922 341.6875L245.08090209960938 341.6875L223.00071716308594 341.6875L223 341.6875L9.995001792907715 578.6875L7.00505256652832 578.6875L7 578.6875L7 578.6819458007812 " fill="#000000"></path>
</svg>
</div>
Here's an image of what it would probably look like if we can carve that hole:
http://i.stack.imgur.com/5fjBR.png
The Path is dynamically generated and can be quite complex, so I can't really eyeball the result.
It has to be done in javascript (or with some very clever usage of styles).
I need the result to be a DOM node that I can eventually move between z-indexes (could be grouped? a resulting "difference" path calculated in js?).
Performance and experimental features are not an issue, this is aimed at nwjs app.
Some other notes:
I'm already using jQuery, svg.js and a bunch of other libraries, so adding
new libraries is not a problem.
The rect could also be replaced by just a color filled div, if that helps solve the problem.
Ive already tried masks and clips but couldnt come to a working solution.
Any help appreciated, Thank you in advance.
A mask is what you need. I'm not sure what you tried before, but it should do what you want.
Just create a mask like so:
<defs>
<mask id="theMask">
<rect width="100%" height="100%" fill="white"/>
<path id="thePath" d="..." fill="#000000"></path>
</mask>
</defs>
Either move the original path into the mask, or copy it and hide the original.
Then apply the mask to the rect
#theRect {
mask: url(#theMask);
}
Demo fiddle here

SVG / JS Interaction - THE SIMPLE VERSION

I'm trying to create an SVG-based menu. I'm completely new to SVG, and have been searching for 1.5 days for a simple example of interaction between JS and SVG. My document structure is:
/LOCAL_FOLDER (not on a server yet)
+index.html
/CSS
+global.css
/JS
+navigation.js
/IMAGES
+navigation.svg
I have a simple html body
<body>
<div id="outer-container">
<div id="navigation-container" onclick="javascript:changeColor();" >
<object id="navigation" type="image/svg+xml" data="images/test.svg" >Your browser does not support SVG</object>
</div>
</div>
</body>
My SVG looks like this (for now)
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle id="test" cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red"/>
</svg>
This is the general structure I want to use. As you can see, it has JS from the html head (linked) interacting with my SVG #test. For now, I'd deal with having it change opacity on load just so I can start figuring out HOW to interact.
I've tried JQuerySVG, Raphael, straight JS, JS within SVG, etc, and I can't seem to connect. What I'm looking for (and can't seem to find an operational snippet of) is a super basic example that I can then learn from...
From what I've tried, I rarely had success using data="", however using something like container.load(your.svg), I could then modify to my hearts content.
another issue is to make sure that the svg data was standard.
from there (I used jQuery) jQuery('#test').attr('style','stroke:#ff0000') should change the stroke to red.

Cannot set opacity to element

I am trying to make and interactive svg which would react to some actions with javascript functions.
My SVG looks like this (this is example of one of many svg I am generating, I deleted some irrelevant elements to make the code more readable):
<svg contentScriptType="text/ecmascript" onmouseover="myOpacity(&apos;msg0&apos;, 0.5)"
onclick="svgClick(&apos;Some example text&apos;)"
width="760" xmlns:xlink="http://www.w3.org/1999/xlink" zoomAndPan="magnify"
onmouseout="myOpacity(&apos;msg0&apos;, 1)"
contentStyleType="text/css" height="30" preserveAspectRatio="xMidYMid meet"
xmlns="http://www.w3.org/2000/svg" version="1.0">
<text fill="black" x="10" id="msg0" font-size="10" y="20">Some text</text>
<script xlink:href="script.js" xlink:actuate="onLoad"
xlink:type="simple" xlink:show="other" type="text/ecmascript"
xmlns:xlink="http://www.w3.org/1999/xlink"/>
</svg>
This is my script.js file with onClick and opacity functions:
function svgClick(text) {
alert(text);
}
function myOpacity(element_id, op_value)
{
element = document.getElementById(element_id);
element.setAttribute('opacity', op_value);
}
The problem is that myOpacity function does not work and nothing happens when I hover over my objects (despite the id should correspond to the argument of the function).
However, the onCLick function works perfectly, so the problem is probably with identifying the element by id.
I am quite stuck here, could you take a look in the code and tell me where did I go wrong?
EDIT: this is a followup from this answer: Interactive SVG - how to choose element to react on mouseover action?
That code works there but it somehow does not do anything in the code I posted here. So my question is why? I know I could do this via attributes, but in that case, I do not know how to handle scenario, when I want to set opacity to one element when mouseover action is triggered on another one...
I pasted your code into a jsFiddle (making the JavaScript inline), and it works without problems in Firefox and Chrome:
http://jsfiddle.net/wpZs6/
However, the hover part could be considerably easier with just a CSS hover selector:
<svg width="760" height="30" xmlns="http://www.w3.org/2000/svg" version="1.0">
<style type="text/css">
svg:hover #msg0 {opacity:.5}
</style>
<text fill="black" x="10" id="msg0" font-size="10" y="20">Some text</text>
</svg>
See here: http://jsfiddle.net/L58z6/
try this :
var divtmp = document.getElementById(element_id);
var newStyle = "filter:alpha(opacity=85);-moz-opacity:0.85; opacity: 0.85;";
divtmp.setAttribute("style", newStyle );

Is it possible to dynamically modify an SVG loaded as a resource with Javascript?

I have these icons and I'd like to procedurally add a drop shadow (basically, something, anything) to them on hover so they don't look so hokey.
They are SVG's so in theory I can prepend something like this:
<filter id="f1" x="0" y="0" width="200%" height="200%">
<feOffset result="offOut" in="SourceAlpha" dx="20" dy="20" />
<feGaussianBlur result="blurOut" in="offOut" stdDeviation="10" />
<feBlend in="SourceGraphic" in2="blurOut" mode="normal" />
</filter>
and some javascript magic to apply it on mouse over. This could possibly save ages of design work.
Problem is, the svg's are presented as <a style='background-image:url(icon.svg)' />.
Is there a way to get into the SVG element?
No, it's not directly possible. A workaround if you need this would be to use inline svg in html, or reference the svg files with either <object>, <iframe> or <embed>.
An example of using inline svg and a filter effect on hover here. The svg part looks like this essentially:
<svg width="400" height="400" viewBox="-2 -2 36 32">
<defs>
<style>
#stack polygon:hover { filter: url(#glow); }
</style>
<filter id="glow">
<feMorphology radius="0.7"/>
<feGaussianBlur stdDeviation="1"/>
<feColorMatrix type="matrix"
values="0 0 0 0 0
0 0 0 0.9 0
0 0 0 0.9 0
0 0 0 1 0"/>
</filter>
</defs>
<g id="stack" class="icon" fill="#850508">
<polygon points="0,20 16,24 32,20 32,24 16,28 0,24"/>
<polygon points="0,12 16,16 32,12 32,16 16,20 0,16"/>
<polygon points="0,4 16,0 32,4 32,8 16,12 0,8"/>
</g>
</svg>
If you're using SVG as an image then you can't get to the image's DOM and manipulate it via javascript.
While you could load them using XMLHTTPRequest and then insert them into the main document as inline data using the DOMParser object, this exposes you to the security issues that the browsers are trying to protect you from by locking down image access i.e. the image could change and you may be loading arbitrary javascript into your page.
What would seem simplest and safest to me is if you just alter the image files directly using an editor and add the filter into them then use the modified images.
What if you use jquery addclass and simply link to another svg that has your changes?
You can also create an svg element with html code (right click on file --> view with notepad) and you will have the code there -- there are online converters that can make all neccessary tweaks and then you can enter the svg code with javascript
I don't know how to do it in the way you show... as a background image... but if you can load the svg file inside a div as in this example you can you can use my importer (a modified version of others importers founded on github) that it's here: http://www.dariomac.com/Document/Raphael-Utils. You can also see this storify where I describe all the steps followed by me to import SVG directly from file.

Categories