2015-12-23 3 views
0

Есть ли обходной путь для реализации SVG's preserveAspectRatio = "xMinYMin slice" для метода drawImage() в холсте?Как реализовать SVG saveAspectRatio = "xMinYMin slice" для метода drawImage холста.

+0

вы имеете в виду, когда '' img' в DrawImage (IMG, х, у) 'относится к документу SVG или просто реализовать такую ​​же функциональность как этот атрибут для любого изображения? – Kaiido

+0

Я хочу сохранить соотношение сторон изображений внутри холста, используя метод drawImage(), как это делается в svg's preserveAspectRatio = "xMinYMin slice". – Randika

ответ

1

Ken's answer в отмеченном как повторяющийся ответ действительно выполняет ту же операцию, что и xMinYMin slice, если вы называете это drawImageProp(ctx, img, 0, 0, canvas.width, canvas.height, 0, 0).

Но для тех, кто хочет в полной реализации атрибута SVG в preserveAspectRatio, вот один:

Он возвращает объект с sx,sy,sw,sh,dx,dy,dw,dh по требованию метода drawImage().

\t var preserveAspectRatio = function(source, destination, userString) { 
 

 
\t var srcWidth = source.width, 
 
\t  srcHeight = source.height, 
 
\t  destinationW = destination.width, 
 
\t  destinationH = destination.height; 
 

 
\t // we should keep the whole source 
 
\t var aRMeet = function(args) { 
 

 
\t  var srcRatio = (srcHeight/srcWidth), 
 
\t  destRatio = (destinationH/destinationW), 
 

 
\t  resultWidth = destRatio > srcRatio ? destinationW : destinationH/srcRatio, 
 
\t  resultHeight = destRatio > srcRatio ? destinationW * srcRatio : destinationH; 
 

 
\t  var getPos = function(arg, res, dest) { 
 

 
\t  var max = Math.max(res, dest), 
 
\t   min = Math.min(res, dest); 
 

 
\t  switch (arg) { 
 
\t   case 'Min': return 0; 
 
\t   case 'Mid': return (max - min)/2; 
 
\t   case 'Max': return max - min; 
 
\t   default: return 'invalid'; 
 
\t  } 
 
\t  }; 
 

 
\t  var obj = { 
 
\t  img: returnedImg, 
 
\t  sx: 0, 
 
\t  sy: 0, 
 
\t  swidth: srcWidth, 
 
\t  sheight: srcHeight, 
 
\t  dx: getPos(args[0], resultWidth, destinationW), 
 
\t  dy: getPos(args[1], resultHeight, destinationH), 
 
\t  dwidth: resultWidth, 
 
\t  dheight: resultHeight 
 
\t  }; 
 

 
\t  if (obj[5] === 'invalid' || obj[6] === 'invalid') { 
 
\t  return default_obj; 
 
\t  } 
 

 
\t  return obj; 
 
\t }; 
 

 
\t // we should slice the larger part 
 
\t var aRSlice = function(args) { 
 

 
\t  var resultWidth, resultHeight; 
 

 
\t  var a = function() { 
 
\t  resultWidth = destinationW; 
 
\t  resultHeight = srcHeight * destinationW/srcWidth; 
 
\t  }; 
 

 
\t  var b = function() { 
 
\t  resultWidth = srcWidth * destinationH/srcHeight; 
 
\t  resultHeight = destinationH; 
 
\t  }; 
 

 
\t  if (destinationW > destinationH) { 
 
\t  a(); 
 
\t  if (destinationH > resultHeight) { 
 
\t   b(); 
 
\t  } 
 
\t  } else if (destinationW === destinationH) { 
 
\t  if (srcWidth > srcHeight) { 
 
\t   b(); 
 
\t  } else { 
 
\t   a(); 
 
\t  } 
 
\t  } else { 
 
\t  b(); 
 
\t  if (destinationW > resultWidth) { 
 
\t   a(); 
 
\t  } 
 
\t  } 
 

 
\t  var getPos = function(arg, res, dest, src) { 
 
\t  switch (arg) { 
 
\t   case 'Min': return 0; 
 
\t   case 'Mid': return (res - dest)/2 * src/res; 
 
\t   case 'Max': return (res - dest) * src/res; 
 
\t   default: return 'invalid'; 
 
\t  } 
 
\t  }; 
 

 
\t  var x = getPos(args[0], resultWidth, destinationW, srcWidth); 
 
\t  var y = getPos(args[1], resultHeight, destinationH, srcHeight); 
 

 
\t  var obj = { 
 
\t  img: returnedImg, 
 
\t  sx: x, 
 
\t  sy: y, 
 
\t  swidth: srcWidth - x, 
 
\t  sheight: srcHeight - y, 
 
\t  dx: 0, 
 
\t  dy: 0, 
 
\t  dwidth: resultWidth - (x * (resultWidth/srcWidth)), 
 
\t  dheight: resultHeight - (y * (resultHeight/srcHeight)), 
 
\t  }; 
 

 
\t  if (obj[1] === 'invalid' || obj[2] === 'invalid') { 
 
\t  return default_obj; 
 
\t  } 
 

 
\t  return obj; 
 
\t }; 
 

 
\t // check if the object passed was drawable over a canvas 
 
\t var returnedImg = source.nodeName === 'IMG' || source.nodeName === 'VIDEO' || source.nodeName === 'CANVAS' ? source : null; 
 

 
\t // if an invalid string or none is set as the preserveAspectRatio, this should be considered as "xMidYMid meet" 
 
\t var default_obj = aRMeet(['Mid', 'Mid']); 
 

 
\t if (!userString) { 
 
\t  return default_obj; 
 
\t } else { 
 

 
\t  var args = userString.trim().split(' '), 
 
\t  minMidMax = args[0].replace('x', '').split('Y'); 
 

 
\t  switch (args[args.length - 1]) { 
 
\t  case "meet": return aRMeet(minMidMax); 
 
\t  case "slice": return aRSlice(minMidMax); 
 
\t  default:  return default_obj; 
 
\t  } 
 
\t } 
 
\t }; 
 

 
\t // 
 
\t // Snippet code 
 
\t //_______________ 
 

 
\t var images = [new Image(), new Image(), new Image()]; 
 
\t var img = images[0]; 
 
\t var selects = document.querySelectorAll('select'); 
 

 
\t var ctxL = outputLandscape.getContext('2d'); 
 
\t var ctxP = outputPortrait.getContext('2d'); 
 
\t var ctxS = outputSquare.getContext('2d'); 
 

 
\t var update = function() { 
 
\t ctxL.clearRect(0, 0, outputLandscape.width, outputLandscape.height); 
 
\t ctxP.clearRect(0, 0, outputPortrait.width, outputPortrait.height); 
 
\t ctxS.clearRect(0, 0, outputSquare.width, outputSquare.height); 
 

 
\t var aspectRatioStr = 'x' + selects[0].value + 'Y' + selects[1].value + ' ' + selects[2].value; 
 

 
\t var p = preserveAspectRatio(img, outputPortrait, aspectRatioStr); 
 
\t ctxP.drawImage(p.img, p.sx, p.sy, p.swidth, p.sheight, p.dx, p.dy, p.dwidth, p.dheight); 
 

 
\t var l = preserveAspectRatio(img, outputLandscape, aspectRatioStr); 
 
\t ctxL.drawImage(l.img, l.sx, l.sy, l.swidth, l.sheight, l.dx, l.dy, l.dwidth, l.dheight); 
 

 
\t var s = preserveAspectRatio(img, outputSquare, aspectRatioStr); 
 
\t ctxS.drawImage(s.img, s.sx, s.sy, s.swidth, s.sheight, s.dx, s.dy, s.dwidth, s.dheight); 
 

 
\t svgImagePortrait.setAttribute('preserveAspectRatio', aspectRatioStr); 
 
\t svgImageLandscape.setAttribute('preserveAspectRatio', aspectRatioStr); 
 
\t svgImageSquare.setAttribute('preserveAspectRatio', aspectRatioStr); 
 
\t }; 
 

 
\t for (var i = 0; i < selects.length - 1; i++) { 
 
\t selects[i].onchange = update; 
 
\t } 
 
\t selects[3].onchange = function() { 
 
\t img = images[+this.value]; 
 
\t update(); 
 
\t svgImagePortrait.setAttributeNS('http://www.w3.org/1999/xlink', 'href', img.src); 
 
\t svgImageLandscape.setAttributeNS('http://www.w3.org/1999/xlink', 'href', img.src); 
 
\t svgImageSquare.setAttributeNS('http://www.w3.org/1999/xlink', 'href', img.src); 
 

 
\t } 
 

 
\t img.onload = function() { 
 
\t svgImagePortrait.setAttributeNS('http://www.w3.org/1999/xlink', 'href', this.src); 
 
\t svgImageLandscape.setAttributeNS('http://www.w3.org/1999/xlink', 'href', this.src); 
 
\t svgImageSquare.setAttributeNS('http://www.w3.org/1999/xlink', 'href', this.src); 
 

 
\t update(); 
 
\t }; 
 

 

 
\t images[0].src = "http://lorempixel.com/100/200"; 
 
\t images[1].src = "http://lorempixel.com/200/100"; 
 
\t images[2].src = "http://lorempixel.com/200/200";
html,body,canvas { 
 
    margin: 0; 
 
    display: block; 
 
    font-size: .9em; 
 
} 
 
svg,canvas { 
 
    display: inline-block; 
 
} 
 
canvas { 
 
    border: 1px solid green; 
 
} 
 
svg { 
 
    border: 1px solid blue; 
 
}
x 
 
<select name="x"> 
 
    <option value="Min">Min</option> 
 
    <option value="Mid">Mid</option> 
 
    <option value="Max">Max</option> 
 
</select> 
 
Y 
 
<select name="Y"> 
 
    <option value="Min">Min</option> 
 
    <option value="Mid">Mid</option> 
 
    <option value="Max">Max</option> 
 
</select> 
 

 
<select name="slice_meet"> 
 
    <option value="slice">slice</option> 
 
    <option value="meet">meet</option> 
 
</select> 
 
image format : 
 
<select name="format"> 
 
    <option value="0">portrait</option> 
 
    <option value="1">landscape</option> 
 
    <option value="2">square</option> 
 
</select> 
 
<br> 
 

 
<canvas id="outputLandscape" width="280" height="200"></canvas> 
 
<svg width="280" height="200" viewBox="0 0 280 200"> 
 
    <image id="svgImageLandscape" x="0" y="0" width="100%" height="100%"></image> 
 
</svg> 
 
<br> 
 
<canvas id="outputPortrait" width="200" height="280"></canvas> 
 
<svg width="200" height="280" viewBox="0 0 200 280"> 
 
    <image id="svgImagePortrait" x="0" y="0" width="100%" height="100%"></image> 
 
</svg> 
 
<br> 
 
<canvas id="outputSquare" width="200" height="200"></canvas> 
 
<svg width="200" height="200" viewBox="0 0 200 200"> 
 
    <image id="svgImageSquare" x="0" y="0" width="100%" height="100%"></image> 
 
</svg>

+0

Я также попробую это. Спасибо за ответ. – Randika

Смежные вопросы