एक बिंदु पर ज़ूम (पैमाने और अनुवाद का उपयोग करके)


156

मैं एक HTML 5 कैनवास में माउस के नीचे बिंदु पर ज़ूम करने में सक्षम होना चाहता हूं, जैसे कि Google मैप्स पर ज़ूम करना । मैं उसे कैसे प्राप्त कर सकता हूं?


2
मैंने अपने कैनवास को ज़ूम करने के लिए इसका इस्तेमाल किया और यह बहुत अच्छा काम करता है! मुझे केवल इतना जोड़ना है कि ज़ूम राशि की गणना वैसी नहीं है जैसी आप अपेक्षा करेंगे। "var zoom = 1 + व्हील / 2;" इसका अर्थ है कि ज़ूम इन करने के लिए 1.5 और ज़ूम आउट करने के लिए 0.5 में परिणाम है। मैंने इसे अपने संस्करण में संपादित किया है ताकि मेरे पास ज़ूम इन करने के लिए 1.5 और ज़ूमिंग के लिए 1 / 1.5 हो जो ज़ूम इन करने और ज़ूम आउट करने की मात्रा को बराबर बनाता है। इसलिए यदि आप एक बार ज़ूम इन करते हैं और ज़ूम इन करते हैं तो आपके पास ज़ूमिंग से पहले की तस्वीर होगी।
क्रिस

2
ध्यान दें कि यह फ़ायरफ़ॉक्स पर काम नहीं करता है, लेकिन इस विधि को आसानी से jQuery mousewheel प्लगइन पर लागू किया जा सकता है । साझा करने के लिए धन्यवाद!
जॉन्डोडो

2
var ज़ूम = Math.pow (1.5f, पहिया); // जूम की गणना के लिए इसका उपयोग करें। इसका लाभ यह है कि पहिया = 2 से जूम करना पहिया = 1 द्वारा दो बार ज़ूम करने के समान है। इसके अलावा, +2 से ज़ूम आउट और +2 द्वारा मूल स्केल को पुनर्स्थापित करता है।
मैट

जवाबों:


126

बेहतर उपाय यह है कि जूम में बदलाव के आधार पर बस व्यूपोर्ट की स्थिति को आगे बढ़ाया जाए। ज़ूम पॉइंट पुराने ज़ूम और नए ज़ूम का बिंदु है जिसे आप एक ही रहना चाहते हैं। कहने का मतलब यह है कि व्यूपोर्ट को ज़ूम करके प्री-ज़ूम किया गया है और व्यूपोर्ट पोस्ट-ज़ूमेड के व्यूपोर्ट के समान ज़ूमपॉइंट है। यह देखते हुए कि हम मूल के सापेक्ष स्केलिंग कर रहे हैं। आप तदनुसार व्यूपोर्ट की स्थिति को समायोजित कर सकते हैं:

scalechange = newscale - oldscale;
offsetX = -(zoomPointX * scalechange);
offsetY = -(zoomPointY * scalechange);

तो वास्तव में आप बस ऊपर और नीचे पैन कर सकते हैं जब आप ज़ूम इन करते हैं, तो आपके द्वारा ज़ूम किए गए बिंदु के सापेक्ष आप कितना ज़ूम इन करते हैं।

यहाँ छवि विवरण दर्ज करें


2
कट और पेस्ट कोड से अधिक मूल्यवान यह स्पष्टीकरण है कि सबसे अच्छा समाधान क्या है और यह सामान के बिना क्यों काम करता है, खासकर अगर यह तीन पंक्तियों का लंबा हो।
ताताराइज़ करें

2
scalechange = newscale / oldscale?
तेजेश अलीमिल्ली

4
इसके अलावा, मैं पैन-ज़ूम घटक जैसे मानचित्र को प्राप्त करने के इच्छुक लोगों के लिए जोड़ना चाहूंगा कि माउस X, Y होना चाहिए (mousePosRelativeToContainer - currentTransform) / currentScale अन्यथा यह वर्तमान माउस स्थिति को कंटेनर के सापेक्ष व्यवहार करेगा।
गिलाद

1
हां, यह गणित मानता है कि ज़ूम के साथ-साथ पैन मूल के लिए संबंधित कोर्ड्स में हैं। यदि वे व्यूपोर्ट के सापेक्ष हैं, तो आपको उन्हें उचित रूप से समायोजित करना होगा। हालांकि मुझे लगता है कि सही गणित zoomPoint = (mousePosRelativeToContainer + currentTranslation) है। यह गणित यह भी मानता है कि मूल बिंदु आमतौर पर क्षेत्र के ऊपरी बाएं भाग में है। लेकिन, थोड़ा सा असामान्य परिस्थितियों के लिए समायोजन करना बहुत आसान है, सरलता को देखते हुए।
ताताराइज़ करें

1
@ C.Finke ctx के भीतर अनुवाद का उपयोग करके दूसरा तरीका यह किया जा सकता है। आप सब कुछ समान आकार और समान स्थितियों में आकर्षित करते हैं। लेकिन, आप केवल संदर्भ के पैन और स्केल (ज़ूम) को सेट करने के लिए जावास्क्रिप्ट कैनवास के भीतर मैट्रिक्स गुणा का उपयोग करते हैं। तो एक अलग स्थान में सभी आकार redraw के बजाय। आप उन्हें उसी स्थान पर आकर्षित करते हैं और जावास्क्रिप्ट के भीतर व्यूपोर्ट को स्थानांतरित करते हैं। इस विधि के लिए यह भी आवश्यक होगा कि आप माउस घटनाओं को लें और उन्हें पीछे की ओर अनुवाद करें। तो आप पैन को घटाएंगे, फिर ज़ूम द्वारा कारक को उल्टा करेंगे।
ताताराइज करें

68

अंत में इसे हल किया:

var zoomIntensity = 0.2;

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var width = 600;
var height = 200;

var scale = 1;
var originx = 0;
var originy = 0;
var visibleWidth = width;
var visibleHeight = height;


function draw(){
    // Clear screen to white.
    context.fillStyle = "white";
    context.fillRect(originx,originy,800/scale,600/scale);
    // Draw the black square.
    context.fillStyle = "black";
    context.fillRect(50,50,100,100);
}
// Draw loop at 60FPS.
setInterval(draw, 1000/60);

canvas.onwheel = function (event){
    event.preventDefault();
    // Get mouse offset.
    var mousex = event.clientX - canvas.offsetLeft;
    var mousey = event.clientY - canvas.offsetTop;
    // Normalize wheel to +1 or -1.
    var wheel = event.deltaY < 0 ? 1 : -1;

    // Compute zoom factor.
    var zoom = Math.exp(wheel*zoomIntensity);
    
    // Translate so the visible origin is at the context's origin.
    context.translate(originx, originy);
  
    // Compute the new visible origin. Originally the mouse is at a
    // distance mouse/scale from the corner, we want the point under
    // the mouse to remain in the same place after the zoom, but this
    // is at mouse/new_scale away from the corner. Therefore we need to
    // shift the origin (coordinates of the corner) to account for this.
    originx -= mousex/(scale*zoom) - mousex/scale;
    originy -= mousey/(scale*zoom) - mousey/scale;
    
    // Scale it (centered around the origin due to the trasnslate above).
    context.scale(zoom, zoom);
    // Offset the visible origin to it's proper position.
    context.translate(-originx, -originy);

    // Update scale and others.
    scale *= zoom;
    visibleWidth = width / scale;
    visibleHeight = height / scale;
}
<canvas id="canvas" width="600" height="200"></canvas>

जैसा कि @Tatarize ने बताया , कुंजी , अक्ष की स्थिति की गणना करना है जैसे कि ज़ूम पॉइंट (माउस पॉइंटर) ज़ूम के बाद उसी स्थान पर रहता है।

मूल रूप से माउस mouse/scaleकोने से कुछ दूरी पर है , हम चाहते हैं कि ज़ूम के बाद माउस के नीचे बिंदु उसी स्थान पर रहे, लेकिन यह mouse/new_scaleकोने से दूर है। इसलिए हमें इसके लिए origin(कोने के निर्देशांक) को स्थानांतरित करने की आवश्यकता है ।

originx -= mousex/(scale*zoom) - mousex/scale;
originy -= mousey/(scale*zoom) - mousey/scale;
scale *= zoom

शेष कोड को स्केलिंग लागू करने और ड्रॉ के संदर्भ में अनुवाद करने की आवश्यकता होती है, इसलिए यह मूल रूप से कैनवास के कोने के साथ मेल खाता है।


शुक्रिया दोस्त, आपका कोड खोजने से पहले 2 दिन, लगभग खो गए
वेलारो

अरे मैं बस कुछ इस तरह की तलाश कर रहा था और सिर्फ यह कहना चाहता था कि आप इसे फटा है!
क्रिसिलिक

26

यह वास्तव में एक बहुत ही कठिन समस्या है (गणितीय रूप से), और मैं लगभग एक ही चीज पर काम कर रहा हूं। मैंने Stackoverflow पर एक समान प्रश्न पूछा, लेकिन कोई प्रतिक्रिया नहीं मिली, लेकिन DocType (HTML / CSS के लिए StackOverflow) में पोस्ट किया गया और उसे प्रतिक्रिया मिली। इसे देखें http://doctype.com/javascript-image-zoom-css3-transforms-calculate-origin-example

मैं एक jQuery प्लगइन के निर्माण के बीच में हूँ जो ऐसा करता है (CSS3 ट्रांसफ़ॉर्म का उपयोग करके Google मैप्स शैली ज़ूम)। मुझे ज़ूम टू माउस कर्सर बिट ठीक काम कर रहा है, फिर भी यह पता लगाने की कोशिश कर रहा है कि उपयोगकर्ता को कैनवास को चारों ओर खींचने की अनुमति कैसे दी जाए जैसे आप Google मानचित्र में कर सकते हैं। जब मुझे यह काम मिलेगा तो मैं यहां कोड पोस्ट कर दूंगा, लेकिन माउस-ज़ूम-टू-पॉइंट भाग के लिए ऊपर दिए गए लिंक को देखें।

मुझे नहीं पता था कि कैनवस के संदर्भ में पैमाने और अनुवाद के तरीके हैं, आप CSS3 जैसे का उपयोग करके एक ही चीज़ प्राप्त कर सकते हैं। jQuery का उपयोग:

$('div.canvasContainer > canvas')
    .css('-moz-transform', 'scale(1) translate(0px, 0px)')
    .css('-webkit-transform', 'scale(1) translate(0px, 0px)')
    .css('-o-transform', 'scale(1) translate(0px, 0px)')
    .css('transform', 'scale(1) translate(0px, 0px)');

सुनिश्चित करें कि आपने CSS3 का रूपांतरण-मूल 0, 0 (-moz- परिवर्तन-मूल: 0 0) सेट किया है। CSS3 के ट्रांसफ़ॉर्मेशन का उपयोग करने से आप किसी भी चीज़ को ज़ूम इन कर सकते हैं, बस सुनिश्चित करें कि कंटेनर DIV को ओवरफ़्लो करने के लिए सेट किया गया है: ज़ूम आउट किए गए किनारों को साइड से बाहर रोकने के लिए छिपा हुआ है।

चाहे आप CSS3 ट्रांसफ़ॉर्म का उपयोग करें, या कैनवास के अपने पैमाने और अनुवाद के तरीके आपके ऊपर हैं, लेकिन गणना के लिए उपरोक्त लिंक की जांच करें।


अपडेट: मेह! मैं आपको लिंक का अनुसरण करने के लिए केवल कोड यहाँ पोस्ट करूँगा:

$(document).ready(function()
{
    var scale = 1;  // scale of the image
    var xLast = 0;  // last x location on the screen
    var yLast = 0;  // last y location on the screen
    var xImage = 0; // last x location on the image
    var yImage = 0; // last y location on the image

    // if mousewheel is moved
    $("#mosaicContainer").mousewheel(function(e, delta)
    {
        // find current location on screen 
        var xScreen = e.pageX - $(this).offset().left;
        var yScreen = e.pageY - $(this).offset().top;

        // find current location on the image at the current scale
        xImage = xImage + ((xScreen - xLast) / scale);
        yImage = yImage + ((yScreen - yLast) / scale);

        // determine the new scale
        if (delta > 0)
        {
            scale *= 2;
        }
        else
        {
            scale /= 2;
        }
        scale = scale < 1 ? 1 : (scale > 64 ? 64 : scale);

        // determine the location on the screen at the new scale
        var xNew = (xScreen - xImage) / scale;
        var yNew = (yScreen - yImage) / scale;

        // save the current screen location
        xLast = xScreen;
        yLast = yScreen;

        // redraw
        $(this).find('div').css('-moz-transform', 'scale(' + scale + ')' + 'translate(' + xNew + 'px, ' + yNew + 'px' + ')')
                           .css('-moz-transform-origin', xImage + 'px ' + yImage + 'px')
        return false;
    });
});

आप निश्चित रूप से कैनवास पैमाने और अनुवाद के तरीकों का उपयोग करने के लिए इसे अनुकूलित करने की आवश्यकता होगी।


अपडेट 2: बस ध्यान दें कि मैं ट्रांसलेशन-मूल का अनुवाद के साथ उपयोग कर रहा हूं। मैं एक ऐसे संस्करण को लागू करने में कामयाब रहा हूं जो सिर्फ स्केल और ट्रांसलेशन का उपयोग करता है, इसे यहां देखेंhttp://www.dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html छवियों का डाउनलोड करने के लिए इंतजार करें फिर अपना उपयोग करें ज़ूम करने के लिए माउस व्हील, छवि को चारों ओर खींचकर पैनिंग का भी समर्थन करता है। यह CSS3 के ट्रांसफ़ॉर्म का उपयोग कर रहा है, लेकिन आपको अपने कैनवस के लिए समान गणनाओं का उपयोग करने में सक्षम होना चाहिए।


मैं अंत में इसे हल कर दिया, मुझे कुछ और करने के 2weeks के बाद अब 3 मिनट लग गए
csiz

उनके अपडेट पर @Synday Ironfoot लिंक काम नहीं कर रहा है। यह लिंक: dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html मैं यह आवेग चाहता हूं। क्या आप यहां कोड पोस्ट कर सकते हैं? धन्यवाद
बोगज़

2
आज के रूप में (sept.2014) MosaicTest.html का लिंक मृत है।
क्रिस

मोज़ेक डेमो चला गया है। मैं आमतौर पर वैनिला js का उपयोग करता हूं और jQuery का नहीं। $ (यह) किसका जिक्र है? document.body.offsetTop? मैं वास्तव में मोज़ेक डेमो देखना चाहता हूं, मेरा माईस्केपस्केप.कॉम प्रोजेक्ट वास्तव में इससे लाभान्वित हो सकता है।
फ्लेवर्डस्केप

2
मोज़ेक डेमो पेज को आर्काइव.ऑर्ग
क्रिस

9

मैं सी ++ का उपयोग करके इस समस्या में भाग गया, जो शायद मुझे नहीं होना चाहिए था कि मैंने ओपनगेल मेट्रिसेस का इस्तेमाल शुरू करने के लिए किया था ... वैसे भी, यदि आप एक नियंत्रण का उपयोग कर रहे हैं जिसका मूल शीर्ष बाएं कोने है, और आप पैन / ज़ूम चाहते हैं Google नक्शे की तरह, यहां लेआउट (मेरे इवेंट हैंडलर के रूप में एलीग्रो का उपयोग करके):

// initialize
double originx = 0; // or whatever its base offset is
double originy = 0; // or whatever its base offset is
double zoom = 1;

.
.
.

main(){

    // ...set up your window with whatever
    //  tool you want, load resources, etc

    .
    .
    .
    while (running){
        /* Pan */
        /* Left button scrolls. */
        if (mouse == 1) {
            // get the translation (in window coordinates)
            double scroll_x = event.mouse.dx; // (x2-x1) 
            double scroll_y = event.mouse.dy; // (y2-y1) 

            // Translate the origin of the element (in window coordinates)      
            originx += scroll_x;
            originy += scroll_y;
        }

        /* Zoom */ 
        /* Mouse wheel zooms */
        if (event.mouse.dz!=0){    
            // Get the position of the mouse with respect to 
            //  the origin of the map (or image or whatever).
            // Let us call these the map coordinates
            double mouse_x = event.mouse.x - originx;
            double mouse_y = event.mouse.y - originy;

            lastzoom = zoom;

            // your zoom function 
            zoom += event.mouse.dz * 0.3 * zoom;

            // Get the position of the mouse
            // in map coordinates after scaling
            double newx = mouse_x * (zoom/lastzoom);
            double newy = mouse_y * (zoom/lastzoom);

            // reverse the translation caused by scaling
            originx += mouse_x - newx;
            originy += mouse_y - newy;
        }
    }
}  

.
.
.

draw(originx,originy,zoom){
    // NOTE:The following is pseudocode
    //          the point is that this method applies so long as
    //          your object scales around its top-left corner
    //          when you multiply it by zoom without applying a translation.

    // draw your object by first scaling...
    object.width = object.width * zoom;
    object.height = object.height * zoom;

    //  then translating...
    object.X = originx;
    object.Y = originy; 
}

9

मुझे ताताराइज़ का उत्तर पसंद है , लेकिन मैं एक विकल्प प्रदान करूँगा। यह एक तुच्छ रैखिक बीजगणित समस्या है, और जो विधि मैंने प्रस्तुत की है वह पैन, ज़ूम, तिरछा आदि के साथ अच्छी तरह से काम करती है, अर्थात, यदि आपकी छवि पहले से ही बदल गई है तो यह अच्छी तरह से काम करती है।

जब एक मैट्रिक्स को स्केल किया जाता है, तो स्केल बिंदु (0, 0) पर होता है। इसलिए, यदि आपके पास एक छवि है और इसे 2 के कारक से मापते हैं, तो तल-दाएं बिंदु x और y दोनों दिशाओं में दोगुना हो जाएगा (सम्मेलन का उपयोग करते हुए [0, 0] छवि का शीर्ष-बाएँ है)।

यदि इसके बजाय आप केंद्र के बारे में छवि को ज़ूम करना चाहते हैं, तो एक समाधान इस प्रकार है: (1) छवि का अनुवाद ऐसे करें कि उसका केंद्र (0, 0) पर हो; (2) एक्स और वाई कारकों द्वारा छवि को स्केल करें; (3) छवि का वापस अनुवाद करें। अर्थात

myMatrix
  .translate(image.width / 2, image.height / 2)    // 3
  .scale(xFactor, yFactor)                         // 2
  .translate(-image.width / 2, -image.height / 2); // 1

अधिक संक्षेप में, एक ही रणनीति किसी भी बिंदु के लिए काम करती है। यदि, उदाहरण के लिए, आप बिंदु P पर छवि को स्केल करना चाहते हैं:

myMatrix
  .translate(P.x, P.y)
  .scale(xFactor, yFactor)
  .translate(-P.x, -P.y);

और अंत में, अगर छवि पहले से ही किसी तरह से रूपांतरित हो जाती है (उदाहरण के लिए, यदि इसे घुमाया, तिरछा, अनुवादित या स्केल किया गया है), तो वर्तमान परिवर्तन को संरक्षित करने की आवश्यकता है। विशेष रूप से, उपरोक्त परिवर्तन को वर्तमान परिवर्तन द्वारा पोस्ट-गुणा (या दाएं-गुणा) किए जाने की आवश्यकता है।

myMatrix
  .translate(P.x, P.y)
  .scale(xFactor, yFactor)
  .translate(-P.x, -P.y)
  .multiply(myMatrix);

ये लो। यहां एक प्लंक है जो इस कार्रवाई में दिखाता है। डॉट्स पर मूसवेल के साथ स्क्रॉल करें और आप देखेंगे कि वे लगातार डालते हैं। (केवल क्रोम में परीक्षण किया गया।) http://plnkr.co/edit/3aqsWHPLlSXJ9JCcJzgH?p=preview


1
मुझे कहना होगा, यदि आपके पास एक एफाइन ट्रांसफ़ॉर्मेशन मैट्रिक्स उपलब्ध है, तो इसे उत्साह के साथ उपयोग करें। बहुत सारे ट्रांसफॉर्मेशन मैट्रिक्‍स में जूम (sx, sy, x, y) फंक्‍शन भी होंगे जो ठीक यही करते हैं। यह लगभग एक खाना पकाने के लायक है अगर आपको उपयोग करने के लिए एक नहीं दिया जाता है।
ताताराइज करें

वास्तव में, मैं स्वीकार करता हूं कि जिस कोड में मैंने इस समाधान का उपयोग किया है, उसे तब से मैट्रिक्स क्लास के साथ बदल दिया गया है। और मैंने इस सटीक चीज़ को कई बार किया है और मैट्रिक्स कक्षाओं को दो बार से कम नहीं पकाया है। ( github.com/EmbroidePy/pyemb कढ़ाई/blob/master/pyemb कढ़ाई/… ), ( github.com/EmbroidePy/EmbroidePy/blob/master/embrovepy/… )। यदि आप इन ऑपरेशनों की तुलना में कुछ अधिक जटिल चाहते हैं तो एक मैट्रिक्स मूल रूप से सही उत्तर है और एक बार जब आपको रैखिक बीजगणित पर एक हैंडल मिल जाता है तो आपको पता चलता है कि यह उत्तर वास्तव में सबसे अच्छा उत्तर है।
ताताराइज करें

6

यहां केंद्र-केंद्रित छवि के लिए मेरा समाधान है:

var MIN_SCALE = 1;
var MAX_SCALE = 5;
var scale = MIN_SCALE;

var offsetX = 0;
var offsetY = 0;

var $image     = $('#myImage');
var $container = $('#container');

var areaWidth  = $container.width();
var areaHeight = $container.height();

$container.on('wheel', function(event) {
    event.preventDefault();
    var clientX = event.originalEvent.pageX - $container.offset().left;
    var clientY = event.originalEvent.pageY - $container.offset().top;

    var nextScale = Math.min(MAX_SCALE, Math.max(MIN_SCALE, scale - event.originalEvent.deltaY / 100));

    var percentXInCurrentBox = clientX / areaWidth;
    var percentYInCurrentBox = clientY / areaHeight;

    var currentBoxWidth  = areaWidth / scale;
    var currentBoxHeight = areaHeight / scale;

    var nextBoxWidth  = areaWidth / nextScale;
    var nextBoxHeight = areaHeight / nextScale;

    var deltaX = (nextBoxWidth - currentBoxWidth) * (percentXInCurrentBox - 0.5);
    var deltaY = (nextBoxHeight - currentBoxHeight) * (percentYInCurrentBox - 0.5);

    var nextOffsetX = offsetX - deltaX;
    var nextOffsetY = offsetY - deltaY;

    $image.css({
        transform : 'scale(' + nextScale + ')',
        left      : -1 * nextOffsetX * nextScale,
        right     : nextOffsetX * nextScale,
        top       : -1 * nextOffsetY * nextScale,
        bottom    : nextOffsetY * nextScale
    });

    offsetX = nextOffsetX;
    offsetY = nextOffsetY;
    scale   = nextScale;
});
body {
    background-color: orange;
}
#container {
    margin: 30px;
    width: 500px;
    height: 500px;
    background-color: white;
    position: relative;
    overflow: hidden;
}
img {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    max-width: 100%;
    max-height: 100%;
    margin: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="container">
    <img id="myImage" src="http://s18.postimg.org/eplac6dbd/mountain.jpg">
</div>


4

यहाँ इसे करने का एक वैकल्पिक तरीका है जो स्केल () और अनुवाद () के बजाय सेटट्रांसफॉर्म () का उपयोग करता है। सब कुछ एक ही वस्तु में संग्रहीत है। कैनवास को पृष्ठ पर 0,0 पर माना जाता है, अन्यथा आपको पृष्ठ के कोर्डर्स से इसकी स्थिति को घटाना होगा।

this.zoomIn = function (pageX, pageY) {
    var zoomFactor = 1.1;
    this.scale = this.scale * zoomFactor;
    this.lastTranslation = {
        x: pageX - (pageX - this.lastTranslation.x) * zoomFactor,
        y: pageY - (pageY - this.lastTranslation.y) * zoomFactor
    };
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    this.lastTranslation.x,
                                    this.lastTranslation.y);
};
this.zoomOut = function (pageX, pageY) {
    var zoomFactor = 1.1;
    this.scale = this.scale / zoomFactor;
    this.lastTranslation = {
        x: pageX - (pageX - this.lastTranslation.x) / zoomFactor,
        y: pageY - (pageY - this.lastTranslation.y) / zoomFactor
    };
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    this.lastTranslation.x,
                                    this.lastTranslation.y);
};

पैनिंग को संभालने के लिए कोडिंग कोड:

this.startPan = function (pageX, pageY) {
    this.startTranslation = {
        x: pageX - this.lastTranslation.x,
        y: pageY - this.lastTranslation.y
    };
};
this.continuePan = function (pageX, pageY) {
    var newTranslation = {x: pageX - this.startTranslation.x,
                          y: pageY - this.startTranslation.y};
    this.canvasContext.setTransform(this.scale, 0, 0, this.scale,
                                    newTranslation.x, newTranslation.y);
};
this.endPan = function (pageX, pageY) {
    this.lastTranslation = {
        x: pageX - this.startTranslation.x,
        y: pageY - this.startTranslation.y
    };
};

उत्तर को स्वयं प्राप्त करने के लिए, विचार करें कि ज़ूम से पहले और बाद में एक ही पृष्ठ निर्देशांक को एक ही कैनवास निर्देशांक से मेल खाना चाहिए। तब आप इस समीकरण से शुरू होने वाले कुछ बीजगणित कर सकते हैं:

(पृष्ठकांड - अनुवाद) / पैमाना = कैनवासकांड


3

मैं यहां उन लोगों के लिए कुछ जानकारी रखना चाहता हूं, जो अलग-अलग चित्र बनाते हैं और चलते-फिरते हैं।

जब आप ज़ूम और व्यूपोर्ट की स्थिति को स्टोर करना चाहते हैं तो यह उपयोगी हो सकता है।

यहाँ दराज है:

function redraw_ctx(){
   self.ctx.clearRect(0,0,canvas_width, canvas_height)
   self.ctx.save()
   self.ctx.scale(self.data.zoom, self.data.zoom) // 
   self.ctx.translate(self.data.position.left, self.data.position.top) // position second
   // Here We draw useful scene My task - image:
   self.ctx.drawImage(self.img ,0,0) // position 0,0 - we already prepared
   self.ctx.restore(); // Restore!!!
}

नोटिस स्केल पहले होना चाहिए

और यहाँ ज़ूमर है:

function zoom(zf, px, py){
    // zf - is a zoom factor, which in my case was one of (0.1, -0.1)
    // px, py coordinates - is point within canvas 
    // eg. px = evt.clientX - canvas.offset().left
    // py = evt.clientY - canvas.offset().top
    var z = self.data.zoom;
    var x = self.data.position.left;
    var y = self.data.position.top;

    var nz = z + zf; // getting new zoom
    var K = (z*z + z*zf) // putting some magic

    var nx = x - ( (px*zf) / K ); 
    var ny = y - ( (py*zf) / K);

    self.data.position.left = nx; // renew positions
    self.data.position.top = ny;   
    self.data.zoom = nz; // ... and zoom
    self.redraw_ctx(); // redraw context
    }

और, निश्चित रूप से, हमें एक ड्रैगर की आवश्यकता होगी:

this.my_cont.mousemove(function(evt){
    if (is_drag){
        var cur_pos = {x: evt.clientX - off.left,
                       y: evt.clientY - off.top}
        var diff = {x: cur_pos.x - old_pos.x,
                    y: cur_pos.y - old_pos.y}

        self.data.position.left += (diff.x / self.data.zoom);  // we want to move the point of cursor strictly
        self.data.position.top += (diff.y / self.data.zoom);

        old_pos = cur_pos;
        self.redraw_ctx();

    }


})

3
if(wheel > 0) {
    this.scale *= 1.1; 
    this.offsetX -= (mouseX - this.offsetX) * (1.1 - 1);
    this.offsetY -= (mouseY - this.offsetY) * (1.1 - 1);
}
else {
    this.scale *= 1/1.1; 
    this.offsetX -= (mouseX - this.offsetX) * (1/1.1 - 1);
    this.offsetY -= (mouseY - this.offsetY) * (1/1.1 - 1);
}

2

यहाँ PIXI.js. का उपयोग करके @ tatarize के उत्तर का एक कोड कार्यान्वयन है मेरे पास एक बहुत बड़ी छवि (उदाहरण के लिए गूगल मैप्स शैली) के हिस्से को देखने वाला एक व्यूपोर्ट है।

$canvasContainer.on('wheel', function (ev) {

    var scaleDelta = 0.02;
    var currentScale = imageContainer.scale.x;
    var nextScale = currentScale + scaleDelta;

    var offsetX = -(mousePosOnImage.x * scaleDelta);
    var offsetY = -(mousePosOnImage.y * scaleDelta);

    imageContainer.position.x += offsetX;
    imageContainer.position.y += offsetY;

    imageContainer.scale.set(nextScale);

    renderer.render(stage);
});
  • $canvasContainer मेरा HTML कंटेनर है
  • imageContainer मेरा PIXI कंटेनर है जिसमें छवि है।
  • mousePosOnImage संपूर्ण छवि (न केवल दृश्य पोर्ट) के सापेक्ष माउस स्थिति है।

यहाँ बताया गया है कि मुझे माउस की स्थिति कैसे मिली:

  imageContainer.on('mousemove', _.bind(function(ev) {
    mousePosOnImage = ev.data.getLocalPosition(imageContainer);
    mousePosOnViewport.x = ev.data.originalEvent.offsetX;
    mousePosOnViewport.y = ev.data.originalEvent.offsetY;
  },self));

0

आपको ज़ूम करने से पहले और बाद में विश्व अंतरिक्ष (स्क्रीन स्पेस के विपरीत) में बिंदु प्राप्त करने की आवश्यकता है, और फिर डेल्टा द्वारा अनुवाद करें।

mouse_world_position = to_world_position(mouse_screen_position);
zoom();
mouse_world_position_new = to_world_position(mouse_screen_position);
translation += mouse_world_position_new - mouse_world_position;

माउस पोजीशन स्क्रीन स्पेस में है, इसलिए आपको इसे वर्ल्ड स्पेस में बदलना होगा। सरल रूपान्तरण इस के समान होना चाहिए:

world_position = screen_position / scale - translation

0

स्क्रॉलबार की स्थिति को संभालने के लिए आप स्क्रॉलआउट (x, y) फ़ंक्शन का उपयोग कर सकते हैं, जिसे आपको ज़ूम करने के बाद दिखाया जाना चाहिए। माउस का उपयोग करने की स्थिति का पता लगाने के लिए। eventientX और event.clientY। यह आपकी मदद करेगा


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.