2015-07-26 2 views
2

Я боролся с этим в течение нескольких дней. Мой вопрос основан на коде, который вы можете найти здесь - http://codepen.io/theOneWhoKnocks/pen/VLExPX. В этом примере вы увидите 3 изображения, первые шкалы из источника [0,0], второе - из центра холста, а третье, которое я хочу масштабировать из центра смещенного изображения.Масштабное изображение в холсте со смещением начала

В основном я хочу, чтобы изображение увеличивалось или уменьшалось, но сохранялось в центре на символах радужной оболочки. Ниже вы найдете фрагмент кода, который управляет рендерингом третьего изображения.

function renderOffset(){ 
    var dims = getScaledDims(); 

    paintBG(ctx3); 
    ctx3.drawImage(loadedImg, offsetX, offsetY, dims.width, dims.height); 
    drawCenterAxis(ctx3); 
} 

После долгих Googling и глядя через форумы, я полагаю, что я должен использовать transformMatrix, но ничего я пытался до сих пор не работает. Я с нетерпением жду любых идей или предложений, которые у вас могут быть, и спасибо за ваше время.


Дальнейшее уточнение

Я создаю редактор изображений. Для конкретного случая использования, который я представляю здесь, пользователь переместил изображение влево на 108 пикселей & до 8 пикселей.

var offsetX = -108; 
var offsetY = 8; 

Когда пользователь масштабирует изображение смещения, я хочу, чтобы масштабировать в центре видимой области холста (красные перекрестия, или в этом случае символы радужки).


Update

Я обновил codepen ссылку, чтобы указать на конечный код. Ниже приведен список дополнений:

  • Добавлено в некоторый код, упомянутый в принятом ответе.
  • Добавлена ​​возможность перемещать изображение вокруг.
  • Добавлен визуальный трекер для смещения.
+0

Если все, что вам нужно сделать, это увеличение +/- в точке на изображении, то вам не нужно преобразовать матрицу. Ознакомьтесь с этим объяснением: http://stackoverflow.com/questions/27339747/zoom-and-pan-in-animated-html5-canvas/27340533#27340533 – markE

+0

@markE Я пробовал реализацию, упомянутую в приведенной ссылке Я создал этот пост. Я обновил кодировщик, и вы увидите, что это тот же результат, что и предыдущий (теперь он прокомментирован). – theOneWhoKnocks

+0

Я отправил ответ, используя 'context.drawImage', чтобы нарисовать глаз вашего мема в центре и увеличить его на холсте. Удачи с вашим проектом! :-) – markE

ответ

1

Трюк понимает, как масштаб изменяет ряд переменных. Во-первых, он изменяет, какая часть исходного изображения видна на холсте. Затем это в сочетании с желаемой центральной точкой масштабирования влияет на то, где на изображении мы должны начать рисовать.

С масштабом 1,0 количество пикселей отображаемого исходного изображения равно числу пикселей, которые имеет холст dst. I.e, если холст 150x150, мы можем видеть 150x150 входных пикселей. Если, однако, масштаб равен 2,0, то мы хотим сделать вещи в 2 раза больше. Это означает, что мы хотим отображать только 75x75 пикселей изображения src на 150x150 пикселях dst canvas. Аналогично, если мы хотим рисовать в масштабе 0,5, мы должны ожидать увидеть 300x300 пикселей изображения src, отображаемого в 150x150 dst canvas. Возможно, теперь вы можете видеть взаимосвязь между масштабом и размером холста.

Имея это в виду, мы можем определить, какую часть изображения src мы хотим видеть. Это прямо вперед:

var srcWidth = canvas.width/scale; 
var srcHeight = canvas.height/scale; 

Теперь, когда мы знаем, как большая часть изображения будет показано ниже, мы можем приступить к определению, где в изображении мы должны начать рисовать с.Поскольку мы имеем заданную центральную точку для масштабирования, мы знаем, что эта точка всегда должна оставаться в центре холста.

Если мы удалим масштабирование из уравнения и используем цифры из ранее, мы можем видеть, что мы хотим отображать 150x150 пикселей изображения src и что нам нужно будет начать рисовать 75 пикселей выше и слева от нашего центра -точка. При этом вы получите 150x150 пикселей исходного изображения и поместите нашу центральную точку справа в середину холста.

Если мы затем рассмотрим масштабирование, мы знаем, что мы не всегда будем рисовать 150x150 пикселей изображения src, а это означает, что мы не можем просто слепо запустить 75 пикселей слева и выше нашей центральной точки - нам придется масштабировать эти 75 пикселей. Поскольку эти 75 пикселей равны половине ширины и половине высоты части изображения, которую мы будем отображать, мы можем определить точку, с которой начнем рисовать изображение, разделив srcWidth и srcHeight на 2 и затем вычитая это значение из центральной точки.

Это дает следующее выражение:

ctx.drawImage(image, imgCenterX-(srcWidth/2), imgCenterY-(srcHeight/2), srcWidth, srcHeight, 0,0, canvas.width, canvas.height); 

Когда я положил обе эти вместе в образец функционирования, я закончился вверх с этим:

<!DOCTYPE html> 
<html> 
<head> 
<script> 
"use strict"; 

var imgOriginX = 182, imgOriginY = 66; 

function byId(id,parent){return (parent == undefined ? document : parent).getElementById(id);} 
window.addEventListener('load', onDocLoaded, false); 
function onDocLoaded() 
{ 
    var targetCanvas = byId('canvas3'); 
    var srcImage = byId('img1'); 

    drawImageScaled(targetCanvas, srcImage, imgOriginX, imgOriginY) 
    drawCrosshair(byId('canvas3')); 

    byId('scaleSlider').addEventListener('input', onScaleSliderChange, false); 
} 

/* 
    code for scaling an image about an arbitrary point 
*/ 

// canvas - target canvas element 
// image - target canvas element 
// imgCenterX - x coord of point of scaling centre-point (unit: pixels) 
// imgCenterY - y coord of point of scaling centre-point (unit: pixels) 
// scale - 1.0 = 100% 
function drawImageScaled(canvas, image, imgCenterX, imgCenterY, scale) 
{ 
    if (scale === undefined) 
     scale = 1.0; 

    var ctx = canvas.getContext('2d'); 
    ctx.clearRect(0,0,canvas.width,canvas.height); 

    var srcWidth = canvas.width/scale; 
    var srcHeight = canvas.height/scale; 
    ctx.drawImage(image, imgCenterX-(srcWidth/2), imgCenterY-(srcHeight/2), srcWidth, srcHeight, 0,0, canvas.width, canvas.height); 
} 

function drawCrosshair(canvas) 
{ 
    var ctx = canvas.getContext('2d'); 
    var width, height; 
    width = canvas.width; 
    height = canvas.height; 
     ctx.save(); 
    ctx.beginPath(); 
     ctx.moveTo(width/2, 0); 
     ctx.lineTo(width/2, height); 
     ctx.moveTo(0, height/2); 
     ctx.lineTo(width, height/2); 
    ctx.closePath(); 
    ctx.strokeStyle = "red"; 
    ctx.stroke(); 
    ctx.restore(); 
} 

function onScaleSliderChange(evt) 
{ 
    var curValue = this.value; 
    var scale = curValue/100; 
    var tgt, src; 

    tgt = byId('canvas3'); 
    src = byId('img1'); 
    drawImageScaled(tgt, src, imgOriginX, imgOriginY, scale); 
    drawCrosshair(tgt); 
} 

</script> 
<style> 
input[type=range] 
{ 
    width: 18px; 
    height: 122px; 
    -webkit-appearance: slider-vertical; 
} 
canvas 
{ 
    border: solid 1px #888; 
} 
</style> 
</head> 
<body> 
    <img id='img1' src='http://s4.postimg.org/r970hc9e5/meme_faces_rage_wallpaper_1.jpg'/> 
    <hr> 
    <canvas id='canvas3' width=150 height=150>Canvas not supported. :(</canvas> 
    <input id='scaleSlider' type="range" class="scale-slider js-scaleSlider" min="0" max="200" value="100" orient="vertical"/> 
</body> 
</html> 
+0

Спасибо за пример и ваш тщательный ответ. Немного поработав с кодом, у меня есть кое-что, что работает довольно хорошо сейчас.Я не на 100% доволен приращением движения после того, как пользователь масштабируется, но это может быть рассмотрено позднее. Что касается исходного вопроса, я считаю, что он ответил. Еще раз спасибо за то, что нашли время, чтобы помочь. – theOneWhoKnocks

+0

Добро пожаловать. Звучит так, как будто вы не можете правильно масштабировать шаг приращения. Точно так же, когда люди идут рисовать линию на масштабированном холсте, они часто забывают также масштабировать ширину линии, в результате получается слишком толстая или слишком тонкая линия. – enhzflep

+0

Спасибо за подробное объяснение. Для меня лично это лучшее, что я видел до сих пор по этому вопросу. У меня была позиция, но масштаб был бесполезен, и это помогло мне понять, почему. – user1059939

2

Вот как тянуть указав [eyeX, eyeY] на центр холста и увеличьте изображение:

  • Потяните глаз на холст [0,0], умножив -eeX & -eyeY на коэффициент масштабирования.
  • Наведите глаз на центр холста, добавив половину ширины холста, высоту.
  • Масштабировать изображение по коэффициенту масштабирования.
  • Используйте context.drawImage, чтобы нарисовать изображение на холсте.

Пример:

context.drawImage(

    // start with the image 
    img, 

    // scale the eyeX offset by the scaling factor 
    // and then push the image horizontally to center canvas 
    -eyeX*scale + canvas.width/2, 

    // scale the eyeY offset by the scaling factor 
    // and then push the image vertically to center canvas 
    -eyeY*scale + canvas.height/2, 

    // scale whole image by the scaling factor 
    canvas.width*scale, 
    canvas.height*scale 
); 

Иллюстрации: Centered глаз на 100% и 175%

enter image description hereenter image description here

Вот пример кода и демо:

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 
function reOffset(){ 
 
    var BB=canvas.getBoundingClientRect(); 
 
    offsetX=BB.left; 
 
    offsetY=BB.top;   
 
} 
 
var offsetX,offsetY; 
 
reOffset(); 
 
window.onscroll=function(e){ reOffset(); } 
 

 
var eyeX=182; 
 
var eyeY=66; 
 
var scale=1.00; 
 
$myslider=$('#myslider'); 
 
$myslider.attr({min:25,max:250}).val(100); 
 
$myslider.on('input change',function(){ 
 
    scale=parseInt($(this).val())/100; 
 
    drawAll(eyeX,eyeY,scale); 
 
}); 
 

 
var iw,ih; 
 
var img=new Image(); 
 
img.onload=start; 
 
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/meme_faces_rage_wallpaper_1.jpg"; 
 
function start(){ 
 
    iw=cw=canvas.width=img.width; 
 
    ih=ch=canvas.height=img.height; 
 
    drawAll(eyeX,eyeY,scale); 
 
} 
 

 
function drawAll(x,y,scale){ 
 
    ctx.clearRect(0,0,cw,ch); 
 
    centerAndZoom(x,y,scale); 
 
    drawCrosshairs();  
 
} 
 

 
function centerAndZoom(x,y,scale){ 
 
    ctx.drawImage(
 
    img, 
 
    -x*scale+iw/2, 
 
    -y*scale+ih/2, 
 
    iw*scale, 
 
    ih*scale 
 
); 
 
} 
 

 
function drawCrosshairs(){ 
 
    ctx.beginPath(); 
 
    ctx.moveTo(cw/2,0); 
 
    ctx.lineTo(cw/2,ch); 
 
    ctx.moveTo(0,ch/2); 
 
    ctx.lineTo(cw,ch/2); 
 
    ctx.stroke(); 
 
}
body{ background-color: white; } 
 
#canvas{border:1px solid red; margin:0 auto; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> 
 
Scale:&nbsp;<input id=myslider type=range><br> 
 
<canvas id="canvas" width=300 height=300></canvas>

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