javascript - SVG hover with multiple elements -
i've 2 svg elements on i've applied mouseover
/mouseout
event. goal increase radius of mask on mouseover
size specified variable (maxmaskradius
) , decrease
on mouseout
initial state (initialmaskradius
).
i works 1 element. when i've 2 elements , hover 1 element another, animation previous elements aborts immediately. i'd have animate initial state. current code that's unfortunately not possible.
any suggestions on how proper?
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 current element svg = $(el).closest('.dday'), svgwidth = svg.width(), svgheight = svg.height(), mask = svg.find('circle')[0]; // on page load there index provided load images each element if(typeof index !== 'undefined'){ loadimage(index); } } function loadimage(index) { // load images , scale them fit 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 , init animation definecurrentelement(ev.target); mouseevent = ev.type; requestanimationframe(animate); } function animate() { if(mouseevent == 'mouseover') { // increase mask radius on mouseover , repeat until target state 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 , repeat until initial state 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, fixed code, , not easy task work code. please declare variables use, , not use in function global variables own private variables, because can re-write existing global variable.
now fixed code:
- css: no changes.
html: removed inline handlers (
onmouseover
,onmouseout
)javascript:
- when document ready each
svg
element classdday
initializing: downloading imagesvg
if variableindex
exists (loading logic didn't changed almost), centering mask, declaring function animation, adding handlerrect
element ina
element in initializingsvg
element. - all settings has been exported variable
settings
- all private variables
svg
stored in{svgelement}.svgdata
object.
- when document ready each
demo: jsfiddle
p.s. way, code not enougt, need more time clean code, code works.
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: (used jquery 1.11 library)
$(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 index provided load images 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); }); } }); });
demo: jsfiddle
Comments
Post a Comment