diff --git a/dev/interact/svg-ellipse.html b/dev/interact/svg-ellipse.html new file mode 100644 index 000000000..bca5b19b3 --- /dev/null +++ b/dev/interact/svg-ellipse.html @@ -0,0 +1,76 @@ + + + + + + SVG demo + + + + + + +
+
+
+ +
+ +
+ +
+
+ + + + + diff --git a/js/canvas2svg.js b/js/canvas2svg.js index 259fa3756..8ea8099e7 100644 --- a/js/canvas2svg.js +++ b/js/canvas2svg.js @@ -82,7 +82,7 @@ function getDominantBaseline(textBaseline) { function normalize(vector) { var len = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]); return [vector[0] / len, vector[1] / len]; -}; +} function intersectRect(rect1, rect2) { @@ -910,7 +910,7 @@ class ctx { x += width; width = -width; } - // See if rect instersects current viewbox + // See if rect intersects current viewbox var r2 = { x: x, y: y, @@ -953,6 +953,32 @@ class ctx { this.__applyStyleToCurrentElement("stroke"); }; + // stroke ellipse + strokeEllipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW) { + this.__ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, 'stroke') + } + + // fill ellipse + fillEllipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW) { + this.__ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, 'fill') + } + + // ellipse helper + __ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, isCCW, style) { + + const config = + { + cx, + cy, + rx, + ry + } + const element = this.__createElement('ellipse', config, true) + const parent = this.__closestGroupOrSvg() + parent.appendChild(element) + this.__currentElement = element + this.__applyStyleToCurrentElement(style) + } /** * Clear entire canvas: diff --git a/js/feature/interactionTrack.js b/js/feature/interactionTrack.js index 2e1c14105..0ed758be3 100644 --- a/js/feature/interactionTrack.js +++ b/js/feature/interactionTrack.js @@ -264,10 +264,10 @@ class InteractionTrack extends TrackBase { const xScale = bpPerPixel; // SVG output for proportional arcs are currently not supported because "ellipse" is not implemented - if(typeof ctx.ellipse !== 'function') { - Alert.presentAlert("SVG output of proportional arcs is currently not supported.") - return; - } + // if(typeof ctx.ellipse !== 'function') { + // Alert.presentAlert("SVG output of proportional arcs is currently not supported.") + // return; + // } IGVGraphics.fillRect(ctx, 0, options.pixelTop, pixelWidth, pixelHeight, {'fillStyle': "rgb(255, 255, 255)"}); @@ -310,9 +310,14 @@ class InteractionTrack extends TrackBase { const color = feature.color || this.color; ctx.strokeStyle = color; ctx.lineWidth = feature.thickness || this.thickness || 1; - ctx.beginPath(); - ctx.ellipse(xc, y, radiusX, radiusY, 0, 0, Math.PI, counterClockwise); - ctx.stroke(); + + if (true === ctx.isSVG) { + ctx.strokeEllipse(xc, y, radiusX, radiusY, 0, 0, Math.PI, counterClockwise) + } else { + ctx.beginPath() + ctx.ellipse(xc, y, radiusX, radiusY, 0, 0, Math.PI, counterClockwise) + ctx.stroke() + } if (this.showBlocks && feature.chr !== 'all') { ctx.fillStyle = color; @@ -326,9 +331,13 @@ class InteractionTrack extends TrackBase { } if (this.alpha) { - const alphaColor = getAlphaColor(color, this.alpha); - ctx.fillStyle = alphaColor; - ctx.fill(); + ctx.fillStyle = getAlphaColor(color, this.alpha) + if (true === ctx.isSVG) { + ctx.fillEllipse(xc, y, radiusX, radiusY, 0, 0, Math.PI, counterClockwise) + } else { + ctx.fill() + } + } feature.drawState = {xc, yc: y, radiusX, radiusY};