我希望能够在悬停时缩放图像的多边形。
准确地说,它是一张世界地图,当你将鼠标悬停在它上面时,我希望将这个国家扩大,然后再将它缩小,不再徘徊。
我知道,例如CSS有transform: scale(2)
,它适用于普通图像或世界地图。但实际上我并不想缩放孔图,而是想要绘制地图的多边形(或者至少,如果不能使用多边形,则为正方形(因此只是地图的一小部分)。
有没有办法做到这一点?不仅仅是CSS,也可以是JS / jQuery。
悬停部分不是问题的一部分,那就是简单的jQuery,但问题是如何只缩放图像的特定部分。
感谢您的帮助!
答案 0 :(得分:1)
这是一个吵闹的夜晚。所以我把一些东西放在一起玩。这是一个不完整的实现 - 我只是抓住图像的一部分悬停并将其扔到原始图片旁边。
由你来决定 (0)显示图像大于完整大小 (1)使用绝对定位和z-index将其定位在原件前面 (2)在悬停区域处理鼠标悬停。
我在评论中链接的答案演示了定位,z排序和将指针事件传递给基础地图元素。
您需要决定放大版本的显示方式/位置。也许你想要它150%,中心点位于地图元素的中心点之上。
正如评论所示,你通常会使用现有的图像,而不是像我在这里一样从头开始创建图像。
首先,将完整的源代码整理成一个 - 只需将其全部复制并复制到新的html文件中。
<!DOCTYPE html>
<html>
<head>
<script>
"use strict";
function byId(e){return document.getElementById(e);}
function newEl(tag){return document.createElement(tag);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(e)
{
createImageFromMapAreasForUseAtStackoverflow();
attachHoverHandlers();
}
// this function is only used for the purpose of answering this question.
// Ordinarily, you would set the src of #img1 to be that of your image. - since cross-origin contamination prevents
// access to the image data if the image comes from a different server, I've just opted to create the image from scratch.
//
// the original image may be found here: https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Australia_location_map_recolored.png/500px-Australia_location_map_recolored.png
function createImageFromMapAreasForUseAtStackoverflow()
{
var imgWidth = 500, imgHeight = 360;
var can = newEl('canvas');
can.width = imgWidth;
can.height = imgHeight;
var ctx = can.getContext('2d');
ctx.fillStyle = '#ecf5f6';
ctx.fillRect(0,0,imgWidth,imgHeight);
var areas = document.querySelectorAll('area');
var i, n = areas.length;
var colours = ['#f4f100', '#b2d025', '#f67c60', '#8fbce1', '#f4f236', '#fca164', '#bc9eee', 'black'];
for (i=0; i<n; i++)
{
var areaType = areas[i].getAttribute('shape');
if ((areaType == 'polygon') || (areaType == 'poly'))
drawMapPoly(areas[i].getAttribute('coords'), colours[i]);
}
byId('img1').src = can.toDataURL();
function drawMapPoly(coordStr, colour)
{
ctx.beginPath();
var ptArray = coordStrToPointArray(coordStr);
var i, n=ptArray.length;
ctx.moveTo(ptArray[0].x, ptArray[0].y);
for (i=0;i<n;i++)
ctx.lineTo(ptArray[i].x,ptArray[i].y);
ctx.closePath();
ctx.fillStyle=colour;
ctx.fill();
}
}
function attachHoverHandlers()
{
//
// Attach event-listeners to each of the areas in the image-map to handle mouseover
//
var areas = document.querySelectorAll('area');
var i, n = areas.length;
for (i=0; i<n; i++)
{
areas[i].addEventListener('mouseover', onAreaHovered, false);
}
}
function onAreaHovered(e)
{
var hoveredElement = this;
var coordStr = this.getAttribute('coords');
var areaType = this.getAttribute('shape');
switch (areaType)
{
case 'polygon':
case 'poly':
showPolyCoords(coordStr);
break;
default:
alert("You need to add a handler for areas of type '" + areaType + "'");
}
}
function coordStrToPointArray(coordStr)
{
var mCoords = coordStr.split(',');
var i, n = mCoords.length;
var coordArray = [];
coordArray.push( new p2d(mCoords[0], mCoords[1]) );
for (i=2; i<n; i+=2)
{
coordArray.push( new p2d(mCoords[i], mCoords[i+1]) );
}
coordArray.push( new p2d(mCoords[0], mCoords[1]) );
return coordArray;
}
// takes a string that contains coords eg - "227,307,261,309, 339,354, 328,371, 240,331"
// draws a line from each co-ord pair to the next - assumes starting point needs to be repeated as ending point.
function showPolyCoords(coOrdStr)
{
var coordArray = coordStrToPointArray(coOrdStr);
var sortedArray = coordArray.slice();
sortedArray.sort(sortX);
var minX = sortedArray[0].x;
var maxX = sortedArray[sortedArray.length-1].x;
sortedArray.sort(sortY);
var minY = sortedArray[0].y;
var maxY = sortedArray[sortedArray.length-1].y;
var topLeft = new p2d(minX, minY);
var botRight = new p2d(maxX, maxY);
testFuncWithClipping(topLeft, botRight, 'img1', coordArray);
}
function p2d(x, y)
{
this.x = Number(x);
this.y = Number(y);
return this;
}
// unneccesary - just makes displaying the point easier.
// Having this prototype available means that (in chrome at least)
// the code: "console.log( pt2d );" or "alert( pt2d );" will result in "<xCoord, yCoord>" being printed/alerted
p2d.prototype.toString = function()
{
return "<"+this.x+", "+this.y+">";
}
// comparison functions used when sorting the point list to obtain the min/max values of both X and Y
function sortX(a, b){return a.x - b.x;}
function sortY(a, b){return a.y - b.y;}
function testFuncWithClipping(topLeft, botRight, srcImgId, pointArray)
{
var width = botRight.x - topLeft.x;
var height = botRight.y - topLeft.y;
var can = newEl('canvas');
can.width = width;
can.height = height;
var ctx = can.getContext('2d');
var img = byId(srcImgId);
ctx.beginPath();
ctx.moveTo( pointArray[0].x - topLeft.x, pointArray[0].y-topLeft.y );
var i, n = pointArray.length;
for (i=0; i<n; i++)
{
ctx.lineTo( pointArray[i].x - topLeft.x, pointArray[i].y-topLeft.y );
}
ctx.clip();
ctx.drawImage(img, topLeft.x, topLeft.y, width, height, 0,0, width,height);
byId('img2').src = can.toDataURL();
}
</script>
<style>
body
{
background-color: gray;
}
#canvas2
{
pointer-events: none; /* make the canvas transparent to the mouse - needed since canvas is position infront of image */
position: absolute; /* you'll need to use this trick to allow the area to know when the mouse leaves it, so you can hide/destroy the */
} /* enlarged version of the hovered area */
</style>
</head>
<body>
<!--
Usually, you would use this element.
For the purpose of making a working demo, I've used the next element and have created the picture using the map data and
the funtion createImageFromMapAreasForUseAtStackoverflow
As mentioned above, the original image is:
https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Australia_location_map_recolored.png/500px-Australia_location_map_recolored.png
which was saved as ausMap.png in the img folder of my localhost.
<img id='img1' usemap='#imgMap1' src='img/ausMap.png' />
-->
<img id='img1' usemap='#imgMap1'/>
<map name='imgMap1' id='imgMap1'>
<area shape="polygon" coords="359, 324, 373, 332, 392, 327, 393, 346, 375, 356, 364, 343" title="Tasmania">
<area shape="polygon" coords="325, 258, 335, 258, 339, 265, 346, 265, 347, 271, 357, 279, 360, 279, 361, 276, 368, 278, 380, 279, 388, 277, 390, 288, 406, 293, 405, 296, 391, 297, 377, 308, 376, 310, 372, 308, 356, 303, 350, 307, 338, 303, 332, 301, 325, 300" title="Victoria">
<area shape="polygon" coords="325, 207, 397, 206, 403, 201, 417, 203, 420, 209, 425, 205, 427, 200, 440, 197, 440, 204, 436, 222, 432, 235, 432, 241, 424, 245, 419, 255, 415, 267, 408, 277, 408, 293, 391, 286, 389, 278, 381, 279, 373, 279, 364, 276, 361, 278, 348, 271, 346, 265, 340, 266, 338, 261, 333, 258, 325, 258" title="New South Wales">
<area shape="polygon" coords="325, 206, 398, 207, 404, 201, 417, 203, 423, 207, 427, 201, 434, 198, 441, 198, 436, 169, 429, 159, 419, 150, 416, 142, 410, 138, 406, 139, 400, 121, 397, 114, 375, 101, 372, 82, 367, 79, 365, 61, 357, 52, 353, 56, 349, 39, 345, 31, 341, 22, 336, 18, 336, 27, 330, 35, 334, 38, 331, 41, 330, 46, 331, 60, 329, 66, 329, 74, 326, 77, 326, 85, 320, 90, 312, 88, 308, 82, 298, 78, 298, 175, 325, 175" title="Queensland">
<area shape="polygon" coords="297, 175, 297, 79, 273, 60, 286, 34, 281, 30, 276, 33, 268, 33, 254, 29, 250, 25, 247, 22, 243, 22, 244, 26, 249, 31, 246, 33, 237, 33, 235, 33, 234, 31, 236, 28, 236, 23, 231, 25, 228, 24, 225, 27, 230, 29, 233, 33, 229, 37, 223, 41, 227, 45, 222, 46, 218, 54, 221, 62, 214, 63, 213, 175" title="Northern Territory">
<area shape="polygon" coords="214, 234, 214, 61, 211, 60, 205, 65, 205, 59, 197, 50, 194, 54, 190, 52, 187, 56, 180, 56, 179, 62, 174, 64, 174, 75, 163, 74, 167, 81, 164, 85, 160, 77, 150, 82, 149, 90, 153, 93, 148, 97, 143, 108, 127, 114, 122, 113, 121, 115, 111, 120, 103, 118, 94, 125, 90, 130, 85, 132, 80, 138, 78, 136, 80, 131, 73, 138, 75, 144, 75, 148, 72, 150, 72, 160, 75, 170, 78, 176, 75, 179, 69, 172, 76, 187, 76, 193, 82, 200, 82, 205, 84, 210, 84, 218, 91, 234, 92, 241, 93, 250, 90, 253, 86, 253, 86, 261, 92, 262, 99, 269, 112, 269, 125, 263, 132, 256, 145, 254, 164, 257, 168, 248, 172, 248, 186, 241, 192, 242" title="Western Australia">
<area shape="polygon" coords="324, 299, 323, 175, 213, 175, 213, 234, 233, 232, 242, 238, 249, 236, 261, 242, 258, 246, 265, 249, 269, 256, 270, 261, 272, 263, 277, 267, 277, 261, 281, 257, 288, 254, 291, 249, 295, 246, 295, 243, 297, 250, 294, 254, 290, 259, 291, 265, 287, 269, 294, 268, 297, 262, 301, 268, 299, 272, 295, 275, 290, 273, 285, 274, 283, 277, 290, 278, 294, 275, 301, 273, 315, 286, 314, 291" title="South Australia">
<area shape='rect' coords='0,0,100,100' title='unsupported area type'>
</map>
<img id='img2'/>
</body>
</html>
接下来,您可以在页面上尝试的工作演示(使用全屏获得最佳体验)
"use strict";
function byId(e){return document.getElementById(e);}
function newEl(tag){return document.createElement(tag);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(e)
{
createImageFromMapAreasForUseAtStackoverflow();
attachHoverHandlers();
}
// this function is only used for the purpose of answering this question.
// Ordinarily, you would set the src of #img1 to be that of your image. - since cross-origin contamination prevents
// access to the image data if the image comes from a different server, I've just opted to create the image from scratch.
//
// the original image may be found here: https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Australia_location_map_recolored.png/500px-Australia_location_map_recolored.png
function createImageFromMapAreasForUseAtStackoverflow()
{
var imgWidth = 500, imgHeight = 360;
var can = newEl('canvas');
can.width = imgWidth;
can.height = imgHeight;
var ctx = can.getContext('2d');
ctx.fillStyle = '#ecf5f6';
ctx.fillRect(0,0,imgWidth,imgHeight);
var areas = document.querySelectorAll('area');
var i, n = areas.length;
var colours = ['#f4f100', '#b2d025', '#f67c60', '#8fbce1', '#f4f236', '#fca164', '#bc9eee', 'black'];
for (i=0; i<n; i++)
{
var areaType = areas[i].getAttribute('shape');
if ((areaType == 'polygon') || (areaType == 'poly'))
drawMapPoly(areas[i].getAttribute('coords'), colours[i]);
}
byId('img1').src = can.toDataURL();
function drawMapPoly(coordStr, colour)
{
ctx.beginPath();
var ptArray = coordStrToPointArray(coordStr);
var i, n=ptArray.length;
ctx.moveTo(ptArray[0].x, ptArray[0].y);
for (i=0;i<n;i++)
ctx.lineTo(ptArray[i].x,ptArray[i].y);
ctx.closePath();
ctx.fillStyle=colour;
ctx.fill();
}
}
function attachHoverHandlers()
{
//
// Attach event-listeners to each of the areas in the image-map to handle mouseover
//
var areas = document.querySelectorAll('area');
var i, n = areas.length;
for (i=0; i<n; i++)
{
areas[i].addEventListener('mouseover', onAreaHovered, false);
}
}
function onAreaHovered(e)
{
var hoveredElement = this;
var coordStr = this.getAttribute('coords');
var areaType = this.getAttribute('shape');
switch (areaType)
{
case 'polygon':
case 'poly':
showPolyCoords(coordStr);
break;
default:
alert("You need to add a handler for areas of type '" + areaType + "'");
}
}
function coordStrToPointArray(coordStr)
{
var mCoords = coordStr.split(',');
var i, n = mCoords.length;
var coordArray = [];
coordArray.push( new p2d(mCoords[0], mCoords[1]) );
for (i=2; i<n; i+=2)
{
coordArray.push( new p2d(mCoords[i], mCoords[i+1]) );
}
coordArray.push( new p2d(mCoords[0], mCoords[1]) );
return coordArray;
}
// takes a string that contains coords eg - "227,307,261,309, 339,354, 328,371, 240,331"
// draws a line from each co-ord pair to the next - assumes starting point needs to be repeated as ending point.
function showPolyCoords(coOrdStr)
{
var coordArray = coordStrToPointArray(coOrdStr);
var sortedArray = coordArray.slice();
sortedArray.sort(sortX);
var minX = sortedArray[0].x;
var maxX = sortedArray[sortedArray.length-1].x;
sortedArray.sort(sortY);
var minY = sortedArray[0].y;
var maxY = sortedArray[sortedArray.length-1].y;
var topLeft = new p2d(minX, minY);
var botRight = new p2d(maxX, maxY);
testFuncWithClipping(topLeft, botRight, 'img1', coordArray);
}
function p2d(x, y)
{
this.x = Number(x);
this.y = Number(y);
return this;
}
// unneccesary - just makes displaying the point easier.
// Having this prototype available means that (in chrome at least)
// the code: "console.log( pt2d );" or "alert( pt2d );" will result in "<xCoord, yCoord>" being printed/alerted
p2d.prototype.toString = function()
{
return "<"+this.x+", "+this.y+">";
}
// comparison functions used when sorting the point list to obtain the min/max values of both X and Y
function sortX(a, b){return a.x - b.x;}
function sortY(a, b){return a.y - b.y;}
function testFuncWithClipping(topLeft, botRight, srcImgId, pointArray)
{
var width = botRight.x - topLeft.x;
var height = botRight.y - topLeft.y;
var can = newEl('canvas');
can.width = width;
can.height = height;
var ctx = can.getContext('2d');
var img = byId(srcImgId);
ctx.beginPath();
ctx.moveTo( pointArray[0].x - topLeft.x, pointArray[0].y-topLeft.y );
var i, n = pointArray.length;
for (i=0; i<n; i++)
{
ctx.lineTo( pointArray[i].x - topLeft.x, pointArray[i].y-topLeft.y );
}
// comment the below line to see the effect of drawing a rectangular
// portion of the image without clipping.
ctx.clip();
ctx.drawImage(img, topLeft.x, topLeft.y, width, height, 0,0, width,height);
byId('img2').src = can.toDataURL();
}
body
{
background-color: gray;
}
#canvas2
{
pointer-events: none; /* make the canvas transparent to the mouse - needed since canvas is position infront of image */
position: absolute; /* you'll need to use this trick to allow the area to know when the mouse leaves it, so you can hide/destroy the */
} /* enlarged version of the hovered area */
<!--
Usually, you would use this element.
For the purpose of making a working demo, I've used the next element and have created the picture using the map data and
the funtion createImageFromMapAreasForUseAtStackoverflow
As mentioned above, the original image is:
https://upload.wikimedia.org/wikipedia/commons/thumb/1/16/Australia_location_map_recolored.png/500px-Australia_location_map_recolored.png
which was saved as ausMap.png in the img folder of my localhost.
<img id='img1' usemap='#imgMap1' src='img/ausMap.png' />
-->
<img id='img1' usemap='#imgMap1'/>
<map name='imgMap1' id='imgMap1'>
<area shape="polygon" coords="359, 324, 373, 332, 392, 327, 393, 346, 375, 356, 364, 343" title="Tasmania">
<area shape="polygon" coords="325, 258, 335, 258, 339, 265, 346, 265, 347, 271, 357, 279, 360, 279, 361, 276, 368, 278, 380, 279, 388, 277, 390, 288, 406, 293, 405, 296, 391, 297, 377, 308, 376, 310, 372, 308, 356, 303, 350, 307, 338, 303, 332, 301, 325, 300" title="Victoria">
<area shape="polygon" coords="325, 207, 397, 206, 403, 201, 417, 203, 420, 209, 425, 205, 427, 200, 440, 197, 440, 204, 436, 222, 432, 235, 432, 241, 424, 245, 419, 255, 415, 267, 408, 277, 408, 293, 391, 286, 389, 278, 381, 279, 373, 279, 364, 276, 361, 278, 348, 271, 346, 265, 340, 266, 338, 261, 333, 258, 325, 258" title="New South Wales">
<area shape="polygon" coords="325, 206, 398, 207, 404, 201, 417, 203, 423, 207, 427, 201, 434, 198, 441, 198, 436, 169, 429, 159, 419, 150, 416, 142, 410, 138, 406, 139, 400, 121, 397, 114, 375, 101, 372, 82, 367, 79, 365, 61, 357, 52, 353, 56, 349, 39, 345, 31, 341, 22, 336, 18, 336, 27, 330, 35, 334, 38, 331, 41, 330, 46, 331, 60, 329, 66, 329, 74, 326, 77, 326, 85, 320, 90, 312, 88, 308, 82, 298, 78, 298, 175, 325, 175" title="Queensland">
<area shape="polygon" coords="297, 175, 297, 79, 273, 60, 286, 34, 281, 30, 276, 33, 268, 33, 254, 29, 250, 25, 247, 22, 243, 22, 244, 26, 249, 31, 246, 33, 237, 33, 235, 33, 234, 31, 236, 28, 236, 23, 231, 25, 228, 24, 225, 27, 230, 29, 233, 33, 229, 37, 223, 41, 227, 45, 222, 46, 218, 54, 221, 62, 214, 63, 213, 175" title="Northern Territory">
<area shape="polygon" coords="214, 234, 214, 61, 211, 60, 205, 65, 205, 59, 197, 50, 194, 54, 190, 52, 187, 56, 180, 56, 179, 62, 174, 64, 174, 75, 163, 74, 167, 81, 164, 85, 160, 77, 150, 82, 149, 90, 153, 93, 148, 97, 143, 108, 127, 114, 122, 113, 121, 115, 111, 120, 103, 118, 94, 125, 90, 130, 85, 132, 80, 138, 78, 136, 80, 131, 73, 138, 75, 144, 75, 148, 72, 150, 72, 160, 75, 170, 78, 176, 75, 179, 69, 172, 76, 187, 76, 193, 82, 200, 82, 205, 84, 210, 84, 218, 91, 234, 92, 241, 93, 250, 90, 253, 86, 253, 86, 261, 92, 262, 99, 269, 112, 269, 125, 263, 132, 256, 145, 254, 164, 257, 168, 248, 172, 248, 186, 241, 192, 242" title="Western Australia">
<area shape="polygon" coords="324, 299, 323, 175, 213, 175, 213, 234, 233, 232, 242, 238, 249, 236, 261, 242, 258, 246, 265, 249, 269, 256, 270, 261, 272, 263, 277, 267, 277, 261, 281, 257, 288, 254, 291, 249, 295, 246, 295, 243, 297, 250, 294, 254, 290, 259, 291, 265, 287, 269, 294, 268, 297, 262, 301, 268, 299, 272, 295, 275, 290, 273, 285, 274, 283, 277, 290, 278, 294, 275, 301, 273, 315, 286, 314, 291" title="South Australia">
<area shape='rect' coords='0,0,100,100' title='unsupported area type'>
</map>
<img id='img2'/>
玩得开心!
答案 1 :(得分:-1)