将鼠标悬停在SVG图像路径上时,我希望鼠标移动来识别光标下方的相关点。
LOGIC: 当前的逻辑是浏览器计算SVG图像路径坐标。 共同组合物存储在2d阵列中。 将这些坐标与mousemove坐标进行比较。 当两者匹配时,匹配的目的地会出现预渲染的圆圈。
关注: 我主要担心的是这种行为对性能的影响,特别是当我接受我目前正在进行的项目时。如何在浏览器上使此过程更轻松。我可以使用'限制'减少浏览器必须完成的计算次数,但主要关注的是上面的逻辑。
的jsfiddle:
HTML:
<div id="svgContainer" style="float: left;">
<svg viewBox="0 0 800 600" height="600" width="800">
<path class="clipPath clipNeck" fill="none" stroke="#848484" stroke-width="1.0244" d="M329.66,99.99l22.1,4c0,0-6.9,45.5-2.1,51.6
c0,0-11.75,72.7-10.05,83.7c0,0,18.8,81.1,17.3,85.4H238.43c-1.5-4.3,17.3-85.4,17.3-85.4c1.7-11-10.12-83.7-10.12-83.7
c4.8-6.1-2.1-51.6-2.1-51.6l22.1-4"/>
</svg>
</div>
<div id="stats" style="float: left;">
<div id="total_nodes">
</div>
<div id="mouse_cordinates">
</div>
<div id="svg_cordinates">
</div>
<div id="response_time">
</div>
<div id="zoom" data-action="zoomin" style="width: 82px;height: 25px;background-color: red;border: 2px solid #000;cursor: pointer;display: none">
Zoom In
</div>
</div>
JS:
var pointsArray = new Array();
var nodes = new Array();
var zoom = document.getElementById('zoom');
function createNode(type, attributes) {
var node = document.createElementNS('http://www.w3.org/2000/svg', type);
if (type === 'image')
attributes.preserveAspectRatio = 'none';
if (typeof attributes !== undefined)
setAttributes(node, attributes);
return node;
}
function setAttributes(el, attributes) {
for (var attribute in attributes) {
if (attributes[attribute] !== null && typeof (attributes[attribute]) !== "undefined") {
el.setAttribute(attribute, attributes[attribute]);
}
}
}
function roundDecimalNumber(number, places) {
var place;
if (places === 0)
place = places;
else if (!places)
place = 2;
else
place = places;
number = parseFloat(number);
number = number.toFixed(place);
number = parseFloat(number);
return number;
}
function showStats(count) {
var total_nodes = document.getElementById('total_nodes');
total_nodes.innerHTML = 'Total Nodes = ' + count;
zoom.style.display = 'block';
}
function fetchTemplatePath() {
var path = document.getElementsByClassName('clipPath clipNeck')[0];
if (path) {
var length = Math.ceil(path.getTotalLength());
var point, tx, ty;
// var tab = TabController.currentTab.id;
// var view = TabController.currentView;
var path2 = createNode('path', {
id: 'path_node_test',
d: '',
stroke: 'red',
'stroke-width': 1,
fill: 'none'
});
document.getElementsByTagName('svg')[0].appendChild(path2);
var i = 0;
var incrementor = 1;
var d = '';
var intervalVar = setInterval(function() {
point = path.getPointAtLength(i);
tx = roundDecimalNumber(point.x, 0);
ty = roundDecimalNumber(point.y, 0);
cordinatesXY = {
x: tx,
y: ty
};
if (!nodes[tx]) {
nodes[tx] = new Array();
nodes[tx][ty] = 1;
}
else {
if (!nodes[tx][ty]) {
nodes[tx][ty] = 1;
}
}
if (i === 0)
d = 'M ' + tx + ' ' + ty + ' L ';
else
d += tx + ' ' + ty + ' ';
path2.setAttribute('d', d);
pointsArray.push(cordinatesXY);
i += incrementor;
if (i > length) {
clearInterval(intervalVar);
showStats(i);
}
}, 1);
}
}
function matchSurrondings(x, y) {
var flag = false;
var radius = 10;//boxes left, right, up & down;
for (var i = x; i <= (x + radius); i++) {// right
if (nodes[i]) {
if (nodes[i][y]) {
return {x: i, y: y};
}
}
}
for (var i = x; i >= (x - radius); i--) {// left
if (nodes[i]) {
if (nodes[i][y]) {
return {x: i, y: y};
}
}
}
for (var i = y; i >= (y - radius); i--) {// top
if (nodes[x]) {
if (nodes[x][i]) {
return {x: x, y: i};
}
}
}
for (var i = y; i <= (y + radius); i++) {// down
if (nodes[x]) {
if (nodes[x][i]) {
return {x: x, y: i};
}
}
}
return flag;
}
function matchMouseCordinatesWithNodes(x, y) {
if (nodes[x]) {
if (nodes[x][y]) {
return {x: x, y: y};
}
}
var value=false;
value = matchSurrondings(x, y);
return value;
}
function getSvgCordinates(event) {
if (!event) {
return {
x: 0,
y: 0
};
}
var mainsvg = document.getElementsByTagName('svg')[0];
var m = mainsvg.getScreenCTM();
var p = mainsvg.createSVGPoint();
var x, y;
x = event.pageX;
y = event.pageY;
p.x = x;
p.y = y;
p = p.matrixTransform(m.inverse());
x = p.x;
y = p.y;
x = roundDecimalNumber(x,0);
y = roundDecimalNumber(y,0);
return {x: x, y: y};
}
function createCircleNode(x, y) {
var circle_node = document.getElementById('circle_node');
if (!circle_node) {
circle_node = createNode('circle', {
id: 'circle_node',
cx: x,
cy: y,
r: 3,
fill: 'green',
stroke: 'none'
});
document.getElementsByTagName('svg')[0].appendChild(circle_node);
}
else {
circle_node.setAttribute('cx', x);
circle_node.setAttribute('cy', y);
}
}
function defaultmousemove(event) {
var starttime=Date.now();
var mouse_cordinates = document.getElementById('mouse_cordinates');
if (mouse_cordinates) {
mouse_cordinates.innerHTML = 'Mouse Co-ordinates = X:' + event.pageX + ' , Y:' + event.pageY;
}
var svgXY = getSvgCordinates(event);
var svg_cordinates = document.getElementById('svg_cordinates');
if (svg_cordinates) {
svg_cordinates.innerHTML = 'SVG Co-ordinates = X:' + svgXY.x + ' , Y:' + svgXY.y;
}
var nodes_matched = matchMouseCordinatesWithNodes(svgXY.x, svgXY.y);
if (nodes_matched)
createCircleNode(nodes_matched.x, nodes_matched.y);
var endTime=Date.now();
var diff=endTime-starttime;
diff=diff/1000;// in secs;
var response_time=document.getElementById('response_time');
response_time.innerHTML='Calculation completed in '+diff+' secs';
}
function zoomIn() {
zoom.setAttribute('data-action', 'zoomout');
zoom.innerHTML = 'Zoom Out';
var mainsvg = document.getElementsByTagName('svg')[0];
mainsvg.setAttribute('viewBox', '100 100 400 200');
}
function zoomOut() {
zoom.setAttribute('data-action', 'zoomin');
zoom.innerHTML = 'Zoom In';
var mainsvg = document.getElementsByTagName('svg')[0];
mainsvg.setAttribute('viewBox', '0 0 800 600');
}
function defaultmousedown(event) {
event.cancelBubble = true;
event.preventDefault();
if (event.target.hasAttribute('data-action')) {
var action = event.target.getAttribute('data-action');
if (action === 'zoomin') {
zoomIn();
}
else if (action === 'zoomout') {
zoomOut();
}
}
}
fetchTemplatePath();
var mainsvg = document.getElementsByTagName('svg')[0];
mainsvg.addEventListener('mousemove', defaultmousemove, false);
document.addEventListener('mousedown', defaultmousedown, false);
答案 0 :(得分:0)
如果路径小于几百点,我就不会发现计算有问题。
但是,鼠标和svg坐标不会跟踪所有broswers的网页滚动时间。
尝试以下方法获取这些值:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>SCR X,Y using SVGPoint & getScreenCTM</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body style='padding:10px;font-family:arial'>
<center>
<h4>SCR X,Y using SVGPoint & getScreenCTM</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
Assume the SVG image is contained in a DIV inline within the HTML5 document. However neiher the SVG <b>viewBox</b> nor its <b>width/height</b> are the same as the DIV container.
Therfore you must use getScreenCTM to get the x,y values(scr).
</div>
<table>
<tr><td align=left>
A 400x400 DIV containing SVG.<br />
SVG has a viewBox=0 0 2000 2000
</td>
<td align=left>
<div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;'>
<svg id="mySVG" width="100%" height="100%" viewBox="0 0 2000 2000" onmousemove="getXY(evt)" >
<circle r=20 fill=black cx=200 cy=200 />
</svg>
</div>
</td>
<td align=left>
<table style='font-family:lucida console'>
<tr><td colspan=4><b>SVG clientX/Y - DIV offset</b></td></tr>
<tr style='font-size:110%'>
<td align=right>svg X:</td> <td><input style='border:2px solid black;font-size:120%' type=text id=svgOffsetXValue size=1 /></td>
<td><input style='border:2px solid black;font-size:120%' type=text id=svgOffsetYValue size=1 /></td><td align=left>:svg Y</td>
</tr>
<tr><td colspan=4><b>SVGPoint/getScreenCTM</b></td></tr>
<tr style='font-size:110%'>
<td align=right>scr X:</td> <td><input style='border:2px solid black;font-size:120%' type=text id=scrXValue size=1 /></td>
<td><input style='border:2px solid black;font-size:120%' type=text id=scrYValue size=1 /></td><td align=left>:scr Y</td>
</tr>
</table>
</td>
</tr>
</table>
<br />SVG Source:<br />
<textarea id=svgSourceValue style='font-size:110%;font-family:lucida console;width:90%;height:200px'></textarea>
<br />Javascript:<br />
<textarea id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea>
</center>
<div id='browserDiv' style='padding:3px;position:absolute;top:5px;left:5px;background-color:gainsboro;'></div>
<script id=myScript>
//---mouse move---
function getXY(evt)
{
var rect = svgDiv.getBoundingClientRect();
svgOffsetXValue.value=evt.clientX-rect.left
svgOffsetYValue.value=evt.clientY-rect.top
var pnt = mySVG.createSVGPoint();
pnt.x = evt.clientX;
pnt.y = evt.clientY;
var sCTM = mySVG.getScreenCTM();
var PNT = pnt.matrixTransform(sCTM.inverse());
scrXValue.value=PNT.x
scrYValue.value=PNT.y
}
</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
svgSourceValue.value=svgDiv.innerHTML
jsValue.value=myScript.text
}
</script>
</body>
</html>