On my highchart i need a delay before the series tooltip is displayed.
I defined a new refresh function with a timer to realize it. If the timer is ready i check if the mouse position. If it moved not that much the tooltip should appear.
function (H) {
var timer = [];
var mousePosition = {
x: 0,
y: 0
};
window.addEventListener("mousemove", function (event) {
mousePosition.x = event.pageX;
mousePosition.y = event.pageY;
});
var getMousePositionX = function () {
return mousePosition.x;
};
var clearTimer = function () {
timer = [];
}
H.wrap(H.Tooltip.prototype, 'refresh', function (proceed) {
var mousePosX = getMousePositionX();
var delayForDisplay = this.chart.options.tooltip.delayForDisplay ? this.chart.options.tooltip.delayForDisplay : 1000;
timer[timer.length+1] = window.setTimeout(function () {
var currMousePosX = getMousePositionX();
if ((mousePosX >= currMousePosX - 5 && mousePosX <= currMousePosX + 5)) {
this.proceed.apply(this.tooltip, this.refreshArguments);
clearTimer();
}
}.bind({
refreshArguments: Array.prototype.slice.call(arguments, 1),
chart: this.chart,
tooltip: this,
clearTimer: clearTimer,
proceed: proceed
}), delayForDisplay);
});
};
The problem I have is, that the hover holos have also a delay.
Here is a sample: JSFiddle
Any solutions for this issue?
You can make new tooltip basing on your standard Highcharts tooltip and show it on your mouseover with some timeout:
load: function() {
chart = this;
this.myTooltip = new Highcharts.Tooltip(this, this.options.tooltip);
this.tooltip.label.element.remove();
}
point: {
events: {
mouseOver: function(e) {
var i = this.x;
points = [];
Highcharts.each(this.series.chart.series, function(s) {
Highcharts.each(s.data, function(p) {
if (p.x === i) {
points.push(p)
}
})
});
myTooltip = chart.myTooltip;
setTimeout(function() {
myTooltip.refresh(points, e)
}, 1000)
}, mouseOut: function() {
setTimeout(function() {
chart.myTooltip.hide();
}, 1000)
}
}
}
Here you can see an example how it can work: http://jsfiddle.net/az39das8/
Related
I have recreated this index chart in Dash.
This is a gif of the chart in the link.
o
The data is dynamically updated by a callback that listens to the hoverData property of the dcc.Graph component when the user hovers the mouse over the graph.
I also added a callback that disables/enables the updates. Right now it is triggered by clicking on the graph area, that is, a change in the clickData property.
However, this doesn’t feel very intuitive to me.
I would like to enable the hover updates when the user holds the left mouse button down and drags the mouse, and disabling it when the mouse is released.
How can I implement this functionality?
Check out the following implementation, did not refer the api so there could be a better way to do it:
mousedown, mouseup, mousemove, SO answer for drag behavior
vis.add(pv.Panel)
.events("all")
.event("mousedown", function() {
isMousedown = true;
})
.event("mouseup", function() {
isMousedown = false;
})
.event("mousemove", function() {
if (isMousedown) {
idx = x.invert(vis.mouse().x) >> 0;
update();
}
});
var data = [],
fy = function(d) {
return d.price
}, // y-axis value
fx = function(d) {
return d.index
}, // x-axis value
ft = function() {
return data[this.parent.index].ticker
}, // label
w = 730,
h = 360,
S = pv.max(pv.values(stocks), function(s) {
return s.values.length
}),
idx = Math.floor(S / 2) - 1,
x = pv.Scale.linear(0, S - 1).range(0, w),
y = pv.Scale.linear(-1, 5).range(0, h),
rescale = true;
/* Normalize the data according to an index point. */
var indexify = function(data, cols, idx) {
return cols.map(function(c) {
var v = data[c].values[idx];
return {
ticker: c,
values: data[c].values.map(function(d, i) {
return {
index: i,
price: ((d - v) / v)
};
})
}
});
};
/* Compute new index values, rescale if needed, and render. */
var update = function() {
data = indexify(stocks, names, idx);
if (rescale) {
var min = pv.min(data.map(function(d) {
return pv.min(d.values, fy)
}));
var max = pv.max(data.map(function(d) {
return pv.max(d.values, fy)
}));
}
y.domain(min, max).nice();
vis.render();
}
/* The visualization panel. Stores the active index. */
var vis = new pv.Panel()
.def("i", -1)
.left(60)
.right(70)
.top(20.5)
.bottom(18)
.width(w)
.height(h);
/* Horizontal gridlines showing %-change. */
vis.add(pv.Rule)
.data(function() {
return y.ticks(8)
})
.bottom(y)
.strokeStyle(function(d) {
return d == 0 ? "black" : "#cccccc"
})
.anchor("left").add(pv.Label)
.text(function(d) {
return (d * 100).toFixed(0) + "%"
});
/* Y-axis label */
vis.add(pv.Label)
.data(["Gain / Loss Factor"])
.left(-45)
.bottom(h / 2)
.font("10pt Arial")
.textAlign("center")
.textAngle(-Math.PI / 2);
/* Stock lines. */
vis.add(pv.Panel)
.data(function() {
return data
})
.add(pv.Line)
.data(function(d) {
return d.values
})
.left(x.by(fx))
.bottom(y.by(fy))
.lineWidth(2)
.add(pv.Label)
.visible(function() {
return this.index == S - 1
})
.textBaseline("middle")
.textMargin(6)
.text(ft);
/* Current index line. */
vis.add(pv.Rule)
.visible(function() {
return idx >= 0 && idx != vis.i()
})
.left(function() {
return x(idx)
})
.top(-4)
.bottom(-4)
.strokeStyle("red")
.anchor("bottom").add(pv.Label)
.text(function() {
return stocks.Date.values[idx]
});
/* An invisible bar to capture events (without flickering). */
var isMousedown = false;
vis.add(pv.Panel)
.events("all")
.event("mousedown", function() {
isMousedown = true;
})
.event("mouseup", function() {
isMousedown = false;
})
.event("mousemove", function() {
if (isMousedown) {
idx = x.invert(vis.mouse().x) >> 0;
update();
}
});
update();
#fig {
width: 860px;
height: 400px;
}
<script src="https://mbostock.github.io/protovis/protovis-r3.2.js"></script>
<script src="https://mbostock.github.io/protovis/ex/stocks.js"></script>
<link href="https://mbostock.github.io/protovis/style.css" rel="stylesheet" />
<div id="fig">
I have a question about the topic.
I use stackover at the first time.
I use JS wookmark plugin. by the way I make web pages.
One of pages with sidebar with open and close.
When I close the left sidebar, It makes a space left of article.
Usually It resizes width on no space. The open sidebar size is 260px. The close size is 70.
I use these but no action.
$(document).ready(function() {
var article_list = $("#grid-container article").get();
var outer = $('<div class="grid-outer"></div>').get(0);
var nowbox = false;
for ( var i = 0; i < article_list.length; i++ ) {
if($(article_list[i]).hasClass('area')){
nowbox = false;
$(outer).append(article_list[i]);
}
if($(article_list[i]).hasClass('area-box')) {
if(!nowbox) {
nowbox = $('<div class="gridbox"></div>').get(0);
$(outer).append(nowbox);
}
$(nowbox).append(article_list[i]);
}
}
$("#grid-container").empty();
$("#grid-container").append(outer);
var options = {
offset: 20, // Optional, the distance between grid items
autoResize: true,
fillEmptySpace: true,
};
var resizeTimer = null;
var gridarr = [];
var gridboxlist = $('.gridbox').get();
for ( var i = 0; i < gridboxlist.length; i++ ) {
gridarr[i] = new Wookmark( gridboxlist[i], options);
}
resize();
resizeTimer = setTimeout(function() {
resize();
}, 0);
$(window).resize(function(){
clearTimeout(resizeTimer);
resize();
resizeTimer = setTimeout(function() {
resize();
}, 0);
})
function resize(){
var gridboxlist = $('.gridbox').get();
$(gridboxlist).each(function(){
var window_w = window.outerWidth;
var outer_w = $(this).width();
if( window_w < 1400) {
var w = Math.floor((( outer_w - ( 20 * 1 )) / 2));
$(this).find('.area-box').css({
'width': w+'px'
});
} else {
var w = Math.floor((( outer_w - ( 20 * 2 )) / 3));
$(this).find('.area-box').css({
'width': w+'px'
});
}
});
if( 0 < gridarr.length ){
refresh();
}
}
function refresh(){
for ( var i = 0; i < gridarr.length; i++ ) {
gridarr[i].layout(true);
}
}
});
I want to make a rectangular move by click on a button and stop it clicking on the same button. Here is a part of my code:
document.getElementById("startStop").addEventListener("click", changePlace);
function changePlace() {
nIntervMove = setInterval(movement, 100);
};
var tmp1 = 0;
function movement() {
var oElem = document.getElementById("colorRectangular");
oElem.getPropertyValue = tmp1;
tmp1 += "10px";
};
function stopMove(){
clearInterval(nIntervMove);
};
Pretty straight forward:
var makeMove = function(x, hx, t, complete) {
var target = document.getElementById('rect'),
dx = 0,
d = setInterval(function() {
target.style.left = dx + "px";
dx += hx;
if(dx >= x) {
clearInterval(d);
complete();
}
}, t);
};
makeMove(100, 5, 500, function() {
alert('done');
});
JSFiddle: http://jsfiddle.net/8ay9cqmd/
I am newbie. I can't sprite animation using jquery..
What's the problem?
How can make progressing the sprite animation on the spot loop as scroll??
$(window).scroll('scroll',function(e){
parallaxScroll();
});
function parallaxScroll() {
var ani_data = [0, -120, -240, -480];
var frame_index = 0;
if ( ScrollCount == 3 ) {
ScrollCount = 1;
$('#fatherwalk').css('background-position', ani_data[frame_index] + 'px 0px');
frame_index++;
if ( frame_index >= ani_data.length ) {
frame_index = 0;
}
}
scrollcount++;
}
Why you don't get a shortcut and try SpinJS?
http://fgnass.github.io/spin.js/
It's so easy to implement and works fine.
Here is a Sample that I've made on JSFiddle
Below a quick implementation of the JS:
$.fn.spin = function (opts) {
this.each(function () {
var $this = $(this),
spinner = $this.data('spinner');
if (spinner) spinner.stop();
if (opts !== false) {
opts = $.extend({
color: $this.css('color')
}, opts);
spinner = new Spinner(opts).spin(this);
$this.data('spinner', spinner);
}
});
return this;
};
$(function () {
$(".spinner-link").click(function (e) {
e.preventDefault();
$(this).hide();
var opts = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 5, // The line thickness
radius: 10, // The radius of the inner circle
color: '#fff', // #rbg or #rrggbb
speed: 1, // Rounds per second
trail: 66, // Afterglow percentage
shadow: true // Whether to render a shadow
};
$("#spin").show().spin(opts);
});
});
Hope this helps.
I'm using the following class along with Mootools to create custom scrolling areas on a site. It includes a mousewheel event. I need to be able to fire an onComplete once the scroller comes to a stop after using the mousewheel. So say you swipe the mousewheel to scroll, I need to fire an oncomplete once the scrolling content comes to a stop.
Suggestions?
var ScrollBar = new Class({
Implements: [Events, Options],
options: {
wheel: (Browser.safari5) ? 1 : 20
},
initialize: function(main, options) {
this.setOptions(options);
this.dragging = false;
this.inside = false;
this.main = $(main);
this.content = this.main.getFirst();
this.vScrollbar = new Element('div', {
'class': 'scrollbar'
}).inject(this.content, 'after');
this.vTrack = new Element('div', {
'class': 'track'
}).inject(this.vScrollbar);
this.vThumb = new Element('div', {
'class': 'handle'
}).inject(this.vTrack);
this.bound = {
'vStart': this.vStart.bind(this),
'end': this.end.bind(this),
'vDrag': this.vDrag.bind(this),
'wheel': this.wheel.bind(this),
'vPage': this.vPage.bind(this)
};
// set scrollarea mousein/out hide of scrollbar
this.vScrollbar.set('tween', {
duration: 200,
transition: 'cubic:out'
});
this.main.addEvent('mouseenter', function(event){
this.inside = true;
this.vScrollbar.get('tween').cancel();
this.vScrollbar.tween('width', 12);
}.bind(this));
this.main.addEvent('mouseleave', function(event){
this.inside = false;
if (!this.dragging) {
this.vScrollbar.get('tween').cancel();
this.vScrollbar.tween('width', 0);
}
}.bind(this));
this.vPosition = {};
this.vMouse = {};
this.update();
this.attach();
this.scrollContent = new Fx.Scroll(this.content, {
duration: 500,
transition: Fx.Transitions.Cubic.easeOut,
onComplete: function(){
Blinds.updateImages();
}
});
this.scrollThumb = new Fx.Morph(this.vThumb, {
duration: 500,
transition: Fx.Transitions.Cubic.easeOut
});
},
update: function() {
var panel_id = (this.content.getFirst()) ? this.content.getFirst().get('id') : '';
if ((this.content.scrollHeight <= this.main.offsetHeight) || panel_id === 'random-doodle' || (this.content.getFirst() && this.content.getFirst().hasClass('collapsed'))) {
this.main.addClass('noscroll');
return false;
}
else { this.main.removeClass('noscroll'); }
this.vContentSize = this.content.offsetHeight;
this.vContentScrollSize = this.content.scrollHeight;
this.vTrackSize = this.vTrack.offsetHeight;
this.vContentRatio = this.vContentSize / this.vContentScrollSize;
this.vThumbSize = 200;
this.vThumb.setStyle('height', this.vThumbSize);
this.vScrollRatio = this.vContentScrollSize / (this.vTrackSize - this.vThumbSize) - this.vContentRatio * (this.vContentScrollSize / (this.vTrackSize - this.vThumbSize));
this.vUpdateThumbFromContentScroll();
this.vUpdateContentFromThumbPosition();
},
vUpdateContentFromThumbPosition: function() {
this.content.scrollTop = this.vPosition.now * this.vScrollRatio;
},
vUpdateContentFromThumbPosition2: function() {
var pos = this.vPosition.now * this.vScrollRatio;
this.scrollContent.start(0, pos);
},
vUpdateThumbFromContentScroll: function() {
this.vPosition.now = (this.content.scrollTop / this.vScrollRatio).limit(0, (this.vTrackSize - this.vThumbSize));
this.vThumb.setStyle('top', this.vPosition.now);
},
vUpdateThumbFromContentScroll2: function(pos) {
this.vPosition.now = (this.content.scrollTopNew / this.vScrollRatio).limit(0, (this.vTrackSize - this.vThumbSize));
this.scrollThumb.start({
'top': this.vPosition.now
});
},
attach: function() {
if (this.options.wheel) { this.content.addEvent('mousewheel', this.bound.wheel); }
this.vThumb.addEvent('mousedown', this.bound.vStart);
this.vTrack.addEvent('mouseup', this.bound.vPage);
},
wheel: function(event) {
this.content.scrollTop -= event.wheel * this.options.wheel;
this.vUpdateThumbFromContentScroll();
event.stop();
},
scrollTo: function(pos){
myInstance = this;
this.content.scrollTopNew = pos;
this.scrollContent.start(0, this.content.scrollTopNew);
myInstance.vUpdateThumbFromContentScroll2(pos);
},
vPage: function(event) {
// if scrolling up
if (event.page.y > this.vThumb.getPosition().y) {
myInstance = this;
this.content.scrollTopNew = this.content.scrollTop.toInt() + this.content.offsetHeight.toInt();
this.scrollContent.start(0, this.content.scrollTopNew);
}
// if scrolling down
else {
myInstance = this;
this.content.scrollTopNew = this.content.scrollTop.toInt() - this.content.offsetHeight.toInt();
this.scrollContent.start(0, this.content.scrollTopNew);
}
myInstance.vUpdateThumbFromContentScroll2(event.page.y);
event.stop();
},
vStart: function(event) {
this.dragging = true;
this.vMouse.start = event.page.y;
this.vPosition.start = this.vThumb.getStyle('top').toInt();
document.addEvent('mousemove', this.bound.vDrag);
document.addEvent('mouseup', this.bound.end);
this.vThumb.addEvent('mouseup', this.bound.end);
event.stop();
},
end: function(event) {
this.dragging = false;
if (!this.inside) {
this.vScrollbar.get('tween').cancel();
this.vScrollbar.tween('width', 0);
}
document.removeEvent('mousemove', this.bound.vDrag);
document.removeEvent('mouseup', this.bound.end);
this.vThumb.removeEvent('mouseup', this.bound.end);
Blinds.updateImages();
event.stop();
},
vDrag: function(event) {
this.vMouse.now = event.page.y;
this.vPosition.now = (this.vPosition.start + (this.vMouse.now - this.vMouse.start)).limit(0, (this.vTrackSize - this.vThumbSize));
this.vUpdateContentFromThumbPosition();
this.vUpdateThumbFromContentScroll();
event.stop();
}
});
You could modify your wheel function to reset a delayed function timer (after clearing any previous timers that might still exist). To have the 'autoComplete' fired 1000ms after the last wheel event, try something like this:
wheel: function(event) {
this.content.scrollTop -= event.wheel * this.options.wheel;
this.vUpdateThumbFromContentScroll();
// clear the timer from previous wheel events, if it still exists
if(this.timer) {
clearTimeout(timer);
}
this.timer = function() {this.fireEvent('autoComplete');}.delay(1000, this);
event.stop();
},