在大网格上平滑滚动图像拼贴?

时间:2012-01-31 01:40:46

标签: javascript jquery css google-maps

长时间听众,第一次来电。

好的,我为这篇文章的篇幅道歉,但我想非常清楚我想要做什么,以及我曾试图指导你的答案。

目标: 我正在尝试创建一个100 x 100的瓷砖(图像)网格,我将一次仅显示网格的一部分,因为图像是240 x 120.通过单击按钮(注意:不需要鼠标滚动,缩放等。),用户将水平和垂直滚动。

作为一个类比,拿一个设置为玩的跳棋板,你正在低头看它。显示起来非常简单,只需要几个基本图像并将它们放在网格上。现在,考虑一下你只想显示底板的1/3。然后,当用户点击时,他们将视图移动到中间,然后再次单击将他们移到板的前1/3处。这是我尝试完成的一个简单示例,除了在视野/移动较小的大得多的网格上。

我尝试过的事情:

  1. 首先我用PHP编写代码来绘制完整的100x100网格,一切看起来都很棒
  2. 然后我改变了代码以实际为每个方块写入文件,将它们保存为X-Y.png
  3. 我陷入了一个地图工具世界和缩放类型工具
  4. 我在编写自己的解决方案方面取得了一定的成功
  5. 地图工具/缩放失败:

    获得完整的地图和瓷砖后,我试图弄清楚如何只滚动这个窗口的一部分。一个灯泡熄灭了:"谷歌地图如何处理事情呢!"当麻烦开始的时候,我被兔子洞吸了一下,研究了所有这些真正让我无处可寻的地图工具,因为很简单,它们似乎只是用于显示地理地图。

    然而,我确实在某个时刻被引导到了Zoomify,我认为这可能是一个选择。第一个问题是我似乎无法在没有完整图像的情况下拍摄自己的瓷砖,所以我尝试了在阳光下的每个屏幕捕获程序,尝试用完整的网格获取我的浏览器的完整镜头让zoomify让他们。我们只是说,这不起作用,但我尝试减小尺寸。它有点工作,但失去了很多质量,我意识到zoomify甚至没有真正完成我需要的东西,因为1.滚动不是那么顺利; 2.这些图像最终将包含一些与其X-Y坐标连接的链接,这意味着我需要控制每次点击向上,向下,向左,向右箭头时滚动多少。

    我自己没有尝试过这样做

    好的,然后我回到了基础知识,我把网格扔进了一个溢出的DIV:隐藏在CSS上。太好了,现在我有了一个窗口。我不想一次加载所有这些图像,所以我只在绝对定位的DIV中绘制了具有唯一ID的网格的一部分(例如Tile_1_1)。这看起来很棒,但现在我需要让你看到你在点击箭头按钮时滚动网格,所以我把它扔到了一个javascript函数。我有javascript计算新X和新Y并交换所有图块的图像源,因为它们都是在网格上的X / Y坐标后命名的。实际上,这完全有效,现在地图滚动。问题是,只是改变图像源有点不稳定。毫无疑问,我们正在这个网格中移动,因为内容只是瞬间改变。而我的朋友就是我需要我们帮助的地方。

    我哪里出错了?这次最新尝试是否在正确的轨道上?我是否需要完全重新考虑这个问题,或者是否有一些简单的方法可以更好地移动瓷砖而不是交换光源?

    请记住,我在php,css等方面表现得相当不错,但我从来没有在javascript上投入太多时间,所以你可能需要在该领域做更多的解释。

    P.S。这是我能在这些板上找到的最接近的东西,但它从来没有得到明确的答案:Tile scrolling / preloading (Google Maps style) of HTML layers with Ajax

    更新:使用解决方案

    我喜欢Cobby和pseudosavant的答案。 Pseudosavant的解决方案非常适合我的盟友,让CSS完成大部分艰苦的工作,但是我选择了Cobby的解决方案。我认为它会给我一点控制权,因为我实际上使用了一个菱形网格,我可以更好地包裹它(不要说另一个也不一定也能用)。

    这就是我所做的。我知道代码有点粗糙,需要一些清理,但也许它可以帮助别人。

    首先我需要找到我的X和Y轴之间的关系,所以我画了一个小图。

    enter image description here

    我很快注意到更多的X意味着在更远的左侧和更高处开始钻石以在视图的中心(用户定义的开始)获得正确的坐标,然后通过Y坐标偏移以取消一些负的左边和降低起点。

    然后,绘制网格的PHP看起来像这样($ xcoord和$ ycoord来自一个表单):

    //draw the grid
    //Offset leftStart and topStart by Xcoord
    $leftStart = 360 - ($xcoord * 120);
    $topStart = 360 - ($xcoord * 60);
    
    //Offset leftStart and topStart by Ycoord
    $leftStart += ($ycoord * 120);
    $topStart -= ($ycoord * 60);
    
    for($y = 1; $y <= 99; $y++) { //y min to y max
        $left = $leftStart;
        $top = $topStart;
        for($x = 1; $x <= 99; $x++) { //x min to x max
           //I only want to draw part of the square
           if(($x < ($xcoord + 6)  && $x > ($xcoord - 6)) && ($y < ($ycoord + 6)  && $y > ($ycoord - 6))) {
              //Put out the image - this is how i needed mine formated
              echo "\t<div class=\"move\" id=\"T" . $x . "_" . $y . "\" style='position:absolute; left:" . $left . "px; top:" . $top . "px;'>\n";
              echo "\t\t<img src=\"./<path to your image>" . $x . "-" . $y . ".gif\">\n";
              echo "\t</div>\n";
           }
           $left = $left + 120;
           $top = $top + 60;
        }
    $leftStart = $leftStart - 120;
    $topStart = $topStart + 60;
    }
    

    用溢出的方式抛出一个DIV:隐藏并给它一个ID(我的是#tileView)。好的,现在你的视图中有一个菱形网格,现在我们需要开始移动它!

    这就是我的jquery看起来的样子。对不起,如果它需要改进,我昨天刚学会了Jquery和Ajax。

    <script type="text/javascript" src="jquery.js"></script>
    <script type="text/javascript">
    $(document).ready(function(){
        $("#top").click(function(){
            var y = document.getElementById('ycoord').value;
            var x = document.getElementById('xcoord').value;
            $(".move").animate({"left": "-=120px", "top": "+=60px"}, 500);
            changeImg(x, y, 'up');
            $("#ycoord").val(parseInt( y ) - 1);
        });     
        $("#bottom").click(function(){
            var y = document.getElementById('ycoord').value;
            var x = document.getElementById('xcoord').value;
            $(".move").animate({"left": "+=120px", "top": "-=60px"}, 500);
            changeImg(x, y, 'down');
            $("#ycoord").val(parseInt( y ) + 1);
        });     
        $("#left").click(function(){
            var y = document.getElementById('ycoord').value;
            var x = document.getElementById('xcoord').value;
            $(".move").animate({"left": "+=120px", "top": "+=60px"}, 500);
            changeImg(x, y, 'left');
            $("#xcoord").val(parseInt( x ) - 1);
        });
         $("#right").click(function(){
            var y = document.getElementById('ycoord').value;
            var x = document.getElementById('xcoord').value;
            $(".move").animate({"left": "-=120px", "top": "-=60px"}, 500);
            changeImg(x, y, 'right');
            $("#xcoord").val(parseInt( x ) + 1);
        });
    
    function changeImg(x, y, move){
        $.ajax({
            type: "POST",
            url: "addImage.php",
            data: 'x=' + x + '&y=' + y + '&move=' + move,  
            cache: false,
            success: function(html){
                $(html).appendTo($("#tileView"));
            }
        });
        $.ajax({
            type: "POST",
            url: "removeImage.php",
            data: 'x=' + x + '&y=' + y + '&move=' + move,  
            cache: false,
            success: function(xml){             
                $("removeTile",xml).each(function(id) {    
                removeTile = $("removeTile",xml).get(id);
                removeID = $("tileID",removeTile).text();
                $("#" + removeID).remove();
            });
            }
        });
    }
    });
    </script>
    

    ajax调用addImage.php在正确的位置添加一个新行,而deleteImage.php则删除现在不在视图中的行(我发现没有删除事情开始运行的那些行很慢)。

    在添加图片中,您只需找出要在页面中添加的html的新位置和输出。例如,part可能看起来像这样(但是根据move设置变量然后遍历循环):

    if($_REQUEST["move"] == "up") {
        $xmin = $x - 5;
        $xmax = $x + 5;
        $y = $y - 6;
    
        $left = 360;
        $top = -360;
    
        for($i = $xmin; $i <= $xmax; $i++) {
            $id = "T" . $i . "_" . $y;
            $newTiles .= "<div class='move' style='position:absolute; left:" . $left . "px; top:" . $top . "px;' id='$id'><img src='./Map/TileGroup1/1-$i-$y.gif'></div>\n";
            $left += 120;
            $top += 60;
        }
    }
    

    然后只需回显$ newTiles就可以使用。

    删除类似,只需在xml中输入要删除的DIV ID,因为我无法使每个()无法正常工作。

    if($_REQUEST["move"] == "up") {
        $xmin = $x - 5;
        $xmax = $x + 5;
        $y = $y + 5;
    
        echo "<?xml version=\"1.0\"?>\n";  
        echo "<response>\n";  
        for($i = $xmin; $i <= $xmax; $i++) {
            echo "\t<removeTile>\n";
            echo "\t\t<tileID>T" . $i . "_" . $y . "</tileID>\n";
            echo "\t</removeTile>\n";
        }
        echo "</response>"; 
    }
    

    希望这有助于某人。谢谢大家的想法和支持!

3 个答案:

答案 0 :(得分:2)

这是我之前使用的解决方案。

  1. 图块应为<div>,其中inline-block设置为<img>。通过<div>控制标题的宽度和高度。 *重要的是<div>元素之间没有空白区域,否则瓷砖不会彼此相邻。
  2. 图块应位于#container <div> line-height 0。容器应设置为图块大小的倍数,因为图块会自动换行。所以20个瓷砖可以是4x5或5x4,具体取决于容器的大小。
  3. #container应该在我称之为视口的<div> overflow: hidden。您可以使用jQuery和#viewport .scrollLeft滚动.scrollTop
  4. 这是一个jsfiddle示例:http://jsfiddle.net/pseudosavant/b4hSV/

答案 1 :(得分:1)

我认为您需要回到使用overflow:hidden嵌套在DIV中的整个网格的方法,但是使用JavaScript来确定哪些图像应该是可见的,并且只根据需要加载这些图像,然后加载当用户滚动到该区域时,在其他相关图像中。

滚动当然应该操纵网格的lefttop CSS属性,以便在包含overflow: hidden DIV中移动它。在您的情况下,最简单的方法就是以图块大小的增量更改定位CSS属性(因此您永远不会显示部分图块)。

从编程的角度来看,这有点痛苦,但听起来你已经有了计算哪些/应该显示的方法?

使用此方法,首次加载图像时会出现初始毛刺,但随后移动网格将不必重新加载相同的图像。一旦你有了这个工作,你可以使用jQuery或类似的方法来动画lefttop属性,以提供平滑的滚动效果。

然后,如果您愿意,可以进一步构建,并允许部分滚动图块并点击并拖动滚动,如Google地图。此外,如果你想要提高性能,我建议你设置一个nginx服务器来监听你网站的几个子域,以提供平铺图像。

编辑:我建议在容器scrollLeft(具有scrollTop)上设置divoverflow: hidden的动画,但会提供更好的效果/更顺畅的滚动。


有一个名为TileMill的简洁程序,而OP不会使用它,它可能适用于其他人。

答案 2 :(得分:1)

如果您的动画是基于时间的,而不是基于位置/帧数,则您只能提供流畅的动画体验。我首先看一下requestAnimationFrame(或适当的,基于时间的polyfill)并设计你的动画/定位计算是基于时间的。问题是:

  

给定时间t我的地图的xy滚动偏移应该是什么?

然后考虑使用错觉将视口放入一个巨大的图块集,而不是实际上有一个使用overflow: hidden来查看小视口的大量图块集。你不想用太多的瓷砖耗尽DOM。

假设您的视口允许查看4 x 4个图块,当图块偏移不会与您的视口对齐时,考虑到部分显示的图块,最多可以显示5 x 5个图块(大多数情况下都会如此)时间)。无论你的地图实际拥有多少个瓷砖,5 x 5瓷砖都将是你所需要的。这是一个草图:

http://jsfiddle.net/6uRHD/

任务将是:

  1. 根据用户动作计算加速度/速度/位置(滚动,用阻尼轻推),然后计算动画时间t的位置。
  2. 根据位置计算哪些图块落入5 x 5图块集,并计算这些图块的视口偏移量。