I am trying to use jsPlumb to connect questions with answers in a quiz. I have most of this working expect I want to be able to click a question and then click an answer instead of dragging from an endpoint to another endpoint. This is because dragging on a touch device is tedious. Is this possible?
Here is my jsbin with the dragging working
Here is the jquery I am using.
$(document).ready(function () {
var targetOption = {
anchor: "LeftMiddle",
isSource: false,
isTarget: true,
reattach: true,
endpoint: "Rectangle",
connector: "Straight",
connectorStyle: { strokeStyle: "#ccc", lineWidth: 5 },
paintStyle: { width: 20, height: 20, fillStyle: "#ccc" },
setDragAllowedWhenFull: true
}
var sourceOption = {
tolerance: "touch",
anchor: "RightMiddle",
maxConnections: 1,
isSource: true,
isTarget: false,
reattach: true,
endpoint: "Rectangle",
connector: "Straight",
connectorStyle: { strokeStyle: "#ccc", lineWidth: 5 },
paintStyle: { width: 20, height: 20, fillStyle: "#ccc" },
setDragAllowedWhenFull: true
}
jsPlumb.importDefaults({
ConnectionsDetachable: true,
ReattachConnections: true
});
jsPlumb.addEndpoint('match1', sourceOption);
jsPlumb.addEndpoint('match2', sourceOption);
jsPlumb.addEndpoint('match3', sourceOption);
jsPlumb.addEndpoint('match4', sourceOption);
jsPlumb.addEndpoint('answer1', targetOption);
jsPlumb.addEndpoint('answer2', targetOption);
jsPlumb.addEndpoint('answer3', targetOption);
jsPlumb.addEndpoint('answer4', targetOption);
jsPlumb.draggable('match1');
jsPlumb.draggable('answer1');
});
I think if you don't need draggable, then you shouldn't use it, and go with normal click=connect approach.
Here is an example:
http://jsbin.com/ajideh/7/
Basically what I did:
//current question clicked on
var questionSelected = null;
var questionEndpoint = null;
//remember the question you clicked on
$("ul.linematchitem > li").click( function () {
//remove endpoint if there is one
if( questionSelected !== null )
{
jsPlumb.removeAllEndpoints(questionSelected);
}
//add new endpoint
questionSelected = $(this)[0];
questionEndpoint = jsPlumb.addEndpoint(questionSelected, sourceOption);
});
//now click on an answer to link it with previously selected question
$("ul.linematchplace > li").click( function () {
//we must have previously selected question
//for this to work
if( questionSelected !== null )
{
//create endpoint
var answer = jsPlumb.addEndpoint($(this)[0], targetOption);
//link it
jsPlumb.connect({ source: questionEndpoint, target: answer });
//cleanup
questionSelected = null;
questionEndpoint = null;
}
});
When you click on the question list element - it adds endpoint, when you click on the answer element - it also adds endpoint and connects it with previously selected question.
I believe this is what you wanted to do ?
P.S. As a side note, to make this more intuitive for the user, make endpoints for questions visible first, so the user would figure out what to do - click. Once question is selected, available answer endpoints can pop-up hinting where user should click next.
Related
We are using Chart.js (version 2.6.0) for a bar chart in an Angular 5 application and the client wanted us to disable hover events for chart interactions(they only wanted the bar to change and the tooltips to show up when the user clicked on a bar).
in the bar chart options object, we have the following defined for the events property:
events: ["touchstart","touchmove","click"]
That disables hovering events over the bar chart. Now however, the client wants us to change the cursor to a pointer when the user hovers over one of the bars, so that they know they can click on it, which is a valid point. I've found several solutions here on SO, but I can't seem to find a way to do it without adding "mousemove" to the events property, which just enables hovering interactions on the entire chart.
What really confuses me is that options.hover has an event property called "onHover" that has a callback, but it fires when ANY of the defined events happens, including clicks.
http://www.chartjs.org/docs/latest/general/interactions/events.html
Is this even possible without re-enabling the hover interaction in general? Any help would be greatly appreciated.
With Chart.js 3.x:
onHover: (event, chartElement) => {
event.native.target.style.cursor = chartElement[0] ? 'pointer' : 'default';
}
With Chart.js 2.x:
onHover: (event, chartElement) => {
event.target.style.cursor = chartElement[0] ? 'pointer' : 'default';
}
Based on #Luca Fagioli answer, in my case, I didn't want to disable the click events in my chart so i added:
events: ['mousemove', 'click'],
onHover: (event, chartElement) => {
event.target.style.cursor = chartElement[0] ? 'pointer' : 'default';
}
now that you have a cursor on the chart you want the cursor in the legend too - if they are clickable - so in the legend settings toy hold add:
onHover: (event) => {
event.target.style.cursor = 'pointer';
}
For versions > 3.x
you find the target under native
options: {
plugins : {
legend: {
labels: {
onHover: function (e) {
e.native.target.style.cursor = 'pointer';
},
onLeave: function (e) {
e.native.target.style.cursor = 'default';
}
}
}
}
}
This is almost 5 years old question, using the version 3.x.x of ChartJS we just need to declare some event handlers like onHover, onClick and define the events handle by the tooltip like events: ['click'].
Here we have a working snippet:
const isArray = a => a instanceof Array
const isNull = a => a == null
const cursor = a => {
if (isNull(a)) return 'default'
if (!isArray(a)) return 'pointer'
if (isArray(a) && a.length > 0) return 'pointer'
return 'default'
}
const $canvas = document.getElementById('chart')
const onHover = (e, item) => {
$canvas.style.cursor = cursor(item)
}
const onLeave = () => {
$canvas.style.cursor = 'default'
}
const onClick = (event, items) => {
if (items.length === 0) return
console.log('onclick')
}
const lineChart = new Chart($canvas, {
type: 'bar',
data: {
labels: ['May', 'June', 'July'],
datasets: [{
data: [15, 25, 15],
label: "My Dataset1",
backgroundColor: "#00F",
fill: false
}, {
data: [35, 15, 25],
label: "My Dataset2",
backgroundColor: "#F00",
fill: false
}]
},
options: {
responsive: true,
onHover,
onClick,
plugins: {
tooltip: {
// Tooltip will only receive click events
events: ['click'],
},
legend: {
onHover,
onLeave,
},
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<canvas id="chart" width="600" height="180"></canvas>
I am attempting to fire a click event when the page loads but only once on each page load. What is happening is that in localhost it works fine, but when I upload to server it dosen't fire at all.
The idea was to set a counter to 0 when the page loads then inc the counter by 1 to disable further clicks. Obviously, there is an error somewhere but I cannot solve it.
I am using jqwidgets jqxgrid to display the data and getting the class as a variable. I am also using jquery 1.11.1
I would be grateful if someone could help me solve this as I seem to have tried many combinations, but ok on localhost but nothing on server. I am using php v5.3.13 wamp and 5.4 on server. Many thanks
var counter = 0;
window.onload = function() {
var calendaricons = document.getElementsByClassName('jqx-icon-calendar');
for (var i = 0; i < calendaricons.length; i++) {
calendaricons[i].addEventListener('click', function() {
if (counter === 0) {
notif({
type: "info",
msg: "Test Message",
width: 650,
height: 99,
multiline: true,
position: "center",
fade: true,
//timeout: 3000,
autohide: false,
clickable: true
});
counter++;
} else {
return false;
}
});
}
}
If you are using jQuery, which it seems the case, you can use the one function that allows your handler to be runt only once.
Here is your code with the use of the one function:
$(window).load(function() {
$('.jqx-icon-calendar').each(function(index, item) {
$(this).one("click", function() {
notif({
type: "info",
msg: "Test Message",
width: 650,
height: 99,
multiline: true,
position: "center",
fade: true,
//timeout: 3000,
autohide: false,
clickable: true
});
});
});
});
I'm trying to prevent the default behavior when I click on the angular-nvD3 Stacked Area Chart. I managed to access the onclick function, but I don't know how to prevent the event (modifies the graphic) from happening. I don't want the graphic to change when the user clicks on it.
.js:
$scope.stackedAreaChartOptions = {
chart: {
type: 'stackedAreaChart',
height: 450,
margin : {
top: 20,
right: 20,
bottom: 30,
left: 40
},
x: function(d){return d[0];},
y: function(d){return d[1];},
useVoronoi: false,
clipEdge: true,
duration: 100,
useInteractiveGuideline: true,
xAxis: {
showMaxMin: false,
tickFormat: function(d) {
return d3.time.format('%H:%M')(new Date(d))
}
},
yAxis: {
tickFormat: function(d){
return d3.format(',.2f')(d);
}
},
zoom: {
enabled: false,
scaleExtent: [1, 10],
useFixedDomain: false,
useNiceScale: false,
horizontalOff: false,
verticalOff: true,
unzoomEventType: 'dblclick.zoom'
},
//chart events
stacked: {
dispatch: {
areaClick:
function (t,u){ null; console.log("areaClick");}
,
areaMouseover:
function (t,u){ null; console.log("areaMouseover");}
,
areaMouseout:
function (t,u){null; console.log("areaMouseout");}
,
renderEnd:
function (t,u){null; console.log("renderEnd");}
,
elementClick:
function (t,u){null; console.log("elementClick");}
,
elementMouseover:
function (t,u){null; console.log("elementMouseover");}
,
elementMouseout:
function (t,u){ null;console.log("elementMouseout");}
}
},
controlLabels: {stacked:"Absoluto", expanded:"Relativo"},
controlOptions:
[
"Stacked",
false,
"Expanded"
]
},
title: {
enable: true,
text: '',
css: {
'font-weight': 'bold'
}
},
caption: {
enable: true,
html: 'VisualizaciĆ³n por horas de acceso a noticia',
css: {
'text-align': 'center',
'margin': '2px 13px 0px 7px',
'font-style': 'italic'
}
}
};
HTML:
<nvd3 options="stackedAreaChartOptions" data="stackedAreaChartData" api="api"></nvd3>
When I click on the graphic, the messages (console.log) are being shown, but I need to prevent the click event from happening.
I know this is an old question, but I run into this problem for my project and here is how I solved it.
It seems it's not possible to disabled these events using angular-nvd3. You must disable them using NVD3.
Get the chart api object available on your angular-nvd3 chart and disable the events on the chart object binded to this api:
HTML
<nvd3 options="options" data="data" api="chartAPI"></nvd3>
Javascript
$timeout( function() {
if ($scope.chartAPI) {
var chart = $scope.chartAPI.getScope().chart;
chart.stacked.dispatch.on('areaClick.toggle', null);
chart.stacked.dispatch.on('areaClick', null);
}
}, 1000);
I made a timeout be sure to have the chartAPI when doing the changes.
Note : It seems you have to disable these events again when you update or refresh the chart (chart.refresh()).
Working example here: https://codepen.io/mvidailhet/pen/JNYJwx
It seems there is a glitch in the chart update on Codepen, but you get the point :)
Hope it helps!
You were close. CSS pointer-events:none; has the disadvantage that it turns off every pointer event (most importantly hover, mouseenter and mouseout).
So IMHO you should avoid to use it.
Actually you were close. You should not pass an it-does-nothing function but null or undefined instead to options.chart.stacked.dispatch.areaClick. Like this:
//chart events
stacked: {
dispatch: {
areaClick: void 0
}
}
I had this very same problem and spent more than an hour to find it out.
EDIT
Turned out that I was wrong. It solved just because it ran into an error that prevented the event. So you can throw an error and everything is fine... :)
Also found a workaround but that causes memory leak, so I'll not share that.
My solution was: accept that it applies click event and hides all other layers. Too small issue to invest more time and effort in it.
I would like to get the element that called the qtip popup. In the documentation here it lets you set the position. I want to set the position using a jquery selector like $(this).find('.icon'). The problem is that this isn't the element that called the qtip (I think it's window).
Does anyone know how I can get the handle that called it (like it would if I set target to false)?
Thanks.
In the qtip source code I found this:
if(config.position.target === false) config.position.target = $(this);
Here's the solution I came up with and it seems to work. There probably is a better way to do it if I modified the qtip script but I want to leave that alone.
$(".report-error").qtip(
{
content: 'test content',
position:
{
adjust:
{
screen: true
},
target: false, //it is changed in the 'beforeRender' part in api section. by leaving it as false here in the qtip it will set it as the position I need using $(this)
corner:
{
target: 'bottomMiddle',
tooltip: 'topRight'
}
},
show:
{
when:
{
event: 'click'
}
},
style:
{
name: 'cream',
tip:
{
corner: 'topRight'
},
padding: 0,
width: 400,
border:
{
radius: 5,
width: 0
}
},
hide:
{
when:
{
event: 'unfocus'
}
},
api:
{
beforeRender: function() { //get the position that qtip found with $(this) in it's script and change it using that as the start position
this.options.position.target = $(this.elements.target).find('.icon');
this.elements.target = this.options.position.target; //update this as well. I don't actually know what it's use is
}
}
});
It's working on the site now at http://wncba.co.uk/results/
Now I know what you guys were thinking when you read the title. Your probable thinking that im talking about jQuery UI draggable. But im actually talking about the plugin i'm making for the community. I am trying to create a target for my plugin. It works as you can see here:
http://jsfiddle.net/XvZLn/24/
As you can see it works fine.
First, let me explain whats suppose to happen. Well what I want, is if the element is dropped in the target...the targ.on() gets launched. This is the onTarget feature in my plugin. This and the offTarget(targ.off()) are not working in my plugin.
This is what I have in my plugin:
var targ = {
on: o.target.onTarget,
off: o.target.offTarget
};
Then my plugin setup code is:
$(document).ready(function() {
$('#drag').jDrag({
revert: false,
revertDuration: 500,
ghostDrop: false,
ghostRevert: false,
ghostOpacity: '0.50',
instantGhost: false,
activeClass: false,
handle: false,
grid: false,
cookies: false,
cookieExdate: 365,
radialDrag: false,
radius: 100,
circularOutline: false,
strictMovement: false,
distance: 0,
not: false,
containment: false,
target: {
init: '#container',
lock: false,
onTarget: function() {
$(this).hide();
},
offTarget: function() {}
},
onPickUp: function() {},
onDrop: function() {}
});
});
I don't see why it wont work.
This is my actually plugin if you want to take a look in it:
http://jsfiddle.net/ZDUZL/89/
Try:
onTarget: function() {
console.log(this);
$(this).hide();
},
You'll see that "this" isn't referring to the element, but rather the object that holds the function.
Pass the element as an argument:
if (locker === false) {
if (statement) {
targ.on(this);
lock = false;
} else {
targ.off();
lock = false;
}
}
http://jsfiddle.net/ZDUZL/91/