-->

Set map borders to not cross inside the view area

2019-08-27 17:35发布

问题:

I am trying to translate an old flash animation with animate. On the original flash animation the map image is draggable and zoomable but the map ´s borders always stick to the sides of the stage if you pan it or zoom it all the way.

On my test i grabbed some code that allows panning and zooming but the map crosses the stage boundaries if you pan all the way, in fact you can make the map dissapear of the stage.

I think there should be a way to draw like a secondary outer stage and not let the map image go beyond it.

This is the code I have.

var that = this;
var clickedX;
var clickedY;
var isDragging = false;
var friction = 0.85;
var speedX = 0;
var speedY = 0;
var mapOriginalX = this.map.x;
var mapOriginalY = this.map.y;
var mapNudge = 5;
var minScale = 0.25;
var maxScale = 3;

function onMouseWheel(e)
{
    var delta;

    if (e == window.event)
        delta = -10 / window.event.wheelDeltaY;
    else
        delta = e.detail / 30;

    var zoomFactor = delta; 
    scaleMap(zoomFactor);   
}

function mouseDown(e)
{
    clickedX = stage.mouseX;
    clickedY = stage.mouseY;
    isDragging = true;  
    console.log(stage.mouseX);
    console.log(stage.mouseY);

}

function stageMouseUp(e)
{
    isDragging = false;
}

function update(e)

{



if (isDragging)
{
    speedX = stage.mouseX - clickedX;
    speedY = stage.mouseY - clickedY;
}   

speedX *= friction;
speedY *= friction;

// saber el tamaño actual del mapa en este punto.
that.map.x += speedX;
that.map.y += speedY; 
console.log(that.map.y); 
console.log(that.map.x); 
clickedX = stage.mouseX;
clickedY = stage.mouseY;

    // 
}

function resetMap()
{
    that.map.x = mapOriginalX;
    that.map.y = mapOriginalY;
    that.map.scaleX = that.map.scaleY = 1;
}

function zoomMap(e)  //control visual
{  
    if (e.currentTarget == that.plusButton)
        scaleMap(-0.1);
    if (e.currentTarget == that.minusButton)
        scaleMap(0.1);
}

function moveMap(e) //control visual
{
    if (e.currentTarget == that.upButton)
        speedY -= mapNudge;
    else if (e.currentTarget == that.rightButton)
        speedX += mapNudge;
    else if (e.currentTarget == that.downButton)
        speedY += mapNudge;
    else if (e.currentTarget == that.leftButton)
        speedX -= mapNudge;
}

function scaleMap(amount)
{

    var map = that.map; // we will scale de map so this goes first.

    map.scaleX -= amount;  // same as map.scaleX = map.scaleX - amount
    map.scaleY = map.scaleX; 

    if (map.scaleX < minScale)
        map.scaleX = map.scaleY = minScale;
    else if (map.scaleX > maxScale)
        map.scaleX = map.scaleY = maxScale;
}

// listeners
this.map.on("mousedown", mouseDown.bind(this));
this.resetButton.on("click", resetMap.bind(this));
this.plusButton.on("click", zoomMap.bind(this));
this.minusButton.on("click", zoomMap.bind(this));
this.upButton.on("click", moveMap.bind(this));
this.rightButton.on("click", moveMap.bind(this));
this.downButton.on("click", moveMap.bind(this));
this.leftButton.on("click", moveMap.bind(this));
stage.on("stagemouseup", stageMouseUp.bind(this));
document.getElementById('canvas').addEventListener('mousewheel', onMouseWheel.bind(this));
document.getElementById('canvas').addEventListener('DOMMouseScroll', onMouseWheel.bind(this));
createjs.Ticker.addEventListener("tick", update.bind(this));

resetMap();

回答1:

One trick I usually use is to create a "fence" procedure that checks bounds and corrects them. It will take some setup though.

To use this method, first set up these variables based on your own scene. Perhaps this is what you meant by defining a "second stage?"

var stageLeft = 0;
var stageRight = 500;
var stageTop = 0;
var stageBottom = 500;
this.map.setBounds(0,0,1462, 1047);  // Set the values to match your map
var mapBounds = this.map.getBounds();

Then, add this procedure, or a variation of it based on how your map coordinates are set.

// procedure to correct the map x/y to fit the stage
function fenceMap() {
    var map = that.map;
    var ptTopLeft = map.localToGlobal(mapBounds.x,mapBounds.y);
    var ptBotRight = map.localToGlobal(mapBounds.width,mapBounds.height);

    if ((ptBotRight.x - ptTopLeft.x) > (stageRight-stageLeft)) {
        if (ptTopLeft.x > stageLeft) {
            map.x -= ptTopLeft.x - stageLeft;
            speedX = 0;
        } else if (ptBotRight.x < stageRight) {
            map.x -= ptBotRight.x - stageRight;
            speedX = 0;
        }
    }
    if ((ptBotRight.y - ptTopLeft.y) > (stageBottom-stageTop)) {
        if (ptTopLeft.y > stageTop) {
            map.y -= ptTopLeft.y - stageTop;
            speedY = 0;
        } else if (ptBotRight.y < stageBottom) {
            map.y -= ptBotRight.y - stageBottom;
            speedY = 0;
        }
    }
}

Then, just add to the end of your update(), zoomMap(), moveMap(), and scaleMap() functions:

    fenceMap();