jQueryUI Auto Scroll on Drag - jquery-ui

http://jsfiddle.net/ujty083a/4/
$(document).ready(function(){
$(".left ul li").draggable({
refreshPosition: true,
revert: true
});
$(".right li").droppable({
drop: function(e, ui){
alert(ui.draggable.text()+" "+$(this).text());
}
});
});
I have three lists one you can drag and the other two accept drop. The right lists may or may not have a scroll bar but there will always be 2 or more.
The first problem I've found is when the top list has a scrollbar and you try to drop an item on the second list two events are triggered. One for the hidden list and one for the visible list.
The second problem is the when one of the lists has a scrollbar it does not auto scroll when the user drags an item into it.

I think you'll need to modify droppable and modify substantially some of the behaviors this way:
You'll need to add an option to define if the droppable should be
scrollable or not.
Then you'll need some kind of validation as to which droppable
are visible or not.
And you'll need to tweak the scroll behavior that are already in some
of jquery ui widgets.
This is not perfect but should give you some ideas:
$.widget('ui.droppable', $.ui.droppable, {
_over: function (e, ui) {
var draggable = $.ui.ddmanager.current;
if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
// this to make sure the droppable is visible
this.scrollVisible = this._isScrollIntoView();
if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element)) && (!this.options.scrollable || this.scrollVisible)) {
if (this.options.hoverClass) {
this.element.addClass(this.options.hoverClass);
}
// to activate scrollable you need to change scrollParent of the draggable
// and adjust some calculations
if (this.options.scrollable) {
draggable.overflowOffset = $(this.element).scrollParent().offset();
draggable.scrollParent = $(this.element).scrollParent();
draggable.offsetParent = $(this.element).scrollParent();
draggable.offset.parent.top = $(this.element).scrollParent().scrollTop();
}
this._trigger('over', event, this.ui(draggable));
}
},
_out: function (event) {
this._super();
var draggable = $.ui.ddmanager.current;
// remove scrollable
if (this.options.scrollable) {
draggable.scrollParent = $(document);
draggable.offsetParent = $(document);
draggable.overflowOffset = $(document).offset();
draggable.offset.parent.top = $(document).scrollTop();
}
},
_drop: function (event, custom) {
var draggable = custom || $.ui.ddmanager.current;
if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
var childrenIntersection = false;
this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function () {
var inst = $.data(this, 'droppable');
if (
inst.options.greedy && !inst.options.disabled && inst.options.scope == draggable.options.scope && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && $.ui.intersect(draggable, $.extend(inst, {
offset: inst.element.offset()
}), inst.options.tolerance)) {
childrenIntersection = true;
return false;
}
});
if (childrenIntersection) return false;
// same as for over, you need to validate visibility of the element
this.scrollVisible = this._isScrollIntoView();
if (this.accept.call(this.element[0], (draggable.currentItem || draggable.element)) && (!this.options.scrollable || this.scrollVisible)) {
if (this.options.activeClass) this.element.removeClass(this.options.activeClass);
if (this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
this._trigger('drop', event, this.ui(draggable));
return this.element;
}
return false;
},
// a function to check visibility. Taken here:
//http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling
_isScrollIntoView() {
var $elem = $(this.element);
var $parent = $(this.element).scrollParent();
var docViewTop = $parent.parent().scrollTop();
var docViewBottom = docViewTop + $parent.parent().height();
var elemTop = $elem.offset().top;
var elemBottom = elemTop + $elem.height();
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}
});
$(document).ready(function () {
$(".left ul li").draggable({
refreshPosition: true,
revert: true,
});
$(".right .top li").droppable({
scrollable: true,
drop: function (e, ui) {
alert(ui.draggable.text() + " " + $(this).text());
}
});
$(".right .bottom li").droppable({
scrollable: false,
drop: function (e, ui) {
alert(ui.draggable.text() + " " + $(this).text());
}
});
});
http://jsfiddle.net/ejv32oen/4/

Related

Synchronized charts example with Highstock crashes with "Cannot read property 'category' of undefined"

I want the functionality of the "Synchronized charts" example, but with Highstock. But when trying to accomplish this, I get "highstock.src.js:9991 Uncaught TypeError: Cannot read property 'category' of undefined"
This also holds directly for the example: http://www.highcharts.com/demo/synchronized-charts doesn't work when converted to Highstock: http://jsfiddle.net/9gq47g0w/
(Since StackOverflow demands me to post some code along with the fiddle, here's from Highstock, noting the point where it crashes with **):
/**
* Refresh the tooltip's text and position.
* #param {Object} point
*/
refresh: function (point, mouseEvent) {
...
// shared tooltip, array is sent over
if (shared && !(point.series && point.series.noSharedTooltip)) {
...
textConfig = {
x: ** point[0].category, ** <- here!
y: point[0].y
};
...
}
...
},
Here you can find an example of synchronized highstock charts:
http://jsfiddle.net/vw77cooj/20/
This example is using custom functions for synchronizing extremes and tooltips on charts:
function syncExtremes(e) {
var thisChart = this.chart;
if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
Highcharts.each(Highcharts.charts, function(chart) {
if (chart !== thisChart) {
if (chart.xAxis[0].setExtremes) { // It is null while updating
chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {
trigger: 'syncExtremes'
});
}
}
});
}
}
$('#container').bind('mousemove touchmove touchstart', function(e) {
Highcharts.each(Highcharts.charts, function(chart) {
event = chart.pointer.normalize(e.originalEvent);
point = chart.series[0].searchPoint(event, true);
if (point) {
point.onMouseOver(); // Show the hover marker
chart.tooltip.refresh(point); // Show the tooltip
chart.xAxis[0].drawCrosshair(event, point); // Show the crosshair
}
});
});
In case of having multiple series on your chart you may change function responsible for synchronizing your tooltip:
function syncTooltip(container, p) {
var i = 0,
j = 0,
data,
series,
points = [];
for (; i < chartSummary.length; i++) {
if (container.id != chartSummary[i].container.id) {
series = chartSummary[i].series
Highcharts.each(series, function(s) {
Highcharts.each(s.data, function(point) {
if (point.x === p && point.series.yAxis.options.index !== 1) {
points.push(point)
}
})
});
chartSummary[i].tooltip.refresh(points);
}
};
}
http://jsfiddle.net/ZArZM/316/
For a nice working example on Highstock, please follow this example with MouseOver and MouseOut:
var onMouseOver = function onMouseOver() {
var x = this.x,
interactedChart = this.series.chart,
points = [],
charts = Highcharts.charts,
each = Highcharts.each;
each(charts, function(chart) {
if (chart !== interactedChart) {
each(chart.series, function(series) {
each(series.data, function(point) {
if (point.x === x && point.series.yAxis.options.index !== 1) {
points.push(point)
}
})
});
each(points, function(p) {
p.setState('hover');
});
chart.tooltip.refresh(points);
}
});
}
http://jsfiddle.net/ska1r5wq/
You can avoid many tooltip issues from examples provided on the web.
Source : https://github.com/highcharts/highcharts/issues/6595

I need anchors on page load ( multiscroll.js )

If you notice there is no anchors when you load the page :
http://alvarotrigo.com/multiScroll/
but if you scroll down and up again :
/multiScroll/#first appears.
I need ' #first ' on first page load not when I scroll so I can use afterLoad function on page load.
Fiddle https://jsfiddle.net/oadfcjt2/8/
$('#myContainer').multiscroll({
sectionsColor: ['#1bbc9b', '#4BBFC3', '#7BAABE'],
menu: false,
afterLoad: function(anchorLink, index){
if(index == 1){
alert("first");
}
}
});
Any help?Thank you.
Use the afterRender callback for it.
$('#myContainer').multiscroll({
sectionsColor: ['#1bbc9b', '#4BBFC3', '#7BAABE'],
menu: false,
afterLoad: function (anchorLink, index) {
afterLoadActions(anchorLink, index);
},
afterRender: function () {
var activeSection = $('.ms-left').find('.ms-section.active');
var activeAnchor = activeSection.data('anchor');
afterLoadActions(activeAnchor, activeSection.index());
}
});
function afterLoadActions(anchorLink, index) {
if (index == 1) {
alert("first");
}
}

Showing Tool-tip & Cross-hair on two independent graphs from a single hover event?

Good day,
We are trying to develop a report which contains two charts. Each chart shows different metrics on the same timescale (unix timestamp). The aim is to show the tooltip & cross hair on both charts regardless of which you hover over.
In my head I would like to get the xAxis timestamp (time) from the tooltip hover event on chart A. I would then fetch the associated series on chart B and trigger the tooltip refresh event.
As it stands, it looks like highcharts only accepts points.
I've added a mouseOver/Out event to both charts. This obtains the hoverPoints
plotOptions: {
series: {
point: {
events: {
mouseOver: function () {
$el.trigger('tooltip-open', {"$sourceEl": $el[0], "point": this});
},
mouseOut: function () {
$el.trigger('tooltip-close', {"$sourceEl": $el[0], "point": this});
}
}
}
}
}
// Where $el is the highcharts container
// ..and tool-tip-XXXXX is a custom jQuery event.
My temporary work around is:
$el.bind('tooltip-open', function (e, data) {
var $el = $(this);
if (data.$sourceEl.id == $el.id) {
return;
}
var chart = $el.highcharts();
var points = $(chart.series).map(function () {
return this.points
}).get();
var pointsForTimestamp = $.grep(points, function (p) {
return p.x == data.point.x;
});
$(pointsForTimestamp).each(function () {
this.setState('hover');
});
chart.tooltip.refresh(pointsForTimestamp);
});
$el.bind('tooltip-close', function (e, data) {
var $el = $(this);
if (data.$sourceEl.id == this.id) {
return;
}
var chart = $el.highcharts();
chart.tooltip.hide();
});
var linkGraphs = function ($elA, $elB) {
function isEventHandled(data){
data.count = data.count || 0;
if(data.count > 0){
return true
}else{
data.count++;
return false;
}
}
function bindToOpen($elA, $elB) {
$elA.bind('tooltip-open', function (e, data) {
if(!isEventHandled(data)){
$elB.trigger('tooltip-open', data);
}
});
}
function bindToClose($elA, $elB) {
$elA.bind('tooltip-close', function (e, data) {
if(!isEventHandled(data)){
$elB.trigger('tooltip-close', data);
}
});
}
bindToOpen($elA, $elB);
bindToOpen($elB, $elA);
bindToClose($elA, $elB);
bindToClose($elB, $elA);
};

jQuery UI multiple selectable tooltips are collapsing

I'm new to jQuery UI.
I'm trying to create a selectable jQuery UI tooltip. The tooltip is associated with the links on a page.
When the link is surrounded by just text, it works fine. But when there are few links next to each other, the functionality overlaps and tooltips don't show smoothly anymore.
you can find the code on http://jsfiddle.net/zumot/Hc3FK/2/
Below the JavaScript code
$("[title][data-scan]").bind("mouseleave", function (event) {
event.stopImmediatePropagation();
var fixed = setTimeout('$("[title][data-scan]").tooltip("close")', 100);
$(".ui-tooltip").click(function () {
alert("I am clickable");
return false;
});
$(".ui-tooltip").hover(
function () {
clearTimeout(fixed);
},
function () {
$("[title][data-scan]").tooltip("close");
});}).tooltip({
items: "img, [data-scan], [title]",
content: function () {
var element = $(this);
if (element.is("[data-scan]")) {
var text = element.attr("href");
return "<a href='http://www.google.com'>You are trying to open a tooltip <span>" + text + "</span></a>";
}
if (element.is("[title]")) {
return element.attr("title");
}
if (element.is("img")) {
return element.attr("alt");
}
},
position: {
my: "right center",
at: "left center",
delay: 200,
using: function (position, feedback) {
$(this).css(position);
$("<div>")
.addClass(feedback.vertical)
.addClass(feedback.horizontal)
.appendTo(this);
}
}});
My attempt to fix the issue was by making the variable fixed global (to make it accessible by other jQuery UI properties), and on Open event, hide any other previously opened tooltips and clear the timeout id saved in fixed variable.
You can find the solution here http://jsfiddle.net/zumot/dVGWB/
, though to see the code working properly, you'll have to run it directly on your browser.
Here's the snapshort of the fixed code.
// Make the timeout id variable global
var fixed = 0;
$("[title][data-scan]").tooltip({
items: "img, [data-scan], [title]",
content: function () {
var element = $(this);
if (element.is("[data-scan]")) {
var text = element.attr("href");
return "<a href='http://www.google.com'>You are trying to open a tooltip <span>" + text + "</span></a>";
}
if (element.is("[title]")) {
return element.attr("title");
}
if (element.is("img")) {
return element.attr("alt");
}
},
open: function (event, ui) {
// When opening a new div, hide any previously opened tooltips first.
$(".ui-tooltip:not([id=" + ui.tooltip[0].id + "])").hide();
// clear timeout as well if there's any.
if (tf > 0) {
clearTimeout(tf)
};
},
position: {
my: "right center",
at: "left center",
delay: 200,
using: function (position, feedback) {
$(this).css(position);
$("<div>")
.addClass(feedback.vertical)
.addClass(feedback.horizontal)
.appendTo(this);
}
}
}).bind("mouseleave", function (event) {
// stop defeulat behaviour
event.stopImmediatePropagation();
fixed = setTimeout('$("[title][data-scan]").tooltip("close")', 100);
$(".ui-tooltip").hover(
function () {
clearTimeout(tf);
}, function () {
$("[title][data-scan]").tooltip("close");
})
});

jQuery Mobile + backbone.js: navbar issue

I load pages created from templates dynamically with a function from the Router (as seen on some tutorials):
changePage: function(page) { // page is a View object
$(page.el).attr('data-role', 'page');
page.render();
$('body').append($(page.el));
var transition = $.mobile.defaultPageTransition;
if (this.firstPage) {
transition = 'none';
this.firstPage = false;
}
$.mobile.changePage($(page.el), {changeHash:false, transition: transition});
}
The thing is when pages contain a JQ Mobile navbar, the active item is not highlighted. Actually it is, like 1 ms, then it's not, I feel like it's because the navbar is "reloaded".
When I click 2 times on the same item, it works the second time.
Is there anybody who is able to have working navbars with jQuery Mobile and backbone.js?
I ended up doing that:
var activeTab = null;
$('[data-role=page]').live('pageshow', function (event, ui) {
$.each($('[data-role=navbar] ul li').children(), function (i, val) {
if (typeof activeTab !== "undefined" && activeTab != null && $(val).attr('id') == 'navTab' + activeTab)
$(val).addClass($.mobile.activeBtnClass);
else
$(val).removeClass($.mobile.activeBtnClass);
});
activeTab = null;
});
And for each route that requires an active tab I just do for instance:
r_search: function() { // Search page (form)
activeTab = "Search";
this.changePage(new SearchView());
},

Resources