首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将非矩形可点击的“图钉”元素放置在<img>上?

如何将非矩形可点击的“图钉”元素放置在<img>上?
EN

Stack Overflow用户
提问于 2016-07-02 20:21:17
回答 1查看 200关注 0票数 1

基本上,我必须在HTML/CSS/Javascript中创建这样的代码:

如你所见,这是一张纽约地图。当用户单击地图下方的一个图标时,图钉(如地图左下角的图钉)应该出现在地图的某些位置。然后,用户应该能够点击它们,以便从它们中弹出另一个带有文本的div。这就是我不知所措的地方。到目前为止,我是这样想的:

-Creating另外3张图片,包含所有动力装置销,所有造船厂别针和所有钢厂别针,并在地图上用z索引定位它们。唯一的问题是,用户只能单击具有最高z索引的图像。例如,如果它们同时启用了造船厂和钢厂,它们将只能点击上一次添加的别针。这就是我放弃这个想法的地方。

-Using div具有绝对位置来复制地图的细分区域。然而,div是矩形的,细分不是。所以这也不好。

-Using图像地图我从20世纪90年代起就没听说过有人用过这些东西。不管怎样,我看不出一张地图对我有什么帮助。我需要定位他们,而不是超链接他们。

我愿意接受任何建议/插件。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-07-03 02:49:12

好吧,您可能不喜欢这个答案,但由于没有其他人提出任何建议,我会这样做(或者实际上使用多层的图像映射,但是您的引脚需要放在图像上):

选项1:将整个映射和引脚作为SVG并将svg代码粘贴到您的html中,并将javascript单击事件附加到它。SVG元素可以使用与html元素相同的DOM事件,可以定位、缩放和成形。你甚至可以用CSS规则和类来隐藏它们!

SVG确实是一个非常优雅的解决方案,有坚实的浏览器支持,如果有可能以这种形式获得您的艺术资产,我可能就是这样做的。您可以在网上为svg获取各种工具和教程,所以我将把它放在这里,只需记住javascript事件就行了!

选项2:用HTML自己做。让我更详细地说明一下这一点,因为它在网络上并不完全是标准的,尽管它是桌面应用程序中使用的相同的想法。

  1. 创建四个图像:地图和引脚。
  2. 创建一个数据数组,它是引脚的位图,显示透明和可点击的部分。这是一个矩形,其中1你可以点击,0你不能,形成形状。这种技术在桌面程序中经常用于鼠标游标之类的东西。最简单的方法可能是使用图像编辑器并将其清除为白色和黑色,然后导出。GIMP可以导出到xpm,您可以手动修复它,使之成为Javascript相当容易。
  3. 创建每个引脚位置的数据数组。(理想情况下,我会将其作为一个绝对定位的HTML链接元素列表,因为这是一种数据格式,在没有Javascript的情况下,这种数据格式会优雅地退化(如果不完美),但是您不想监听它们上的事件。)
  4. 在包含所有图像的div上放置一个事件侦听器,并使用单击的坐标查找数据数组中的引脚。如果需要,可以使用位图下降--循环遍历可能的对象,并查看是否位于边框中。如果是,请检查位图。如果它是可点击的,你有一个命中!如果没有,就转到下一个。

线性搜索是最容易实现的,并且工作得很好,尽管如果您有数千项,您可能需要对其进行一些优化,如果需要的话,您可以在web上搜索其他算法/数据结构,如四叉树。但是,如果您有那么多对象,地图可能对用户是不可用的!

因此,基本上,点击将所有的工作坐标数据数组,而不是关闭HTML元素,这些图像只是为用户。

我用你的图像拼凑了一个技术演示,只是懒洋洋地用cut+paste把它从引脚上砍了出来。如果你有原始图像,你可以做一个更好的工作。

活动链接(可能是临时的) http://arsdnet.net/demo.html

为后代复制/粘贴代码:

代码语言:javascript
运行
复制
<!DOCTYPE html>
<html>
<head>
<title>Demo of map idea</title>
<script>
        window.onload = function() {
                var map = document.querySelector(".ny-map");
                // on each click on the map, we need to loop through
                // the bounding boxes of the pins and see which one we hit.
                map.addEventListener("click", function(event) {
                        var pins = map.querySelectorAll(".pin");
                        var i;
                        // we are searching BACKWARD so it checks
                        // for clicks on the topmost pin first, then
                        // proceeds down to the bottom ones.
                        for(i = pins.length - 1; i >= 0; i--) {
                                var rect = pins[i].getBoundingClientRect();
                                if (event.clientX >= rect.left
                                 && event.clientX < rect.right
                                 && event.clientY >= rect.top
                                 && event.clientY < rect.bottom)
                                {
                                        // if we're inside the bounding box,
                                        // next we need to check the transparency
                                        // bitmap to see if it is an actual hit

                                        var x = event.clientX - rect.left;
                                        var y = event.clientY - rect.top;

                                        // pinBitmap is defined below
                                        // "." happens to be the char my Gimp export
                                        // gave to the clickable region, so we check for it
                                        if(pinBitmap[y].charAt(x) == ".") {
                                                // we hit this one!
                                                // toggle class "showing"
                                                if(pins[i].className.indexOf(" showing") == -1)
                                                        pins[i].className += " showing";
                                                else
                                                        pins[i].className = pins[i].className.replace(" showing", "");
                                                break; // all done
                                        }
                                        // if we didn't hit on the bitmap, continue
                                        // searching the one below by proceeding with the loop
                                }
                        }
                });
        };
</script>
</head>
<body>
<div class="ny-map">
        <div class="shipyard pin" style="left: 140px; top: 450px;">
                <p>This is information about shipyard #1.</p>
        </div>
        <div class="shipyard pin" style="left: 150px; top: 450px;">
                <p>This is information about shipyard #2, which overlaps shipyard #1.</p>
        </div>
        <div class="shipyard pin" style="left: 460px; top: 350px;">
                <p>This is information about a shipyard pin in the Syracuse area.</p>
        </div>
</div>

<script>
var pinBitmap = [
"+++++++++++.++.............++++++++++++++",
"+++++++++++..................++++++++++++",
"++++++++++.....................++++++++++",
"+++++++..........................++++++++",
"+++++................................++++",
"++.......................................",
"....+...............................+++++",
".+++.................................++++",
"+++...................................+++",
"+++...................................+++",
"++.....................................++",
"++.....................................++",
"+.......................................+",
"+.......................................+",
".........................................",
".........................................",
".........................................",
".........................................",
".........................................",
".........................................",
".........................................",
".........................................",
".........................................",
".........................................",
".........................................",
".........................................",
"+.......................................+",
"+.......................................+",
"+.......................................+",
"++.....................................++",
"++.....................................++",
"+++...................................+++",
"+++...................................+++",
"+++...................................+++",
"++++.................................++++",
"++++.................................++++",
"+++++...............................+++++",
"+++++...............................+++++",
"++++++.............................++++++",
"++++++.............................++++++",
"+++++++...........................+++++++",
"+++++++...........................+++++++",
"++++++++.........................++++++++",
"+++++++++.......................+++++++++",
"+++++++++.......................+++++++++",
"++++++++++.....................++++++++++",
"++++++++++.....................++++++++++",
"+++++++++++....................++++++++++",
"+++++++++++....................++++++++++",
"++++++++++++...................++++++++++",
"+++++++++++++...............+..++++++++++",
"+++++++++++++...............+..++++++++++",
"++++++++++++++.............++..++++++++++",
"+++++++++++++++...........+++..++++++++++",
"+++++++++++++++...........+++..++++++++++",
"++++++++++++++++.........++++..++++++++++",
"++++++++++++++++.........++++..++++++++++",
"+++++++++++++++++.......+++++..++++++++++",
"++++++++++.................++..++++++++++",
"++++++.........................++++++++++",
"++++..............................+++++++",
"+++................................++++++",
"+++................................++++++",
"++++..............................+++++++",
"++++++..........................+++++++++",
"++++++++++..................+..++++++++++"];
</script>

<style>

.ny-map {
        width: 985px;
        height: 815px;
        background-image: url('demo/qDOGS-fs8.png');
        position: relative;
}

.pin {
        width: 41px;
        height: 66px;
        margin-left: -20px;
        margin-top: -66px;
        position: absolute;
}

.shipyard.pin {
        background-image: url('demo/pin.png');
        background-repeat: no-repeat;
}

.pin:not(.showing) > * {
        display: none;
}

.pin.showing {
        background-color: rgba(255, 255, 255, 0.8);
        padding-left: 48px;
        padding-right: 4px;
        width: auto;
}

</style>

</body>
</html>

我就是这么做的。首先,处理奇怪形状的pinBitmap部分单击:

在GIMP中拍摄别针图片并打开它。使用颜色选择工具选择所有透明部件,点击它。使用桶填充,选择“填充整个选择”使其全部黑色。点击选择->倒转选择其余的图像和桶填充它全部为白色。

现在将文件导出为XPM。在您的文本编辑器中打开它,并将第7行(嗯,第一个带有图像数据的长代码,不管它恰好在您的文本中)复制到末尾,并粘贴到Javascript中。

我在它周围放了数组括号来创建pinBitmap变量,因为Gimp生成了字符串,所以我只在函数中使用了字符串。

文件底部的CSS使我们的地图和引脚图像。showing类控制更多信息的显示。当然,你也可以做一些类似.ny-map .powerplant { display: none; }之类的事情,来切换事物的显示。在搜索要单击的项目时,请确保使用computedStyle或仅使用一些标志变量可以看到它们,如果没有,则继续进行!

您会注意到,引脚本身在HTML中是半语义的,只是使用内联样式来定位它们。在CSS中,我做了一些负面的保证金技巧,以使它显示更多的引脚点,我想要的坐标,但你可以只是调整这一点- JS帐户为所有这些css调整,信不信由你!只需从gimp或其他地方获取相对于图像的坐标即可。

我把有关引脚的细节放在HTML中,所以它也与内容很好地组合在一起。

最后,魔法函数,在文件的顶部。它只是地图上一个普通的事件侦听器,通过引脚循环。getBoundingClientRect函数是标准DOM的一部分,并生成项所在的矩形。一个简单的4部分的检查看看我们是否在那个盒子里。

如果是这样,我们想要相对于矩形的坐标,通过简单的减法实现,然后检查位图,如果它实际上是可点击的.就这样!如果没有,我们认为这是一个失败,并继续循环。如果是这样的话,我将切换showing类来完成剩下的工作。

这段代码应该在IE9+浏览器上可靠工作,而不需要任何插件或库脚本。

如果你对我的方法/代码还有什么疑问,请告诉我。

编辑: lol我把它叫做“造船厂”,但是去掉了发电厂的形象。哦,你知道我的意思。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38164155

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档