I'm trying to both stretch and rotate an image into an SVG polygon (Basically an arc).
What I need is to stretch the image to fit, not tile or clip it.
What I'd like is :
The stretched/distorted image in the arc without the image clipped.
What I have is:
Clipped arc image
Here's the fiddle I've been working on -
https://jsfiddle.net/eLrgfnxb/57/
<svg style="overflow:visible; margin-left:111px; margin-top:22px; " height="1000" width="1000">
<defs>
<pattern id="blip1" patternUnits="userSpaceOnUse" width="100%" height="100%">
<image preserveAspectRatio="none" xlink:href="http://i.imgur.com/uTDpE6J.jpg" ></image>
</pattern>
</defs>
<polygon points="453,372 67,184 70,177 73,171 77,164 81,158 85,151 88,145 92,138 97,132 101,126 105,120 110,114 114,108 115,107" x="1" y="1" style="stroke-linejoin:round; fill:url(#blip1); stroke-width:2; stroke:hsl(212,45%,26%); ">
</polygon>
</svg>
I've seen a few ones:
How to stretch an image in a SVG shape to fill its bounds? (This is where I started, but doesn't handle the arc very well)
Image to fill a polygonal SVG shape (Also doesn't handle the complicated shape)
Resize image inside polygon point path(svg) and make it not clipped
I was thinking about switching to a canvas to see if that worked. I saw a couple interesting things here:
Stretch image to fit polygon html5 canvas
Thanks for the help!
After some work, I'm able to do it by going layer by layer through the image and putting it in an isosceles triangle. Then rotating it to about the right area.
Its a bit of a hairy assumption for the arc to be an isosceles, but lets make it better later.
Updated jfiddle - http://jsfiddle.net/gobfink/w1Lake9f/210/
<!DOCTYPE html>
<html>
<body>
<p>Tiger</p>
<!--
<img id="tiger" width="220" height="277" src="http://i.imgur.com/uTDpE6J.jpg" alt="the tiger" />
-->
<img id="tiger" width="340" height="429" src="http://i.imgur.com/uTDpE6J.jpg" alt="the tiger" />
<p>TigerCanvas:</p>
<canvas id="tigerCanvas" width="500" height="500" style="border:1px solid #d3d3d3;" >
</canvas>
<p>PolygonCanvas:</p>
<canvas id="polygonCanvas" width="500" height="500" style="border:1px solid #d3d3d3;" >
</canvas>
<p>PolygonTigerCanvas</p>
<canvas id="polygonTigerCanvas" width="1000" height="500" style="border:1px solid #d3d3d3;" >
</canvas>
<p>MousePosition: </p>
<canvas id="mousePositionCanvas" width="400" height="100" style="border:1px solid #d3d3d3;" >
</canvas>
<script>
window.onload = function() {
var p_canvas=document.getElementById("polygonCanvas");
var p_ctx = p_canvas.getContext("2d");
var p_maxX,p_minX, p_maxY, p_minY;
var poly_points = [[453,372] ,[67,184], [70,177], [73,171], [77,164], [81,158], [85,151], [88,145], [92,138], [97,132], [101,126], [105,120], [110,114], [114,108], [115,107]];
p_ctx.fillStyle='#f00';
p_ctx.beginPath();
p_ctx.moveTo(poly_points[0][0],poly_points[0],[1]);
poly_points.forEach(function(point) {
if (p_minX == null || point[0] < p_minX[0] ){
p_minX = point;
}
if (p_minY == null || point[1] < p_minY[1] ){
p_minY = point;
}
if (p_maxX == null || point[0] > p_maxX[0] ){
p_maxX = point;
}
if (p_maxY == null || point[1] > p_maxY[1] ){
p_maxY = point;
}
p_ctx.lineTo(point[0],point[1]) ;
});
console.log("p_minX: ", p_minX,", p_minY: ", p_minY, ", p_maxY: ", p_maxY, ", p_maxX: ", p_maxX);
p_ctx.closePath();
p_ctx.fill();
p_ctx.font= '8px serif';
p_ctx.fillStyle='#000';
p_ctx.fillText("maxX:" + p_maxX[0] + ","+ p_maxX[1] , p_maxX[0], p_maxX[1]);
p_ctx.fillText("minX:" + p_minX[0] + ","+ p_minX[1] , p_minX[0], p_minX[1]);
p_ctx.fillText("minY:" + p_minY[0] + ","+ p_minY[1] , p_minY[0], p_minY[1]);
//p_ctx.fillText(p_maxX[0] + ","+ p_maxX[1] , p_maxX[0], p_maxX[1]);
//p_ctx.fillText(p_maxX[0] + ","+ p_maxX[1] , p_maxX[0], p_maxX[1]);
var leg_distance = Math.floor(Math.hypot(p_maxX[0] - p_minX[0],p_maxX[1] - p_minX[1]));
var base_distance = Math.floor(Math.hypot(p_minX[0]- p_minY[0], p_minX[1]-p_minY[1]));
var arc_height = Math.floor(Math.sqrt(Math.pow(leg_distance,2) - Math.pow(base_distance/2,2)));
var p1 = [0,0];
var p2 = [base_distance,0];
var p3 = [base_distance/2, arc_height];
var p13_slope = (p3[1] - p1[1]) / (p3[0] - p1[0]);
var p13_intercept = p3[1] - p13_slope * p3[0];
var p23_slope = (p3[1] - p2[1]) / (p3[0] - p2[0]);
var p23_intercept = p3[1] - p23_slope * p3[0];
var orientation_angle = Math.asin((p_maxX[0] - p_minY[0]) /leg_distance);
console.log("leg_distance:",leg_distance,", base_distance: ", base_distance, ", arc_height: ", arc_height);
console.log("p1:", p1, ", p2: ",p2,", p3: ", p3);
console.log("p13_slope:", p13_slope, ", p13_intercept: ",p13_intercept);
console.log("p23_slope:", p23_slope, ", p23_intercept: ",p23_intercept);
console.log("orientation angle: ", orientation_angle);
var c = document.getElementById("tigerCanvas");
var ctx = c.getContext("2d");
var img = document.getElementById("tiger");
//var c_height = distance;
//var c_width = img.width/img.height * distance;
img.width = img.width/img.height * leg_distance ; //normalize the width
img.height = arc_height;
//ctx.drawImage(img, 1, 1);
ctx.drawImage(img, 1, 1,img.width,img.height);//, c_width, c_height);
var p_tiger_canvas = document.getElementById("polygonTigerCanvas");
var pt_ctx = p_tiger_canvas.getContext("2d");
//Assumes MaxX== MaxY
var slopeA = (p_maxX[1] - p_minX[1])/(p_maxX[0] - p_minX[0]) ;
var slopeB = (p_maxX[1] - p_minY[1])/(p_maxX[0] - p_minY[0]) ;
var inceptA = (p_maxX[1] - slopeA * p_maxX[0]);
var inceptB = (p_maxX[1] - slopeB * p_maxX[0]);
console.log("slopeA: ",slopeA, ", slopeB: ", slopeB, ", inceptA:", inceptA, "inceptB: ",inceptB);
console.log("img.width - ", img.width, " img.height -",img.height);
pt_ctx.font= '8px serif';
pt_ctx.fillStyle='#000';
p_ctx.fillText("maxX:" + p_maxX[0] + ","+ p_maxX[1] , p_maxX[0], p_maxX[1]);
p_ctx.fillText("minX:" + p_minX[0] + ","+ p_minX[1] , p_minX[0], p_minX[1]);
p_ctx.fillText("minY:" + p_minY[0] + ","+ p_minY[1] , p_minY[0], p_minY[1]);
//pt_ctx.translate(p_maxX[0]/4,p_maxX[1]);
pt_ctx.setTransform(1,0,0,1,p_minX[0],p_minX[1])
pt_ctx.rotate(-orientation_angle);
var i;
for (i = 0; i < arc_height; i++){
var Bx = (i - inceptB) / slopeB;
var Ax = (i - inceptA) / slopeA;
var p13x = (i - p13_intercept)/ p13_slope;
var p23x = (i - p23_intercept)/ p23_slope;
var d12_23= Math.hypot( p13x-p23x ,0);
var dAB = Math.hypot(Bx-Ax,0);
//console.log("i: ", i, ", Bx - ", Bx, ", Ax - ", Ax, ", dAB - ", dAB);
pt_ctx.drawImage(c,0,i,img.width,1,p13x,i,d12_23,1);
if (i % 10 == 0){
pt_ctx.fillText(Math.round(p13x) , p13x, i);
pt_ctx.fillText(Math.round(p23x) + ","+ i , p23x, i);
}
}
var mousePositionCanvas = document.getElementById('mousePositionCanvas');
function writeMessage(canvas, message) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
context.font = '18pt Calibri';
context.fillStyle = 'black';
context.fillText(message, 10, 25);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
p_tiger_canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(p_tiger_canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(mousePositionCanvas, message);
}, false)
}
</script>
</body>
</html>
I want to scale inline SVG document in html. I have code like this:
var svg_width = svg.attr('width');
var svg_height = svg.attr('height');
function resize(width, height) {
svg.attr('width', width).attr('height', height);
var group = svg.find('#resize_group');
if (!group.length) {
group = svg.children().not('metadata, defs').wrapAll('<g/>').
parent().attr('id', 'resize_group');
}
var matrix = svg[0].createSVGMatrix();
//var matrix = group[0].getCTM();
matrix.a = width/svg_width;
matrix.d = width/svg_height;
group.attr('transform', matrix.asString());
}
SVGMatrix.prototype.asString = function() {
return 'matrix(' + this.a + ' ' + this.b + ' ' + this.c + ' ' + this.d +
' ' + this.e + ' ' + this.f + ')';
};
NOTE: I need to transform the elements inside svg because otherwise the image is trimmed.
but when I call resize function whole svg disappear. I've save svg to file and open it in Inkscape and it look normal (it's scaled). Why the svg disappear? (I tested on Firefox, Chrome and Opera)
I found quick hack, to replace svg with text of the svg to force redraw.
$.fn.xml = function() {
return (new XMLSerializer()).serializeToString(this[0]);
};
$.fn.SVGRedraw = function() {
return $(this.xml()).replaceAll(this);
};