将可放置的 div 拖到背景图像上的特定点

Posted

技术标签:

【中文标题】将可放置的 div 拖到背景图像上的特定点【英文标题】:dragging a droppable div to a specific point on a background image 【发布时间】:2019-03-01 08:25:03 【问题描述】:

我正在尝试创建一个简单的教育游戏,其中将旗帜拖放到地图背景图像上的正确位置。所以我知道如何使标志可拖动和放置,但不知道如何使可放置区域在地图上的特定点。

这是我目前所拥有的:

    <!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>temperate journeys</title>

<style>
    #flagsfloat:left; height:100px;width:35px; padding:2px;margin-right: 10px;
    #chinaheight:20px; width:25px; background-color:red; border: 1px solid #B7191C;padding:3px;
    .chinaheight:22px; width:27px; background-color:green; border: 1px solid green;
    #australia height:20px; width:25px; background-color:blue; border: 1px solid #3324AF;padding:3px;
    </style>
 <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  <script>
  $( function() 
    $( "#china" ).draggable();
     $( "#australia" ).draggable(); 
     $( ".china" ).droppable(accept:"#china");  
   );
  </script>
</head>

<body>

    <div id="flags">
    <div id="china"> Ch </div>
    <div id="australia">Au</div>    


    </div>
<img src="map.gif"    usemap="#Map"/>
<map name="Map"><area class="china" shape="rect" coords="346,118,397,153" href="#" target="_self">

  <area shape="rect" coords="409,209,461,240" class="australia" target="_self">
</map>
</body>

【问题讨论】:

您是否阅读过相关文档? jqueryui.com/droppable/#accepted-elements 【参考方案1】:

尝试将 Image-Map 与 Droppable 一起使用不会很有趣,也不会按照您想要的方式工作。

&lt;area&gt; 标签定义了图像映射内的一个区域(图像映射是具有可点击区域的图像)。

&lt;area&gt; 元素总是嵌套在标签内。

注意:&lt;img&gt;标签中的usemap属性与&lt;map&gt;元素的name属性相关联,并在图像和地图之间建立关系。

这对我们的 UI 意味着什么?嗯,它有点暗示&lt;area&gt; 元素不符合与&lt;img&gt;&lt;div&gt; 相同意义的元素。它更多的是用于检查区域是否已被单击的坐标参考。它在 DOM 中,但它的盒子模型与它关联的图像相同。所以$("map .china") 的宽度和位置与图片相同。

这并不意味着它没有帮助。每个&lt;area&gt; 元素仍然具有定义坐标的属性。所以$("map .china").attr("coords") 会产生"346,118,397,153",我们可以用这个字符串做点什么!

目标

允许用户将标志拖放到地图上 放下后,确定标志是否在坐标内 告知用户是否击中或未命中目标 (将标志恢复到原始位置?)

示例

https://jsfiddle.net/Twisty/saufz8tg/

HTML

<div class="drag-area">
  <div id="flags">
    <div id="china" class="flag" title="China">Ch</div>
    <div id="australia" class="flag" title="Autstralia">Au</div>
  </div>
  <img class="map-image" src="https://www.wpclipart.com/dl.php?img=/geography/world_maps/world_map_basic_color.png"    usemap="#Map" />
  <map name="Map">
    <area class="china" shape="rect" coords="346,118,397,153" href="#" target="_self">
    <area shape="rect" coords="409,209,461,240" class="australia" target="_self">
  </map>
</div>

这里没有太多变化。 &lt;div&gt; 帮助包装和包含东西。还有一些类可以帮助组织和分配样式。

CSS

#flags 
  float: left;
  height: 100px;
  width: 35px;
  padding: 2px;
  margin-right: 10px;


.flag 
  height: 20px;
  width: 25px;
  margin-bottom: 1px;
  border: 1px solid #B7191C;
  border-radius: 3px;
  padding: 3px;


#china 
  background-color: red;


#australia 
  background-color: blue;

同样,没有重大变化。简单的清理和更容易的组织,更少的重复代码。

javascript

$(function() 
  function getObjCoords(o) 
    var p = o.position();
    var d = 
      width: o.width(),
      height: o.height()
    ;
    var coords = [
      p.left, // X1
      p.top, // Y1
      p.left + d.width, // X2
      p.top + d.height // Y2
    ];
    return coords;
  

  function getObjCenter(o) 
    var p = o.position();
    var d = 
      width: o.width(),
      height: o.height()
    
    var c = [
      parseInt(p.left + (d.width / 2)),
      parseInt(p.top + (d.height / 2))
    ];
    return c;
  

  function hit(o, t, off) 
    var x, y;
    var center = getObjCenter(o);
    var hit = false;
    if (center[0] > (t[0] + off.left) && center[0] < (t[2] + off.left)) 
      x = true
     else 
      x = false;
    
    if (center[1] > (t[1] + off.top) && center[1] < (t[3] + off.top)) 
      y = true;
     else 
      y = false;
    
    if (x && y) 
      hit = true;
    
    return hit;
  

  var $mapArea = $("map[name='Map']");
  var imgOff = $(".map-image").position();
  console.log("Image Position:", imgOff);

  $(".flag").draggable(
    containment: ".drag-area"
  );
  $(".flag").disableSelection();
  $(".map-image").droppable(
    drop: function(e, ui) 
      var itemCenter = getObjCenter(ui.draggable);
      console.log("Drop Center:", itemCenter);
      var t = ui.draggable.attr("id");
      var tPos = $mapArea.find("." + t).attr("coords").split(",");
      $.each(tPos, function(k, v) 
        tPos[k] = parseInt(v);
      );
      console.log("Target Coords:", tPos);
      console.log("Target Offset: [ " + (tPos[0] + imgOff.left) + ", " + (tPos[1] + imgOff.top) + ", " + (tPos[2] + imgOff.left) + ", " + (tPos[3] + imgOff.top) + " ]");
      if (hit(ui.draggable, tPos, imgOff)) 
        console.log("Hit!");
        return true;
       else 
        console.log("Miss.");
        return false;
      
    
  );
);

我的 JavaScript/jQuery 布局如下:函数、常量和 UI 定义/设置。我们有三个辅助函数:getObjCoords()getObjCenter()hit()。我把这个脚本比作游戏战舰,所以我使用了很多相同的术语。

我怀疑你会有更多的旗帜和区域来放置它们。这就是这些辅助函数发挥作用的地方。我们将把繁重的工作留给他们,只在拖放区域中处理我们更基本的对象。

getObjCoords(jQuery 对象)

接受一个 jQuery 对象并根据对象的位置和尺寸返回一个 [x1, y1, x2, y2] 数组。

getObjCenter(jQuery 对象)

接受一个 jQuery 对象并返回一个由 [x, y] 组成的数组,该数组定义了对象框的中心。

hit(jQuery 对象,数组坐标,数组偏移)

确定对象中心是否在 4 个区域坐标内。

备注

由于您没有定义如何处理命中或未命中,我只是在丢弃标志时将其发送到控制台。现在,可以放下旗帜然后再次移动。 .split() 用于将字符串转换为数组,但它将是字符串数组。 JavaScript 通常会接受这一点,但为了进行适当的比较,我已将它们转换为整数。 getObjCenter() 可以使用数学来四舍五入这些值。请记住,除以奇数会产生一个长整数 (3 / 2 = 1.5),而 HTML 不喜欢半个像素。您可以使用Math.round()Math.floor(),但parseInt() 也可以。选择你的毒药。

希望对您有所帮助。此外,这不是执行此操作的唯一方法,您必须确定这是否对您的脚本有用。

【讨论】:

谢谢@Twisty。我添加了更多的标志,它就像一个梦

以上是关于将可放置的 div 拖到背景图像上的特定点的主要内容,如果未能解决你的问题,请参考以下文章

div背景图像和iOS Mobile Safari兼容性问题

为啥我的 <div> 中没有出现背景图像?

特定高度的部分的背景图像

常见的几种抠图方式?

如何将可自定义的颜色更改框下载为带有背景图像的图像?

如何使用 jQuery 将可拖动项目居中放置在可放置的图像地图区域上?