Imported SVG rendering as string - javascript

I'm using the editorjs npm package and have created a custom plugin.
To display an icon for the editor an SVG has to be provided as seen below
This works when inline svg is used as seen below
return {
title: 'Image',
icon: '<svg width="17" height="15" viewBox="0 0 336 276" xmlns="http://www.w3.org/2000/svg"><path d="M291 150V79c0-19-15-34-34-34H79c-19 0-34 15-34 34v42l67-44 81 72 56-29 42 30zm0 52l-43-30-56 30-81-67-66 39v23c0 19 15 34 34 34h178c17 0 31-13 34-29zM79 0h178c44 0 79 35 79 79v118c0 44-35 79-79 79H79c-44 0-79-35-79-79V79C0 35 35 0 79 0z"/></svg>',
}
However when I attempt to import the SVG and use the reference instead:
const toolBoxIcon = require('./image.svg');
return {
title: 'Image',
icon: toolBoxIcon,
};
It renders as string:
I'm trying to figure out what needs to be done to load the SVG in the second instance.

Related

Vue unicons - set viewBox in custom icon

I have just installed the Vue Unicons module in my vue project.
Vue version: 2.6.10
Vue unicons version: 3.3.1
I am trying to create my own custom icons as explained here:
custom-icons.js:
export const myTestIcon = {
name: 'myTestIcon',
style: 'line',
viewBox: '0 0 680 680',
path: '<path d="M 635 497 l 1 -466 l -620 0 L 20 640 L 516 643 L 231 221z"></path>';
}
app.js:
import Unicon from 'vue-unicons/dist/vue-unicons-vue2.umd';
import { myTestIcon } from './custom-icons';
Unicon.add([myTestIcon]);
App.vue:
<unicon name="my-test-icon"></unicon>
Although I set viewBox is the icon definition, the icon is rendered with default value of viewBox (0 0 24 24).
If I add viewBox="0 0 650 650" or even v-bind="{viewBox:'0 0 650 650'}" to the <unicon> element, it works fine. But I cannot do it since I use icons dynamically.
I read in this place that it might happen due to compilation, but the answer did not help me.
Any idea how can I achieve it?
The custom icon definition schema does not include a viewBox property, so setting it in your definition has no effect. Specifically, Vue Unicons only reads name, style, and path from the custom icon definition.
The viewBox can only be set as a prop on the <unicon> component:
<unicon name="my-custom-icon"
viewBox="0 0 32 32" 👈
width="64"
height="64" />
demo

How can I load a custom svg in SVG JS

I'm ripping apart a pong demo (https://css-tricks.com/pong-svg-js/) to learn about Javascript, SVGs, and SVG.js.
My version will draw a ball that bounces back and forth in the window. Using the "var ball = draw.circle(ballsize)" it works correctly, but when I try to substitute a custom SVG, it fails.
How can I correct this to draw my custom svg in place of the ball?
<html>
<body translate="no" >
<div id="svg-data" hidden>
<svg id="svg2" width="720" height="720" xmlns="http://www.w3.org/2000/svg">
<g>
<title>background</title>
<rect fill="none" id="canvas_background" height="602" width="802" y="-1" x="-1"/>
</g>
<g>
<title>Layer 1</title>
<g id="layer1">
<path d="m339.03,161.54001c166.28,1.498 323.57,64.413 335.55,203.73c8.98,101.9 -125.84,194.73 -292.11,194.73c-167.78,-1.5 -323.57,-62.91 -337.05,-202.18c-8.987,-103.45 127.24,-196.28 293.61,-196.28zm40.352,364.01c71.903,0 118.34,-68.954 110.85,-124.33c-16.478,-109.35 -53.928,-197.78 -152.79,-197.78c-71.903,0 -113.85,70.405 -104.86,125.83c16.571,109.4 48.029,196.28 146.8,196.28z" id="path270"/>
</g>
</g>
</svg>
</div>
<div id="pong"></div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.7.1/svg.min.js'></script>
<script id="rendered-js" >
// define document width and height
var width = 450,height = 300;
// create SVG document and set its size
var draw = SVG('pong').size(width, height);
draw.viewbox(0, 0, 450, 300);
// draw background
var background = draw.rect(width, height).fill('#dde3e1');
// define ball size
var ballSize = 10;
// original image - create ball
//var ball = draw.circle(ballSize);
// custom image - fails
var ball = draw.svg(document.getElementById('svg2').innerHTML);
ball.size(30,30);
ball.center(width / 2, height / 2).fill('#7f7f7f');
var ballDirection = -1;
var ballSpeed = 100;
function update(dt) {
ball.dmove( ballDirection * ballSpeed * dt, 0);
if (ball.cx() < 0 || ball.cx() > width) {
if (ball.cx() < 0) {
ball.cx(0);
}
else if (ball.cx() > width) {
ball.cx(width);
}
ballDirection *= -1;
}
}
var lastTime, animFrame;
function callback(ms) {
cancelAnimationFrame(animFrame);
if (lastTime) {
update((ms - lastTime) / 1000);
}
lastTime = ms;
animFrame = requestAnimationFrame(callback);
}
callback();
</script>
</body>
</html>
Let's say you have a file containing the grafics of a tennis ball. I have selected that file for its minimal size, the markup content of something you would like to use could be much larger:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36">
<circle fill="#77B255" cx="18" cy="18" r="18"/>
<path fill="#A6D388" d="M26 18c0 6.048 2.792 10.221 5.802 11.546C34.42 26.42 36 22.396 36 18c0-4.396-1.58-8.42-4.198-11.546C28.792 7.779 26 11.952 26 18z"/>
<path fill="#FFF" d="M27 18c0-6.048 1.792-10.221 4.802-11.546-.445-.531-.926-1.028-1.428-1.504C27.406 6.605 25 10.578 25 18c0 7.421 2.406 11.395 5.374 13.05.502-.476.984-.973 1.428-1.504C28.792 28.221 27 24.048 27 18z"/>
<path fill="#A6D388" d="M10 18c0-6.048-2.792-10.22-5.802-11.546C1.58 9.58 0 13.604 0 18c0 4.396 1.58 8.42 4.198 11.546C7.208 28.22 10 24.048 10 18z"/><path fill="#FFF" d="M4.198 6.454C7.208 7.78 9 11.952 9 18c0 6.048-1.792 10.22-4.802 11.546.445.531.926 1.027 1.428 1.504C8.593 29.395 11 25.421 11 18c0-7.421-2.406-11.395-5.374-13.049-.502.476-.984.972-1.428 1.503z"/>
</svg>
SVG.js would be able to reference that file in an SVG <image> tag:
var ball = draw.image('/path/to/Twemoji12 1f3be.svg').size(ballsize, ballsize)
But that has a drawback: the ball is loaded from a separate file, you need a request for that that takes time to fullfill (just like with every image file).
But the ball is just something you can write into your main file. That is where the size of your grafic markup will make a difference.
Variant 1: draw every tag separately
This is what SVG.js is really meant to do.
// draw a wrapper element, here you would use a nested `<svg>` element
var ball = draw.svg().size(ballsize, ballsize).viewbox(0 0 36 3)
// draw the circle
ball.circle(18).cx(18).cy(18).fill('#77B255')
// and so on for every tag and every attribute
Frankly: this is just more work than you probably would like to do.
Variant 2: construct the elements from strings
var ball = SVG(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36">
<circle fill="#77B255" cx="18" cy="18" r="18"/>
<path fill="#A6D388" d="M26 18c0 6.048 2.792 10.221 5.802 11.546C34.42 26.42 36 22.396 36 18c0-4.396-1.58-8.42-4.198-11.546C28.792 7.779 26 11.952 26 18z"/>
<path fill="#FFF" d="M27 18c0-6.048 1.792-10.221 4.802-11.546-.445-.531-.926-1.028-1.428-1.504C27.406 6.605 25 10.578 25 18c0 7.421 2.406 11.395 5.374 13.05.502-.476.984-.973 1.428-1.504C28.792 28.221 27 24.048 27 18z"/>
<path fill="#A6D388" d="M10 18c0-6.048-2.792-10.22-5.802-11.546C1.58 9.58 0 13.604 0 18c0 4.396 1.58 8.42 4.198 11.546C7.208 28.22 10 24.048 10 18z"/><path fill="#FFF" d="M4.198 6.454C7.208 7.78 9 11.952 9 18c0 6.048-1.792 10.22-4.802 11.546.445.531.926 1.027 1.428 1.504C8.593 29.395 11 25.421 11 18c0-7.421-2.406-11.395-5.374-13.049-.502.476-.984.972-1.428 1.503z"/>
</svg>`)
draw.add(ball).size(ballsize, ballsize)
A bit better, but at least I don't like mixing Javascript and markup inside the same file. I would go with a
Variant 3: bypass SVG.js and just write the markup in your HTML markup directly
I am saddling you with a high learning curve here, but ultimately you wanted to get that out of it, didn't you?
SVG contains its own templating mechanism, whith an element called <symbol>. Here is how your initial markup could look:
<div id="pong">
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<symbol id="ball" viewBox="0 0 36 36">
<circle fill="#77B255" cx="18" cy="18" r="18"/>
<path fill="#A6D388" d="M26 18c0 6.048 2.792 10.221 5.802 11.546C34.42 26.42 36 22.396 36 18c0-4.396-1.58-8.42-4.198-11.546C28.792 7.779 26 11.952 26 18z"/>
<path fill="#FFF" d="M27 18c0-6.048 1.792-10.221 4.802-11.546-.445-.531-.926-1.028-1.428-1.504C27.406 6.605 25 10.578 25 18c0 7.421 2.406 11.395 5.374 13.05.502-.476.984-.973 1.428-1.504C28.792 28.221 27 24.048 27 18z"/>
<path fill="#A6D388" d="M10 18c0-6.048-2.792-10.22-5.802-11.546C1.58 9.58 0 13.604 0 18c0 4.396 1.58 8.42 4.198 11.546C7.208 28.22 10 24.048 10 18z"/><path fill="#FFF" d="M4.198 6.454C7.208 7.78 9 11.952 9 18c0 6.048-1.792 10.22-4.802 11.546.445.531.926 1.027 1.428 1.504C8.593 29.395 11 25.421 11 18c0-7.421-2.406-11.395-5.374-13.049-.502.476-.984.972-1.428 1.503z"/>
</symbol>
</svg>
</div>
What did I do here?
I copied the file content inside your wrapper <div>.
Then I inserted a <symbol> element so that it wraps the grafical elements.
The <svg> element gets zero size, because it initially only contains the template (I'm simplifying.)
The viewBox attribute gets moved to the <symbol> and a unique id is added.
Now, your script can work just as before. The line
var draw = SVG('pong').size(width, height)
would just insert a second <svg> element after that first, invisible one. But you could also pickup the first one and draw there. The initial zero size gets overwritten.
var draw = SVG('#pong svg').size(width, height)
In both variants, the ball is then used in the form of a reference:
var ball = draw.use('ball').size(ballsize, ballsize)

Fontawesome Icon SVG Not shown in Firefox for Heremap Marker

I have a Here Map, within a Vue application, that shows a marker at a specific lat/lng. The marker uses an SVG from FontAwesome (with appropriately displayed attribution)
In Chrome, IE and Safari the marker displays perfectly. However, in Firefox (65.0.1 (64-bit) on MacOS) it doesn't show at all.
There are no errors thrown, it just silently refuses to display.
The code looks like this:
let img = document.createElement('img');
img.src = require('../assets/img/home-solid.svg');
const icon = new H.map.Icon(img, {
size: {
w: 55,
h: 55
}
});
const actMarker = new H.map.Marker(
{ lat: newVal.latitude, lng: newVal.longitude },
{ icon: icon }
);
this.markerGroup.addObject(actMarker);
this.map.setViewBounds(this.markerGroup.getBounds());
The SVG looks like this:
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="home" class="svg-inline--fa fa-home fa-w-18" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
<path fill="currentColor" d="M280.37 148.26L96 300.11V464a16 16 0 0 0 16 16l112.06-.29a16 16 0 0 0 15.92-16V368a16 16 0 0 1 16-16h64a16 16 0 0 1 16 16v95.64a16 16 0 0 0 16 16.05L464 480a16 16 0 0 0 16-16V300L295.67 148.26a12.19 12.19 0 0 0-15.3 0zM571.6 251.47L488 182.56V44.05a12 12 0 0 0-12-12h-56a12 12 0 0 0-12 12v72.61L318.47 43a48 48 0 0 0-61 0L4.34 251.47a12 12 0 0 0-1.6 16.9l25.5 31A12 12 0 0 0 45.15 301l235.22-193.74a12.19 12.19 0 0 1 15.3 0L530.9 301a12 12 0 0 0 16.9-1.6l25.5-31a12 12 0 0 0-1.7-16.93z">
</path>
</svg>
As I mentioned, the same code loaded in Chrome works fine.
I've looked at some answers on SO regarding Firefox and SVG but none of what I've read seem to help - e.g. ensuring the CSS class is loaded (that's coming in from the FA CDN)
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr"
crossorigin="anonymous">
Does anyone know what's going on here?
As an aside - using a PNG works fine in all browsers so this definitely seems to be SVG related.
Firefox requires that SVG documents used as images and then converted to canvas have a defined width and height.
Adding width="576px" height="512px" to your SVG document's root element will fix it.

svg-sprite: symbol conversion to single svg icon

I have a svg sprite like the following:
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" style="width:0;height:0;visibility:hidden;">
<symbol viewBox="0 0 500 500" id="test-icon"><title>test</title><ellipse class="background" id="test-background" fill="#fff" cx="248.8" cy="251.4" rx="246.2" ry="244.8"/>
<path class="test-frame" d="M249.4 18C121.1 18 16.8 122.3 16.8 250.6S121.3 483 249.4 483 482 378.8 482 250.5 377.7 18 249.4 18m0 480.8c-66 0-128.3-26.4-176.2-73.1C27.6 378.9 1.3 316.5 1.3 249.3s26.3-128.2 73.1-175 109.1-73.1 175-73.1 128.3 26.4 176.2 73.1c46.7 46.8 73.1 109.2 73.1 176.2s-26.4 128.3-73.1 176.2c-46.7 45.6-109 72.1-176.2 72.1"/>
<path class="test-figure" d="M133.8 103.5v293h232.5V148.9l-22-22-23.4-23.4H133.8zm17.9 22h108.7v12.4H151.7v-12.4zm0 24.8h108.7v12.4H151.7v-12.4zm192.5 211.8H151.7v-24.7h191.2v24.7h1.3zm0-41.2H151.7v-24.7h191.2v24.7h1.3zm0-42.7H151.7v-24.7h191.2v24.7h1.3zm0-44H151.7v-23.4h191.2v23.4h1.3z"/>
</symbol>
<symbol viewBox="0 0 500 500" id="test-icon"><title>test</title><ellipse class="background" id="test-background" fill="#fff" cx="248.8" cy="251.4" rx="246.2" ry="244.8"/>
<path class="test-frame" d="M249.4 18C121.1 18 16.8 122.3 16.8 250.6S121.3 483 249.4 483 482 378.8 482 250.5 377.7 18 249.4 18m0 480.8c-66 0-128.3-26.4-176.2-73.1C27.6 378.9 1.3 316.5 1.3 249.3s26.3-128.2 73.1-175 109.1-73.1 175-73.1 128.3 26.4 176.2 73.1c46.7 46.8 73.1 109.2 73.1 176.2s-26.4 128.3-73.1 176.2c-46.7 45.6-109 72.1-176.2 72.1"/>
<path class="test-figure" d="M133.8 103.5v293h232.5V148.9l-22-22-23.4-23.4H133.8zm17.9 22h108.7v12.4H151.7v-12.4zm0 24.8h108.7v12.4H151.7v-12.4zm192.5 211.8H151.7v-24.7h191.2v24.7h1.3zm0-41.2H151.7v-24.7h191.2v24.7h1.3zm0-42.7H151.7v-24.7h191.2v24.7h1.3zm0-44H151.7v-23.4h191.2v23.4h1.3z"/>
</symbol>
<symbol viewBox="0 0 500 500" id="test-icon"><title>test</title><ellipse class="background" id="test-background" fill="#fff" cx="248.8" cy="251.4" rx="246.2" ry="244.8"/>
<path class="test-frame" d="M249.4 18C121.1 18 16.8 122.3 16.8 250.6S121.3 483 249.4 483 482 378.8 482 250.5 377.7 18 249.4 18m0 480.8c-66 0-128.3-26.4-176.2-73.1C27.6 378.9 1.3 316.5 1.3 249.3s26.3-128.2 73.1-175 109.1-73.1 175-73.1 128.3 26.4 176.2 73.1c46.7 46.8 73.1 109.2 73.1 176.2s-26.4 128.3-73.1 176.2c-46.7 45.6-109 72.1-176.2 72.1"/>
<path class="test-figure" d="M133.8 103.5v293h232.5V148.9l-22-22-23.4-23.4H133.8zm17.9 22h108.7v12.4H151.7v-12.4zm0 24.8h108.7v12.4H151.7v-12.4zm192.5 211.8H151.7v-24.7h191.2v24.7h1.3zm0-41.2H151.7v-24.7h191.2v24.7h1.3zm0-42.7H151.7v-24.7h191.2v24.7h1.3zm0-44H151.7v-23.4h191.2v23.4h1.3z"/>
</symbol>
</svg>
Now my question is: can I just make a svg out of the symbol, just by extracting the symbol and then replacing the symbol-tag with an svg-tag? Or how can I achieve this conversion to separate svg?
I thought of a little script, that can inject several svg icons from an svg-sprite like above, so the icons can be style by css better/individually.
The thing here is that in the sprite there are symbols, which (as far as I read) can only be used with <use xlink:href>. But then the icon can't be styled individually like inline svg could be (as it is a clone).
Edit:
I found open-iconic svgIncetor that uses an img-src and single svgs to inject into the html.
Also to mention is that I alread read following articles by Chris Coyier:
http://css-tricks.com/svg-use-external-source/
http://css-tricks.com/svg-symbol-good-choice-icons/
http://css-tricks.com/icon-fonts-vs-svg/
http://css-tricks.com/svg-sprites-use-better-icon-fonts/
Basically I want to combine the technics used there to have an icon system, that can have multi-color icons based on css and icon-sprite (with inline svg through js-inject).
The open-iconic injector can only inject sinlge svgs and not from sprites afaik.
There isn't a lot you need to change (see http://jsfiddle.net/yo8bhxfu/):
Remove the view box from the SVG element
Adapt the style of the SVG element so it's visible and specifies the proper size (taken from the symbol's view box)
Convert the symbol tags into g tags
You might be on the safe side if you additionally remove the class attributes, the id attributes and the title.
<svg xmlns="http://www.w3.org/2000/svg" style="width:500px; height:500px;">
<g viewBox="0 0 500 500" id="test-icon">
<title>test</title>
<ellipse class="background" id="test-background" fill="#fff" cx="248.8" cy="251.4" rx="246.2" ry="244.8"/>
<path class="test-frame" d="M249.4 18C121.1 18 16.8 122.3 16.8 250.6S121.3 483 249.4 483 482 378.8 482 250.5 377.7 18 249.4 18m0 480.8c-66 0-128.3-26.4-176.2-73.1C27.6 378.9 1.3 316.5 1.3 249.3s26.3-128.2 73.1-175 109.1-73.1 175-73.1 128.3 26.4 176.2 73.1c46.7 46.8 73.1 109.2 73.1 176.2s-26.4 128.3-73.1 176.2c-46.7 45.6-109 72.1-176.2 72.1"/>
<path class="test-figure" d="M133.8 103.5v293h232.5V148.9l-22-22-23.4-23.4H133.8zm17.9 22h108.7v12.4H151.7v-12.4zm0 24.8h108.7v12.4H151.7v-12.4zm192.5 211.8H151.7v-24.7h191.2v24.7h1.3zm0-41.2H151.7v-24.7h191.2v24.7h1.3zm0-42.7H151.7v-24.7h191.2v24.7h1.3zm0-44H151.7v-23.4h191.2v23.4h1.3z"/>
</g>
</svg>
I have created a small script using Nodejs and svg-parser, to split a SVG icons sprite file:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="act" viewBox="0 0 48 48">
<path d="M24 22c0.552 0 1-0.448 1-1v-18c0-0.552-0.448-1-1-1s-1 0.448-1 1v18c0 0.552 0.448 1 1 1z" />
<path
d="M33.027 8.148c0 0-0.010 0.013-0.012 0.015-0.152-0.094-0.322-0.163-0.515-0.163-0.552 0-1 0.448-1 1 0 0.377 0.217 0.693 0.525 0.864 0.004 0.004-0.001 0.015 0.004 0.018 5.503 2.817 9.971 8.868 9.971 16.118 0 9.625-7.866 18-18 18-10.17 0-18-8.375-18-18 0-7.33 4.443-13.31 9.972-16.118 0.005-0.002 0-0.014 0.003-0.018 0.308-0.171 0.525-0.487 0.525-0.864 0-0.552-0.448-1-1-1-0.191 0-0.359 0.068-0.511 0.16-0.002-0.002-0.011-0.015-0.011-0.015-6.513 3.298-10.978 10.055-10.978 17.855 0 11.046 8.954 20 20 20s20-8.954 20-20c0-7.798-4.462-14.553-10.973-17.852z" />
</symbol>
...
</defs>
</svg>
const fs = require('fs');
const { parse } = require('svg-parser');
// Read from sprite file
fs.readFile('file.svg', 'utf8', function (err, contents) {
console.log(err);
const parsed = parse(contents);
const symbols = parsed.children[0].children[0].children;
symbols.forEach(symbol => {
let paths = '';
const name = symbol.properties.id;
symbol.children.forEach(path => {
paths = paths + `<path d="${path.properties.d}" />`
});
// Build SVG content
const newIcon = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50">
<g>
${paths}
</g>
</svg>`
// White to file
fs.writeFile(`export/${name}.svg`, newIcon, () => {
console.log(name);
});
});
});
I improved Bogdan's code and created a script to parse any sprite to it's original svgs.
import {toHtml} from "hast-util-to-html";
import {parse} from "svg-parser";
import * as fs from 'fs';
fs.readFile('input/path/sprite.svg', 'utf8', function (err, contents) {
const parsed = parse(contents);
const symbols = parsed.children[0].children;
symbols.forEach(symbol => {
const name = symbol.properties.id;
symbol.tagName = "svg";
let newIcon = toHtml(symbol);
fs.writeFile(`output/path/${name}.svg`, newIcon, () => {
console.log(name);
});
});
})
Just add your sprite path and the output path and it will generate the inner svgs with it's ids in the output folder.
you can find the code in this gist
I used Codo's answer, but it didn't fully work in my case. A solution that worked for the SVG i came across: (which was <use xlink:href= and the svg optimised to just <path>s)
(using Chrome or similar dev tools)
Inspect the svg, find the <use xlink:href= element
expand the element, and expand the #shadow-root (you may need to enable the Shadow DOM in your dev tools settings)
copy the svg element inside into a text editor
ensure there is a structure <g> containing the paths and shapes, like so:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480">
<g>
...
</g>
</svg>
(optional) clean up the svg using https://jakearchibald.github.io/svgomg/
save the file as .svg

Recognize point(x,y) is inside svg path or outside

I have closed SVG path that is the province of the country.
How to recognize point(x,y) is inside SVG path or outside by javascript?
For SVGGeometryElement, which includes paths and the basic shapes, there are
SVGGeometryElement.isPointInStroke() and
SVGGeometryElement.isPointInFill().
They return whether the given point is in the stroke respective in the fill, just as the name suggests.
Example:
const svg = document.getElementById("your-svg");
const path = document.getElementById("your-path");
// SVGPoint is deprecated according to MDN
let point = svg.createSVGPoint();
point.x = 40;
point.y = 32;
// or according to MDN
// let point = new DOMPoint(40, 32);
console.log("In stroke:", path.isPointInStroke(point)); // shows true
console.log("In fill:", path.isPointInFill(point)); // shows false
<svg id="your-svg" width="200" height="200">
<path d="M 10 80 C 40 10, 65 10, 95 80 S 150 10, 150 110 S 80 190, 40 140 Z" stroke="yellowgreen" stroke-width="5" fill="#adff2f77" id="your-path"/>
<!-- only to show where the point is -->
<circle id="stroke-point" cx="40" cy="32" r="2.5" fill="red" />
</svg>
Besides being more descriptive than Document.elementFromPoint() those functions handle stacked elements and pointer events correctly. Note that the above example already contains the small circle laying over the path at the requested point. It is not or only hardly possible to check this case with Document.elementFromPoint().
const svg = document.getElementById("your-svg");
const path = document.getElementById("your-path");
console.log("In stroke / fill:", svg.ownerDocument.elementFromPoint(40, 32) == path);
<svg id="your-svg" width="200" height="200">
<path d="M 10 80 C 40 10, 65 10, 95 80 S 150 10, 150 110 S 80 190, 40 140 Z" stroke="yellowgreen" stroke-width="5" fill="#adff2f77" id="your-path"/>
<!-- only to show where the point is -->
<circle id="stroke-point" cx="40" cy="32" r="2.5" fill="red" />
</svg>
Edit: Thanks to #Arlo who pointed out that the point representation object to use is not clear. MDN is using a DOMPoint (or DOMPointInit). Chrome assumed to get an SVGPoint which is deprecated according to MDN.
Note that the support on Edge and1 Internet Explorer is unknown at the moment (according to MDN).
1According to MDN Edge ≥79 supports both, isPointInStroke() and isPointInFill().
Call document.elementFromPoint. If the position is in the path then it will return that element. If the path is not filled then you may need to adjust the pointer-events property so that it works properly.

Categories

Resources