Pointing SVG with multiple elements

I have two svg elements on which I applied the mouseover/ event mouseout. The goal is to increase the radius of the mask by mouseoverup to the size specified by the variable ( maxMaskRadius) and decreaseby mouseout, in the initial state ( initialMaskRadius).

I work perfectly with one element. But when I have two elements and hover over one element to another, the animation from the previous elements is interrupted immediately. But I would like him to come to life in its original state. With my current code, which, unfortunately, is not possible.

Any suggestions on how to do this?

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);
}
+4
3

, , . , , , , .

:

  • CSS: .
  • HTML: (onmouseover onmouseout)

  • JavaScript:

    • , svg dday : svg, index ( ), , rect a svg.
    • settings
    • svg {svgElement}.svgData.

: jsFiddle

P.S. , , , .

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

+4

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 output function
*/
var HoverSizeIncrease=.5 //---the element 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>
0

Try to do this using a very simple way. I did not apply animation. I think you will understand how to do this.

Remove mouse event from inline

Js

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

});

CHECK JSFiddle

0
source

Source: https://habr.com/ru/post/1535548/


All Articles