Reputation: 643
I stucked a little.
I have a code that is working in codepen and if I paste it in opened F12 window it will work fine, so it is ok.
The idea of this svg code was that I can hover not exactly on path
, but somewhere near, for it to change color.
But I need to generate exact same code using javascipt, I wrote 2 classes, used them, they now generate same code as in codepen link, I can see it in F12 dev window, but it doesn't work.
My javascript code:
class Polyline {
// https://codepen.io/francoisromain/pen/dzoZZj
constructor(points, smoothing, fill, color) {
this.points = points;
this.smoothing = (smoothing === undefined) ? 0.2 : smoothing;
this.fill = fill;
this.color = color;
}
line (pointA, pointB) {
const lengthX = pointB[0] - pointA[0];
const lengthY = pointB[1] - pointA[1];
return {
length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),
angle: Math.atan2(lengthY, lengthX)
}
}
controlPoint (current, previous, next, reverse) {
const p = previous || current;
const n = next || current;
const o = this.line(p, n);
const angle = o.angle + (reverse ? Math.PI : 0);
const length = o.length * this.smoothing;
const x = current[0] + Math.cos(angle) * length;
const y = current[1] + Math.sin(angle) * length;
return [x, y];
}
bezierCommand(point, i, a) {
const cps = this.controlPoint(a[i - 1], a[i - 2], point);
const cpe = this.controlPoint(point, a[i - 1], a[i + 1], true);
return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`;
}
svgPath(points, svg) {
const d = points.reduce((acc, point, i, a) => i === 0
? `M ${point[0]},${point[1]}`
: `${acc} ${this.bezierCommand(point, i, a)}`
, '');
const defs = document.createElement( 'defs' );
defs.innerHTML = "<path id='poly-1' d='" + d + "' fill=" + this.fill + "></path>";
svg.appendChild(defs);
const g = document.createElement( 'g' );
g.setAttribute("id", "group");
svg.appendChild(g);
const use1 = document.createElement( 'use' );
use1.setAttribute("xlink:href", "#poly-1");
use1.setAttribute("stroke-width", "15");
use1.setAttribute("pointer-events", "stroke");
g.appendChild(use1);
const use2 = document.createElement( 'use' );
use2.setAttribute("class", "use");
use2.setAttribute("xlink:href", "#poly-1");
g.appendChild(use2);
}
draw() {
const svg = document.getElementById("chart-main-canvas");
this.svgPath(this.points, svg);
}
}
class Canvas {
constructor(w, h, color) {
this.width = w;
this.height = h;
this.color = color;
// this.scale = 1;
}
canvas() {
return `<svg width="${this.width}" height="${this.height}" id="chart-main-canvas" style="background-color: ${this.color}; z-index:5000;" ></svg>`;
}
draw() {
const c = document.getElementById("lifespan-chart-content");
c.innerHTML = this.canvas();
}
}
window.addEventListener('load', function() {
c1 = new Canvas(1000, 500, "bisque");
c1.draw();
var smoothing = 0.2;
var fill = "green";
var color = "red";
const points = [
[5, 10],
[100, 400],
[200, 400],
[355, 50],
[500, 500]
]
p1 = new Polyline(points, smoothing, fill, color);
p1.draw();
});
Why and how I can fix it?
Another additional link on working svg example:link
PS I pretty sure that the problem method is svgPath
in Polyline
class
edit 1
edited function:
svgPath(points, svg) {
const d = points.reduce((acc, point, i, a) => i === 0
? `M ${point[0]},${point[1]}`
: `${acc} ${this.bezierCommand(point, i, a)}`
, '');
const defs = document.createElementNS("http://www.w3.org/2000/svg", 'defs' );
defs.innerHTML = "<path id='poly-1' d='" + d + "' fill=" + this.fill + "></path>";
svg.appendChild(defs);
const g = document.createElementNS("http://www.w3.org/2000/svg", 'g' );
g.setAttribute("id", "group");
svg.appendChild(g);
const use1 = document.createElementNS("http://www.w3.org/2000/svg",'use' );
use1.setAttribute("xlink:href", "#poly-1");
use1.setAttribute("stroke-width", "15");
use1.setAttribute("pointer-events", "stroke");
g.appendChild(use1);
const use2 = document.createElementNS("http://www.w3.org/2000/svg", 'use' );
use2.setAttribute("class", "use");
use2.setAttribute("xlink:href", "#poly-1");
g.appendChild(use2);
}
still doesnt work
Upvotes: 0
Views: 60
Reputation: 2549
You can also use this technique to draw SVG, because it is not that simple to just innerHTML
them
// Your SVG code (formed as you wish)
const svgFromJS = `<svg width="1000" height="500" id="chart-main-canvas" style="background-color: bisque; z-index:5000;">
<defs>
<path id="poly-1" d="M 5,10 C 24,88 60.99999999999998,322 100,400 C 139,478 149,470 200,400 C 251,330 295,30.000000000000007 355,50 C 415,70 470.99999999999994,410 500,500" fill="none"></path>
</defs>
<g id="group">
<use xlink:href="#poly-1" stroke-width="15" pointer-events="stroke"></use>
<use class="use" xlink:href="#poly-1"></use>
</g>
</svg>`;
// Create a tmp container
const c = document.createElement('div');
// Add SVG to tmp container
c.innerHTML = '' + svgFromJS;
// Move childs of the SVG inside tmp container to target SVG at the body
Array.prototype.slice.call(c.childNodes[0].childNodes).forEach(function(el) {
document.getElementById('swgtodraw').appendChild(el);
});
#group .use{
stroke:red
}
#group:hover .use{
stroke: green;
}
<svg id="swgtodraw" width="1000" height="500" style="background-color: bisque; z-index:5000;"></svg>
Upvotes: 1