2

I'm developing an interactive map, where can be seen arrows. These arrows are made with SVG code. When the SVG container is clicked, a popup is showed like in the figure down below:

Stations

The main issue, is that the cointainer box (marked with solid 1px white border) act as click zone to show the popup, making it difficult to click specifically one of them when some arrows are near, like in the next example:

near arrows

So I'm trying to make the svg container like and little bigger arrow:

wanted solution

Making it easily clickable the desired arrow.

I'm not a very experienced HTML/javascript developer, so I don't know if it's possible to "shapelize" the SVG container to it content, making it with the same "arrow" shape, and if where possible, How I should proceed?

EDIT 1: A jsfiddle with an example:

I'm using the following javascript code:

function windArrow(speed, angle)
{    
  //var angulo = 0;
  var direction = 90-angle;
  // var speed = 20;
  var x = speed*Math.cos(deg2rad(direction)).toFixed(4);
  var y = speed*Math.sin(deg2rad(direction)).toFixed(4);
  var svgHeader = '<svg version="1.1" id="arrow_svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100px" height="100px" ><defs><marker id="arrowHead" markerWidth="10" markerHeight="10" refX="0" refY="1" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L0,2 L2,1 z" stroke="none" fill="red"/><path stroke-width=".3" stroke="white" fill="none" d="M0,0 L0,2 L2,1 z" /></marker></defs>';
  var outerArrow = '<g class="outerArrow"> <path marker-end="url(#arrowHead)" d="M50,50 l'+x.toString()+','+y.toString()+'" /></g>';
  var innerArrow = '<g  class="innerArrow"><path marker-end="url(#arrowHead)" d="M50,50 l'+x.toString()+','+y.toString()+'" /></g>';
  var svgFoot = '</svg>';
  return svgHeader+outerArrow + '\n' + innerArrow + svgFoot;
}
document.getElementById('arrow').innerHTML = windArrow(20,45);

DEMO: https://jsfiddle.net/manespgav/at8y24dL/3/

manespgav
  • 167
  • 1
  • 9
  • I'm not sure what you mean when you say that it makes "it difficult to click specifically one of them when some arrows are near". Crop this image so that you show a problematic case, and then please show what you _want_ it to look like (just draw that using photoshop or something), describing how it want it to behave for the bits that cannot be captured in static images (e.g. if the user moves the mouse or clicks on overlapping areas) – Mike 'Pomax' Kamermans Oct 11 '19 at 16:01
  • i dont think making an arrow is possible when you want a easy solution(yes it is possible if you create a whole lot of `div's` and make them one shape together), but you can make one small div around the arrow and give it `border-radius:100%` – Ramon de Vries Oct 11 '19 at 16:01
  • Just a note. Even if you make it smaller, it may still overlap (or it will not)? – apple apple Oct 11 '19 at 16:05
  • @RamondeVries Border-radius:100% don't avoid the overlapping, but it improves – manespgav Oct 11 '19 at 16:09

3 Answers3

5

I'm not really sure what you want, but you can bind onclick to svg component

svg { pointer-events: none; border: 1px solid black;}
svg * { pointer-events: auto;}
#g2 { position:absolute; left:50px;}
<svg height="100" width="100">
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="gray" onclick="console.log('clicked Gray')"/>
</svg>
<svg id=g2 height="100" width="100">
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="green" onclick="console.log('clicked Green')"/>
</svg>
apple apple
  • 10,292
  • 2
  • 16
  • 36
1

There are multiple ways to fix your solution. As another answer here states, you may bind click events to the relevant element of your SVG graphics -- like an explicitly defined hitbox for the arrow, the entire arrow, the tip of it or whatever else.

Another solution, and I personally think it's the one you should be preferring -- because your SVG dimensions are seemingly arbitrary and do not make much sense considering it's just hardcoded and your arrow occupies just part of it. What you want is to correct your SVG document viewport through the use of the viewBox attribute on your SVG elements.

The SVG specification covers it very well, but in short your problem is that your SVG has the dimensions of 100 x 100 pixels, while the arrow graphics it renders are much smaller. Remove width and height attributes from the root SVG element, add the viewBox attribute instead with appropriate values for the viewport (sizing it to the bounding box of your arrow graphics), and use CSS to control rendered dimensions of your svg elements on the map.

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
  • I need to let if as fixed "icon size" because the marker "drift" on zoom – manespgav Oct 11 '19 at 16:32
  • It drifts on zoom because your anchor coordinates are wrong. If you think about it, you'll understand what I mean. But without you telling more about the zooming in your question I don't think I can help you further. You are dealing with a very simple problem, but we need details to help you. And it should not be comment on my answer, but you should *edit your question*. – Armen Michaeli Oct 12 '19 at 10:28
  • you are right, that's because I need to use fixed height and width (currently, 100px x 100px), with iconAnchor at 50px, 50px – manespgav Oct 14 '19 at 18:01
0

Pointer Events may help you achieve more accurate click zones:

https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pointer-events

CodeUK
  • 421
  • 1
  • 5
  • 13