Making Materialize CSS Tooltips stay when hovering over them - html

A piece I'm currently working on is calling for tooltips that display when you hover over part of an SVG element, disappear as normal on mouse-out but providing the mouse does not go over the tooltip itself. We are using Materialize CSS which does come with a tooltip component.
A segment of my code is below.
<svg width="400" height="400">
<rect x="190" y="255" width="70" height="25" class="fixture good tooltipped" id="ines" data-position="top" data-delay="50" data-tooltip="Carbonated Drinks<br><a href='#'>View More</a>"" data-html="true"/>
</svg>
As you can see, the reason I want this is so that the user can click the 'View more' link if they mouse onto the actual tooltip. Currently, however, the tooltips disappear even if you mouse onto them.
I know this can be done with other frameworks/libararies, but I have been unable to do this in Materialize CSS so far.
Does anyone know if this is possible as an extensive internet search has turned up nothing.

Materialize tooltip assign a "mouseleave.tooltip" event handler for each involved dom node.
This event is triggered as soon as you will leave the dom element, and after 225 milliseconds (for details refer to source code) the tootip will be hidden.
Moreover, the tooltip has the style pointer-events equal to none: no mouse event can be triggered, so your anchor will be never clickable.
In order to overcome all these steps a possibility is:
save the jQuery mouseout event object
remove the previous object from the jQuery handlers so no mouseleave.tooltip can be triggered.
handle the jQuery hover event for each tooltip (having class: material-tooltip): this to save a property in order to test against the mouse position in or out the tooltip
on mouseenter for your element set the pointer-events to default auto
in the same way on mouseleave set a timeout less than 225 milliseconds in order to test if the mouse is over the tooltip: if not execute the standard jQuery materialize mouseleave.tooltip event
on mouseleave the tooltip do the same step in the previous point.
The snippet (jsfiddle):
$(function () {
var x = jQuery._data( document.getElementById('ines'), "events" )['mouseout'][0];
delete jQuery._data( document.getElementById('ines'), "events" )['mouseout'];
$('.material-tooltip').hover(function(e) {
$(this).attr('hover', 1);
}, function(e) {
$(this).attr('hover', 0);
x.handler.apply( document.getElementById('ines'), x);
});
$('#ines').on('mouseenter', function(e) {
$('.material-tooltip:visible').css('pointer-events', 'auto');
}).on('mouseleave', function(e) {
setTimeout(function() {
var val = $('.material-tooltip:visible').attr('hover');
if (val == undefined || val == 0) {
x.handler.apply( document.getElementById('ines'), x);
}
}, 150);
})
});
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/js/materialize.min.js"></script>
<svg width="400" height="400">
<rect x="190" y="155" width="70" height="25" class="fixture good tooltipped" id="ines" data-position="top"
data-delay="50" data-tooltip="Carbonated Drinks<br><a href='#'>View More</a>"
data-html="true"/>
</svg>

Related

AngularJS ng-href and svg xlink

I'd like some input on using xml namespaced attributes with angular.
The problem is angular comes with a couple of directives to handle writing attributes such as href and src when angular has parsed the expresssions (otherwise the browser will try to load {{mymodel.myimage}} as a url)
https://github.com/angular/angular.js/blob/master/src/ng/directive/booleanAttrs.js#L329
The problem I'm facing is that I'm using angular to output svg together with D3 and since angular doesn't have a way to output xlink:href I was stuck.
I created a custom directive that outputs xlink:href
app.directive('ngXlinkHref', function () {
return {
priority: 99,
restrict: 'A',
link: function (scope, element, attr) {
var attrName = 'xlink:href';
attr.$observe('ngXlinkHref', function (value) {
if (!value)
return;
attr.$set(attrName, value);
});
}
};
});
Full demo: http://plnkr.co/edit/cMhGRh
But it seems that if I don't manually add xlink:href to the element, the svg image will not render.
Any suggestions on how to best handle xml namespaces / svg together with angular would be greatly appreciated.
You can use ng-attr-<some attribute>
ng-attr-xlink:href="{{xxx}}" works for me.
Note that you also need an empty xlink:href="" as initial value. – Derek Hsu
If, like me, you're looking for a way to add images to svg, you can do so adding:
xlink:href="" ng-href="{{ foo }}"
Example:
http://jsbin.com/sigoleya/1/edit?html,js,output
Where I found the solution:
https://github.com/angular/angular.js/issues/7697
I ran into a similar problem when trying to output a value for xlink:href that's tied to the model. Based on the user's chosen <option> in a <select> control, I was trying to show a dynamic SVG icon via the xlink:href attribute of the <use> element.
I found a thread about this in the GitHub Issues for AngularJS. Based on the discussion there, it appears that because a viable workaround exists, they've effectively tabled a fix by moving it to the Backlog milestone.
What ultimately worked for me was inspired by this JSBin:
http://jsbin.com/sigoleya/1/edit?html,js,output
Here's the code I used in my template:
<svg class="icon" data-ng-class="category.iconName">
<use xlink:href="" data-ng-href="{{'#' + category.iconName}}">
</svg>
Given a category.iconName of icon-music, for example, Angular sets the xlink:href dynamically to #icon-music, which references the <svg id="icon-music"> element further up on the same page.
As others have noted, what's key is setting a blank xlink:href="" attribute on the element where you call the ngHref directive. Attribute order does not seem to matter. Using ng-attr-xlink:href="{{xxx}}" (as mentioned in Derek Hsu's answer) did not work for me.
All of this assumes Angular 1.3.36.
I solved the same problem with the following modules:
Module for SVGs:
var app = angular.module('Svgs', []);
angular.forEach([
{ ngAttrName: 'ngXlinkHref', attrName: 'xlink:href' },
{ ngAttrName: 'ngWidth', attrName: 'width' },
{ ngAttrName: 'ngHeight', attrName: 'height' }
], function (pair) {
var ngAttrName = pair.ngAttrName;
var attrName = pair.attrName;
app.directive(ngAttrName, function (IeHelperSrv) {
return {
priority: 99,
link: function (scope, element, attrs) {
attrs.$observe(ngAttrName, function (value) {
if (!value) return;
attrs.$set(attrName, value);
if (IeHelperSrv.isIE) element.prop(attrName, value);
});
}
};
});
});
Module for IE detection:
angular.module('IeHelper', []).factory('IeHelperSrv', function () {
return {
isIE: checkForIE.isIE,
}
});
var checkForIE = {
init: function () {
this.isIE = (navigator.userAgent.indexOf('MSIE') != -1);
}
};
checkForIE.init();
HTML:
<!-- image has initial fake source, width and height to force it to render -->
<image xlink:href="~/Content/Empty.png" width="1" height="1"
ng-xlink-href="{{item.imageSrc}}"
ng-width="{{item.width}}" ng-height="{{item.height}}"
ng-cloak
/>
For anyone else having this problem due to Angular/Angular UI Router in HTML5 mode, I came up with a straightforward fix to enable svg sprite icons to work with their xlink:href attribute and the tag.
Gist is here: https://gist.github.com/planetflash/4d9d66e924aae95f7618c03f2aabd4a3
app.run(['$rootScope', '$window', function($rootScope, $window){
$rootScope.$on('$locationChangeSuccess', function(event){
$rootScope.absurl = $window.location.href;
});
<svg><use xlink:href="{{absurl+'#svgvID'}}"></use></svg>
I ran into this problem where I was using Ajax to load the svg spritesheet onto the page. If I had a on the page before the spritesheet was loaded, it would fail and would not resolve once the spritesheet was avaialble. Any added to the dom after the spritesheet was loaded were fine. I had to delay putting the items in the dom until after the spritesheet finished loading.
This only affected IOS. All other browsers didn't care about the order.
This took me more time than I would've wanted. Around 20-30 minutes.
If I understand correctly, any failed loading on image element will render that element useless in the future. I believe it's something similiar #GeekyMonkey is saying. If angular binding system has set xlink:href initially to null, Image element wont work anymore, even if we have valid value in the future.
Here is solution, notice how I have wrapped image element inside g element, using ng-if directive. That makes sure we will bind against image only when a correct value is available.
<g ng-if="vm.svgMap.background != null">
<image
ng-attr-xlink:href="{{vm.svgMap.background.image | trusted}}"
ng-attr-width="{{vm.svgMap.background.width}}"
ng-attr-height="{{vm.svgMap.background.width}}"
xlink:href=""
width="1"
height="1"
x="0"
y="0"></image>
</g>
As others said, the order of attributes are important as well. To ensure that angularJS allows us to bind image element, we'll also have to trust that resource, I've done it through filter (it's the one in xlink:href attribute):
(function() {
'use strict';
angular.module('myTool').filter('trusted', TrustedFilter);
function TrustedFilter($sce) {
return function(url) {
return $sce.trustAsResourceUrl(url);
};
};
}());

SVG mousemove events stop firing in Firefox after a few mousedowns

I am writing an HTML5 app using primarily SVG content, within an HTML page. One of the tasks I need to do is move objects around on the canvas. I find that, in Firefox, the first press-drag-release operation works as expected, but very soon the code stops receiving mousemove events after a mousedown. Instead, I see the "ghostbusters" cursor, as if Firefox thinks I am trying to do a Drag-and-Drop operation. I can eventually restore mousemove after mousedown events for one or two cycles by clicking around the green rectangle, but then the problem recurs. I have even set draggable="false" as seen in the simple test case below, to make sure DnD is disabled. (All of the content was copied from one file, though it looks like it is getting separated here.)
This test case works fine in IE9, Chrome, Opera, and Safari.
A similar "pure" SVG page works in Firefox as well as the other browsers.
I am using Firefox 15.0.1 on a Windows 7 client, serving the page up from a Linux box.
Is there something I am missing? Or is this perhaps a Firefox bug?
<!DOCTYPE HTML5>
<title>Test Mouse Events</title>
<script>
function mouseDown(evt)
{
document.getElementById("udText").textContent = "mousedown at "+evt.clientX+","+evt.clientY;
}
function mouseMove(evt)
{
document.getElementById("moveText").textContent = "mousemove at "+evt.clientX+","+evt.clientY;
}
function mouseUp(evt)
{
document.getElementById("udText").textContent = "mouseup at "+evt.clientX+","+evt.clientY;
}
function init()
{
document.getElementById("field").addEventListener("mousedown", mouseDown, false);
document.getElementById("field").addEventListener("mouseup", mouseUp, false);
document.getElementById("field").addEventListener("mousemove", mouseMove, false);
}
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events"
id="canvas"
width="800"
height="600"
version="1.1"
baseProfile="full"
onload="init()"
>
<rect id="field" x="50" y="50" width="700" height="500" fill="#20c000" draggable="false"/>
<text id="udText" x="80" y="520" font-size="30" fill="#000000">No up or down events yet</text>
<text id="moveText" x="420" y="520" font-size="30" fill="#000000">No move events yet</text>
</svg>
You should call evt.preventDefault(); in all the mouseXXX handlers. Firefox has default drag/drop handling and you don't want that. It's not a bug in Firefox that it does that.
These changes fix it for me:
function mouseDown(evt)
{
evt.preventDefault();
document.getElementById("udText").textContent = "mousedown at "+evt.clientX+","+evt.clientY;
}
function mouseMove(evt)
{
evt.preventDefault();
document.getElementById("moveText").textContent = "mousemove at "+evt.clientX+","+evt.clientY;
}
function mouseUp(evt)
{
evt.preventDefault();
document.getElementById("udText").textContent = "mouseup at "+evt.clientX+","+evt.clientY;
}

Making an added element draggable

I am working with an icon which is clickable and once you clicked it. It will add another icon in the div i want to set the created icon to be draggable and from the inspect element it is draggable yet I can't drag it on my screen. Can someone check what seems to be the problem?
HTML:
<div id = icon>
<img class="icon" src="../../Pictures/bulb.png" width="50" height="50"/>
<img class="icon" src="../../Pictures/snow.png" width="50" height="50"/>
</div>
Jscript
$(function () {
$('.icon').click(function () { DrawImage($(this).attr('src')); });
});
function DrawImage(a) {
image = document.createElement('img');
image.setAttribute('class', 'drag');
image.setAttribute('src', a);
image.setAttribute('draggable', 'true');
image.setAttribute('style', 'position:relative; top:0px; left:0px;');
image.height = 50;
image.width = 50;
$('#icon').append(image);
}
added this on my html head
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery.min.js")"></script>
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery-ui-1.8.11.js")"></script>
update:
fixed it by cloning the image element and assigning some attribute to it
var iconnew = $(iconimg).clone();
iconnew.attr({ "id": "clone"});
iconnew.css({'top':mouseY, 'left':mouseX})
iconnew.appendTo('#drag').draggable({ containment: '#bg' });
I don't think you are actually enabling the draggable functionality on your image element when you append it to the DOM. You could try changing your DrawImage function to this:
http://jsfiddle.net/qDZsb/

onmouseover and canvas, not continuous

I'd like to display continuously updating coordinates when the mouse is over a canvas.
The below Firefox-tested code should produce this, but onmouseover is only called when the mouse enters the canvas. When over it, nothing happens and the coordinates are not updated.
<HTML>
<BODY>
<Canvas width="200" height="200" onmouseover="myMouse(event)">No support</Canvas>
<P id="text"/>
<Script>
function myMouse(event) {
document.getElementById("text").innerHTML = "Position = " + event.clientX + ", " + event.clientY;
}
</Script>
</BODY>
</HTML>
What can I do to have onmouseover be continuous, and not only update when the mouse enters the canvas?
On the web, the closest subject I've found was this, but they did not answer the question on making this work ... I must be missing something.
Instead of onmouseover try onmousemove.
The onmouseover event fires when the mouse moves over an element once. The onmousemove event fires whenever the mouse is being moved.
jsFiddle example.
https://developer.mozilla.org/en/DOM/element.onmousemove

zoomin/zoomout of an image in html5

i have simple application which should work on keyboard events like onfocus and onblur instead of onmouseover and onmouseout.
here is my code snippet to zoomin/zoomout:
<script>
var nW,nH,oH,oW;
function zoom(iWideSmall,iHighSmall,iWideLarge,iHighLarge,whichImage)
{
oW=whichImage.style.width;oH=whichImage.style.height;
if((oW==iWideLarge)||(oH==iHighLarge))
{
nW=iWideSmall;nH=iHighSmall;
}
else
{
nW=iWideLarge;nH=iHighLarge;
}
whichImage.style.width=nW;whichImage.style.height=nH;
}
</script>
calling this function in this way:
<td align=center valign=middle >
<figure>
<button style="background-color:black; height:160px;width:160px ; border:none"><img src="F:\rashmi\icons_tv\Help_Normal.png" onfocus="zoom('57px','120px','96px','136px',this);"
onblur="zoom('57px','120px','57px','120px',this);" > </button>
<figcaption><font size="5" color="white" style="font-weight:bold"><center>help</center></font></figcaption>
</figure>
</td>
but problem is when i select image using tab key i cant see any zoomin/zoomout effect. if i replace onfocus/onblur with onmouseover/onmouseout respectively it works well.
please some one help me where i am going wrong.
regards
rashmi
You will not get focus on an img element by tabbing but on the button element instead. Move your onblur/onfocus events to the button element. This will change your button's size each time you focus/lose focus on it, but it will not change your image size. What you have to do then is to modify your code so the change is mapped on the button's contained image dimensions as well. Something that I can think of right now is
<script type="text/javascript">
var nW,nH,oH,oW;
function zoom(iWideSmall,iHighSmall,iWideLarge,iHighLarge,whichElement)
{
theImage = whichElement.firstChild;
theImage.style.width=nW;theImage.style.height=nH;
oW=whichElement.style.width;oH=whichElement.style.height;
if((oW==iWideLarge)||(oH==iHighLarge))
{
nW=iWideSmall;nH=iHighSmall;
}
else
{
nW=iWideLarge;nH=iHighLarge;
}
whichElement.style.width=nW;whichElement.style.height=nH;
theImage.style.width=nW;theImage.style.height=hH;
}
</script>
Here, the first child of the button element, which happens to be the image, takes the same height and width with the button, whenever that changes.