簡體   English   中英

SVG懸停在多個元素上

[英]SVG hover with multiple elements

我有兩個svg元素,我已經應用了mouseover / mouseout事件。 目標是將mouseover時的蒙版半徑增加到變量( maxMaskRadius )指定的大小,並在mouseout maxMaskRadiusdecrease回初始狀態( initialMaskRadius )。

我只使用一個元素完美地工作。 但是當我有兩個元素並從一個元素懸停到另一個元素時,前面元素的動畫會立即中止。 但我想讓它重新回到它的初始狀態。 我目前的代碼很遺憾是不可能的。

關於如何做到這一點的任何建議?

DEMO

CSS:

.dday.highlight .overlay {
    fill: rgba(247,99,62,0.8);
}

.dday.normal {
    width: 288px;
    height: 288px;
}

HTML:

<svg class="dday highlight normal" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-image="car.jpg">

    <image height="196" width="250" />

    <a class="overlay" xlink:href="/svg/index.html" target="_top">
        <rect x="0" y="0" width="288" height="288" style="mask: url(#mask1)" onmouseover="initAnimation(evt)" onmouseout="initAnimation(evt)" />
    </a>

    <mask id="mask1">
        <rect x="0" y="0" width="288" height="288" fill="#fff" />
        <circle cx="125" cy="125" r="25" />
    </mask>

</svg>


<svg class="dday highlight normal" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-image="nokia.jpg">

    <image height="196" width="250" />

    <a class="overlay" xlink:href="/svg/index.html" target="_top">
        <rect x="0" y="0" width="288" height="288" style="mask: url(#mask2)" onmouseover="initAnimation(evt)" onmouseout="initAnimation(evt)" />
    </a>

    <mask id="mask2">
        <rect x="0" y="0" width="288" height="288" fill="#fff" />
        <circle cx="125" cy="125" r="25" />
    </mask>

</svg>

JS:

var maxImageWidth = 250,
    maxImageHeight = 196,
    ease = 50,
    speed = 12,
    maxMaskRadius = 100,

    svg = null,
    svgWidth = null,
    svgHeight = null,
    mask = null,
    maskRadius = null,
    initialMaskRadius = null,
    imageObj = [],
    imageSrcs = [],
    imageWidth = null,
    imageHeight = null,
    mouseEvent = null;

init();

function init(el, index) {
    $('.dday').each(function(index){
        defineCurrentElement(this, index);
        positionMask();
    });
}

function defineCurrentElement(el, index) {
    // Redefine the current Element
    svg = $(el).closest('.dday'),
    svgWidth = svg.width(),
    svgHeight = svg.height(),
    mask = svg.find('circle')[0];

    // On page load there is a index provided to load the images for each element
    if(typeof index !== 'undefined'){
        loadImage(index);
    }
}

function loadImage(index) {
    // Load images and scale them to fit the predefined area
    imageSrcs[index] = svg.data('image');

    imageObj[index] = new Image(),
    imageObj[index].image = $('image')[index];

    imageObj[index].onload = function(){
        scale_width = maxImageWidth / this.width;
        scale_height = maxImageHeight / this.height;

        scale = Math.min(scale_width, scale_height);

        imageWidth = this.width * scale;
        imageHeight = this.height * scale;

        var xCoordinate = (svgWidth - imageWidth) / 2,
            yCoordinate = (svgHeight - imageHeight) / 2;

        this.image.setAttributeNS('http://www.w3.org/1999/xlink','href', imageSrcs[index]);
        this.image.setAttributeNS(null,'width', imageWidth);
        this.image.setAttributeNS(null,'height', imageHeight);
        this.image.setAttributeNS(null,'x', xCoordinate);
        this.image.setAttributeNS(null,'y', yCoordinate);
    };
    imageObj[index].src = imageSrcs[index];
}

function initAnimation(ev) {
    // Triggered on mouseover/-out
    // Change current element and init animation
    defineCurrentElement(ev.target);
    mouseEvent = ev.type;
    requestAnimationFrame(animate);
}

function animate() {
    if(mouseEvent == 'mouseover') {
        // Increase mask radius on mouseover and repeat until target state is reached

        maskRadius += Math.round(Math.max(((maxMaskRadius-maskRadius)/ease) * speed, 0.5));

        if(maskRadius >= maxMaskRadius) {
            // Target radius has been reached
            maskRadius = maxMaskRadius;
        } else {
            // Target radius hasn't been reached yet -> repeat animation
            mask.setAttributeNS(null,'r', maskRadius);
            requestAnimationFrame(animate);
        }
    } else {
        // Decrease mask radius on mouseover and repeat until initial state is reached

        maskRadius -= Math.max(((maskRadius-initialMaskRadius)/ease) * speed, 0.5);

        if(maskRadius <= initialMaskRadius) {
            // Target radius has been reached
            maskRadius = initialMaskRadius;
        } else {
            // Target radius hasn't been reached yet -> repeat animation
            mask.setAttributeNS(null,'r', maskRadius);
            requestAnimationFrame(animate);
        }
    }
}

function positionMask() {
    // Center mask inside element
    maskRadius = initialMaskRadius = parseInt(mask.getAttributeNS(null, 'r'), 10);

    var maskWidth = maskRadius * 2,
        xCoordinate = (svgWidth - maskWidth) / 2 + maskRadius,
        yCoordinate = (svgHeight - maskWidth) / 2 + maskRadius;

    mask.setAttributeNS(null,'cx', xCoordinate);
    mask.setAttributeNS(null,'cy', yCoordinate);
}

Okke,我修復了你的所有代碼,這對你的代碼來說並不是一件容易的事。 請聲明您使用的所有變量,而不是在函數全局變量中用作您自己的私有變量,因為您可以重寫現有的全局變量。

現在關於固定代碼:

  • CSS:沒有變化。
  • HTML:刪除了內聯處理程序( onmouseoveronmouseout

  • 使用Javascript:

    • 當文件已經准備好各svg與類元素dday正在初始化:在下載的圖像為svg如果變量index存在(裝載邏輯沒有幾乎改變),則定心掩模,動畫聲明功能,然后加入處理程序rect在元件a元件在初始化svg元素。
    • 所有設置都已導出到變量settings
    • svg所有私有變量都存儲在{svgElement}.svgData對象中。

演示: jsFiddle

PS順便說一下,這段代碼也不好用,需要更多的時間來清理代碼,但這段代碼有效。

HTML:

<svg class="dday sector-sports normal" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-image="http://img1.wikia.nocookie.net/__cb20130511205806/epicrapbattlesofhistory/images/9/94/Vaderrotj.jpg">

    <image height="196" width="250" />

    <a class="overlay" xlink:href="/svg/index.html" target="_top">
        <rect x="0" y="0" width="288" height="288" style="mask: url(#mask1)" />
    </a>

    <mask id="mask1">
        <rect x="0" y="0" width="288" height="288" fill="#fff" />
        <circle cx="125" cy="125" r="25" />
    </mask>

</svg>


<svg class="dday sector-sports normal" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" data-image="http://static.comicvine.com/uploads/original/11111/111116692/3213841-7948839370-yoda..jpg">

    <image height="196" width="250" />

    <a class="overlay" xlink:href="/svg/index.html" target="_top">
        <rect x="0" y="0" width="288" height="288" style="mask: url(#mask2)" />
    </a>

    <mask id="mask2">
        <rect x="0" y="0" width="288" height="288" fill="#fff" />
        <circle cx="125" cy="125" r="25" />
    </mask>

</svg>

Javascript :(使用jQuery 1.11庫)

$(document).ready(function () {
    var settings = {
        imageWidthMax: 250,
        imageHeightMax: 196,
        ease: 50,
        speed: 12,
        maskRadiusMax: 100
    };
    var maskElements = [];

    $('svg.dday').each(function (index) {

        if (maskElements.indexOf(this) < 0) {
            maskElements.push(this);
            var sd = {};
            this.svgData = sd;

            sd.svg = $(this);
            sd.svgWidth = sd.svg.width();
            sd.svgHeight = sd.svg.height();
            sd.mask = sd.svg.find('circle')[0];

            // On page load there is a index provided to load the images for each element
            if (typeof index !== 'undefined') {

                var img = new Image();

                img.image = $('image')[index];
                img.onload = function () {
                    var m_scale_width = settings.imageWidthMax / this.width;
                    var m_scale_height = settings.imageHeightMax / this.height;
                    var m_scale = Math.min(m_scale_width, m_scale_height);

                    sd.imgWidth = this.width * m_scale;
                    sd.imgHeight = this.height * m_scale;

                    var m_x = (sd.svgWidth - sd.imgWidth) / 2;
                    var m_y = (sd.svgHeight - sd.imgHeight) / 2;

                    this.image.setAttributeNS('http://www.w3.org/1999/xlink', 'href', sd.svg.data('image'));
                    this.image.setAttributeNS(null, 'width', sd.imgWidth);
                    this.image.setAttributeNS(null, 'height', sd.imgHeight);
                    this.image.setAttributeNS(null, 'x', m_x);
                    this.image.setAttributeNS(null, 'y', m_y);
                };
                img.src = sd.svg.data('image');

            }

            //Center mask inside element
            sd.maskRadiusInit = parseInt(sd.mask.getAttributeNS(null, 'r'), 10);
            sd.maskRadius = sd.maskRadiusInit;

            sd.maskWidth = sd.maskRadius * 2;
            sd.maskX = (sd.svgWidth - sd.maskWidth) / 2 + sd.maskRadius;
            sd.maskY = (sd.svgHeight - sd.maskWidth) / 2 + sd.maskRadius;

            sd.mask.setAttributeNS(null, 'cx', sd.maskX);
            sd.mask.setAttributeNS(null, 'cy', sd.maskY);

            var animate = function () {
                var m_addToRadius = Math.round(Math.max(((settings.maskRadiusMax - sd.maskRadius) / settings.ease) * settings.speed, 0.5));
                if (sd.eventType === 'mouseover') {
                    sd.maskRadius += m_addToRadius;

                    if (sd.maskRadius > settings.maskRadiusMax) {
                        sd.maskRadius = settings.maskRadiusMax;
                        sd.mask.setAttributeNS(null, 'r', sd.maskRadius);
                    } else {
                        sd.mask.setAttributeNS(null, 'r', sd.maskRadius);
                        requestAnimationFrame(animate);
                    }
                } else {
                    sd.maskRadius -= Math.round(Math.max(m_addToRadius, 0.5));

                    if (sd.maskRadius <= sd.maskRadiusInit) {
                        sd.maskRadius = sd.maskRadiusInit;
                        sd.mask.setAttributeNS(null, 'r', sd.maskRadius);
                    } else {
                        sd.mask.setAttributeNS(null, 'r', sd.maskRadius);
                        requestAnimationFrame(animate);
                    }
                }
            };

            $('a>rect', this).on('mouseover mouseleave', function (evt) {
                sd.eventType = evt.type;
                requestAnimationFrame(animate);
            });
        }
    });
});

演示: jsFiddle

下面是一個Javascript動畫對象的示例, AnimateJS它可以跨瀏覽器工作。 該示例顯示了svg元素或包含<g>元素的二次懸停效果。 嘗試使用您的應用。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Example: Hover Over Element - Quadratic</title>
  <script type="text/javascript" src="../bowser.js"></script>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body style='padding:10px;font-family:arial'>
<center>
<h4>Example: Hover Over Element - Quadratic</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
When the cursor moves over the element its size is increased. This works on both transfomed and non-transformed elements, contained in a &lt;g&gt;, or as individual elements. Uses <b>getBBox</b> to determine scale reference point.
The previous hover size increase is reduced to its original size.
</div>
<table><tr>
<td>
<table>
<tr><td colspan=2><b>Animation Settings:</b></td></tr>
<tr><td>1. Smoothness</td><td>100 frames per second</td></tr>
<tr><td>2. Duration</td><td>200 - runtime in ms</td></tr>
<tr><td>3. Range</td><td> increase scale .5</td></tr>
<tr><td>4. Output Equation</td><td><span style=color:blue>function</span> quad(p){return Math.pow(p, 2)}</td></tr>
<tr><td>6. Application Output </td><td>element transform</td></tr>
</table><br />
<i>There are 2 hover functions: <b>hoverOverG(evt)</b> for &lt;g&gt; elements,<br />and <b>hoverOverE(evt)</b> for individual elements.</i>
</td>
<td>
<div id="svgDiv" style='background-color:lightgreen;'>
<svg version="1.1" id="mySVG" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400" overflow="hidden" >
<g id="CircleStar1" onmouseover="hoverOverG(evt)"   transform="translate(100 100)" ><polygon fill="crimson" stroke="none" points="15,-1.37091e-006 14.2658,-4.63527 12.1353,-8.81679 8.81679,-12.1353 4.63524,-14.2659 -1.37091e-006,-15 -4.63527,-14.2659 -8.81679,-12.1353 -12.1353,-8.81679 -14.2659,-4.63527 -15,-1.37091e-006 -14.2659,4.63524 -12.1353,8.81679 -8.81679,12.1353 -4.63527,14.2658 -1.37091e-006,15 4.63524,14.2658 8.81679,12.1353 12.1353,8.81679 14.2658,4.63524" /><polygon fill="dodgerblue" stroke="none" points="6.2319,3.59799 14.392,-1.37091e-006 6.2319,-3.59799 7.19598,-12.4638 -1.37091e-006,-7.19598 -7.19598,-12.4638 -6.2319,-3.59799 -14.392,-1.37091e-006 -6.2319,3.59799 -7.19598,12.4638 -1.37091e-006,7.19598 7.19598,12.4638" /></g>
<g id="CircleStar2" onmouseover="hoverOverG(evt)"   transform="translate(200 200)" ><polygon fill="crimson" stroke="none" points="15,-1.37091e-006 14.2658,-4.63527 12.1353,-8.81679 8.81679,-12.1353 4.63524,-14.2659 -1.37091e-006,-15 -4.63527,-14.2659 -8.81679,-12.1353 -12.1353,-8.81679 -14.2659,-4.63527 -15,-1.37091e-006 -14.2659,4.63524 -12.1353,8.81679 -8.81679,12.1353 -4.63527,14.2658 -1.37091e-006,15 4.63524,14.2658 8.81679,12.1353 12.1353,8.81679 14.2658,4.63524" /><polygon fill="dodgerblue" stroke="none" points="6.2319,3.59799 14.392,-1.37091e-006 6.2319,-3.59799 7.19598,-12.4638 -1.37091e-006,-7.19598 -7.19598,-12.4638 -6.2319,-3.59799 -14.392,-1.37091e-006 -6.2319,3.59799 -7.19598,12.4638 -1.37091e-006,7.19598 7.19598,12.4638" /></g>
<g id="CircleStar3" onmouseover="hoverOverG(evt)"   transform="translate(300 300)" ><polygon fill="crimson" stroke="none" points="15,-1.37091e-006 14.2658,-4.63527 12.1353,-8.81679 8.81679,-12.1353 4.63524,-14.2659 -1.37091e-006,-15 -4.63527,-14.2659 -8.81679,-12.1353 -12.1353,-8.81679 -14.2659,-4.63527 -15,-1.37091e-006 -14.2659,4.63524 -12.1353,8.81679 -8.81679,12.1353 -4.63527,14.2658 -1.37091e-006,15 4.63524,14.2658 8.81679,12.1353 12.1353,8.81679 14.2658,4.63524" /><polygon fill="dodgerblue" stroke="none" points="6.2319,3.59799 14.392,-1.37091e-006 6.2319,-3.59799 7.19598,-12.4638 -1.37091e-006,-7.19598 -7.19598,-12.4638 -6.2319,-3.59799 -14.392,-1.37091e-006 -6.2319,3.59799 -7.19598,12.4638 -1.37091e-006,7.19598 7.19598,12.4638" /></g>
<g id=rectEllipse transform="translate(330 20)scale(.5)" onmouseover="hoverOverG(evt)">
<rect x=50 y=200 width=60 height=50 fill=orange />
<ellipse cx=80 cy=227 rx=25 ry=15 fill=blue />
</g>
<g id=rectEllipseTransform transform="translate(130 120)scale(.5)" onmouseover="hoverOverG(evt)">
<rect x=50 y=200 width=60 height=50 fill=orange />
<ellipse cx=80 cy=227 rx=25 ry=15 fill=blue />
</g>
<g id=hoverElements >
<circle onmouseover="hoverOverE(evt)" cx=250 cy=150 r=10 fill=blue />
<circle onmouseover="hoverOverE(evt)" cx=150 cy=150 r=10 fill=blue />
<circle onmouseover="hoverOverE(evt)" cx=350 cy=350 r=10 fill=blue />
<circle transform="translate(110 40)" onmouseover="hoverOverE(evt)" cx=150 cy=150 r=10 fill=maroon />
<circle transform="translate(220 80)" onmouseover="hoverOverE(evt)" cx=150 cy=150 r=10 fill=maroon />
<circle transform="translate(220 80)" onmouseover="hoverOverE(evt)" cx=-10 cy=-10 r=10 fill=red />
<circle transform="translate(80 320)scale(.8)" onmouseover="hoverOverE(evt)" cx=-10 cy=-10 r=10 fill=red />
</g>
</svg>
</div>

</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:5px;position:absolute;top:5px;left:5px;background-color:gainsboro;'>OK in:IE11/CH32/FF23<br /></div>
<script id=myScript>
/*---generalized animate core function
Allows progress/output to follow a specific/customized equation(delta)
Inspired by: Ilya Kantor - http://javascript.info/tutorial/animation
*/
var AnimateJS=function(options){
    this.options=options
    var start = new Date
    var iT = setInterval(
    function(){
        var timePassed = new Date - start
        var progress = timePassed / options.duration
        if (progress > 1) progress = 1
        this.progress=progress
        var delta = options.delta(progress)
        options.output(delta)
        if (progress == 1)clearInterval(iT);
    },options.delay)
}
/*
provide options:
1) range(end value)
2) frames per second(delay = 1000/frames per second)
3) duration in ms
4) delta: equation(linear,etc.)
5) output:  This application's output function
*/
var HoverSizeIncrease=.5 //---the element's size increased by 50%--
var FinishedOver=true
var StartTrans=null
var PrevTarget=null
//--onmouseover g symbol---
function hoverOverG(evt)
{
    if(FinishedOver==true && (evt.target.parentNode!=PrevTarget)) //--allows initial run---
    {
        if(PrevTarget)
            extractHover(PrevTarget)
        var target=evt.target.parentNode
        PrevTarget=target
        FinishedOver=false
        var scaleBegin=1
        var range=HoverSizeIncrease //---scale increase
        var FPS=100  //---frames per second---
        var duration=200 //---ms,.2 seconds---
        //---quadratic formula in nth degree---
        var delta=function quad(p){return Math.pow(p,2)}
        if(target.getAttribute("transform"))
        {
            StartTrans=target.getAttribute("transform")
            var myTrans=StartTrans
        }
        else
        {
            StartTrans=null
            var myTrans=""
        }
        var bb=target.getBBox()
        var bbx=bb.x
        var bby=bb.y
        var bbw=bb.width
        var bbh=bb.height
        var cx=bbx+.5*bbw
        var cy=bby+.5*bbh
        //----core animation function---
        new AnimateJS(
        {
            delay: 1000/FPS,
            duration: duration,
            delta: delta, //---quadratic---
            output: function(delta)
            {
                var scale=scaleBegin+delta*range
                target.setAttribute("transform",myTrans+"translate("+(cx)+" "+(cy)+")scale("+scale+")translate("+(-cx)+" "+(-cy)+")")
                //---finished---
                if(progress==1)
                    onFinish()
            }
        })
    }
}
//--onmouseover element---
function hoverOverE(evt)
{
    if(FinishedOver==true && (evt.target!=PrevTarget)) //--allows initial run---
    {
        if(PrevTarget)
            extractHover(PrevTarget)
        var target=evt.target
        PrevTarget=target
        FinishedOver=false
        var scaleBegin=1
        var range=HoverSizeIncrease //---scale increase
        var FPS=100  //---frames per second---
        var duration=200 //---ms,.2 seconds---
        //---quadratic formula in nth degree---
        var delta=function quad(p){return Math.pow(p,2)}
        if(target.getAttribute("transform"))
        {
            StartTrans=target.getAttribute("transform")
            var myTrans=StartTrans
        }
        else
        {
            StartTrans=null
            var myTrans=""
        }

        var bb=target.getBBox()
        var bbx=bb.x
        var bby=bb.y
        var bbw=bb.width
        var bbh=bb.height
        var cx=bbx+.5*bbw
        var cy=bby+.5*bbh
        //----core animation function---
        new AnimateJS(
        {
            delay: 1000/FPS,
            duration: duration,
            delta: delta, //---quadratic---
            output: function(delta)
            {
                var scale=scaleBegin+delta*range
                target.setAttribute("transform",myTrans+"translate("+(cx)+" "+(cy)+")scale("+scale+")translate("+(-cx)+" "+(-cy)+")")
                //---finished---
                if(progress==1)
                    onFinish()
            }
        })
    }
}
var FinishedExtract=true
var ExtractTarget
var ExtractTrans
function extractHover(PrevTarget)
{
    if(FinishedExtract==true) //--allows initial run---
    {
        ExtractTarget=PrevTarget
        if(StartTrans)
            ExtractTrans=StartTrans
        else
            ExtractTrans=""
        FinishedExtract=false
        var scaleBegin=1+HoverSizeIncrease
        var range=HoverSizeIncrease //---scale decrease
        var FPS=100  //---frames per second---
        var duration=200 //---ms,.2 seconds---
        //---quadratic formula in nth degree---
        var delta=function quad(p){return Math.pow(p,2)}
        var bb=ExtractTarget.getBBox()
        var bbx=bb.x
        var bby=bb.y
        var bbw=bb.width
        var bbh=bb.height
        var cx=bbx+.5*bbw
        var cy=bby+.5*bbh

        //----core animation function---
        new AnimateJS(
        {
            delay: 1000/FPS,
            duration: duration,
            delta: delta, //---quadratic---
            output: function(delta)
            {
                var scale=scaleBegin-delta*range
                ExtractTarget.setAttribute("transform",ExtractTrans+"translate("+(cx)+" "+(cy)+")scale("+scale+")translate("+(-cx)+" "+(-cy)+")")

                    if (progress == 1) // --- finished---
                        extractFinish();
            }
        })
    }
}

//---this example animation: loop finished---
function onFinish()
{
    FinishedOver=true

}

//---this example animation: loop finished---
function extractFinish()
{
    FinishedExtract=true
    if(ExtractTrans!="")
        ExtractTarget.setAttribute("transform",ExtractTrans)
    else
        ExtractTarget.removeAttribute("transform")
}


</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
    jsValue.value=myScript.text
    svgSourceValue.value=svgDiv.innerHTML
}

</script>

</body>

</html>

嘗試使用非常簡單的方法。 我沒有應用任何動畫。 我想你會弄清楚如何做到這一點。

從內聯中刪除鼠標事件

JS

$('svg')
  .mouseenter(function(ev) {
       console.log($(this).find('circle').attr('r',40));
  })
  .mouseleave(function(ev) {
      console.log($(this).find('circle').attr('r',25));

});

檢查JSFiddle

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM