Draggable elements with connectors in jsPlumb - javascript

I want to implement a mapping app with draggable elements. I have used the following code but when the draggable is set, the div element is not draggable, only the anchor is draggable. What am I missing?
JSFiddle
<style>
.dd{
width:60px;
height:60px;
border:1px solid red;
position:relative;
}
</style>
<div class="container">
<div id="window3" class="dd" style="margin-left:50px;margin-top:100px"></div>
<div id="window4" class="dd" style="margin-left:400px;margin-top:100px"></div>
</div>
<script>
jsPlumb.ready(function () {
//
jsPlumb.draggable($(".dd"));
var endpointOptions = {
isSource: true,
isTarget: true,
endpoint: ["Dot", {
radius: 10
}],
style: {
fillStyle: 'blue'
},
maxConnections: -1,
connector: "Straight",
connectorStyle: {
lineWidth: 3,
strokeStyle: 'black'
},
scope: "blackline",
dropOptions: {
drop: function (e, ui) {
alert('drop!');
}
}
};
var window3Endpoint = jsPlumb.addEndpoint('window3', {
anchor: "Right"
}, endpointOptions);
var window4Endpoint = jsPlumb.addEndpoint('window4', {
anchor: "Left"
}, endpointOptions);
});
</script>
using jQuery draggable allows the div to be draggable but then the anchors become detached.
So the two options are
Use $(".dr").draggable() and find a way to bind anchors to the div
Make the div draggable in jsPlumb.draggable()
Or is my approach completely wrong?
UPDATE: I set the CSS position as absolute in the divs and now the divs are draggable but still the binding is faulty

You missed to invoke jsPlumb.repaintEverything() once the DOM element is dragged.
Here is the version which uses jQuery.draggable()
jsPlumb.ready(function() {
$('.dd').draggable({
//listen for element dragged event
drag: function(){
jsPlumb.repaintEverything();
}
});
var endpointOptions = {
isSource: true,
isTarget: true,
endpoint: ["Dot", {
radius: 10
}],
style: {
fillStyle: 'blue'
},
maxConnections: -1,
connector: "Straight",
connectorStyle: {
lineWidth: 3,
strokeStyle: 'black'
},
scope: "blackline",
dropOptions: {
drop: function(e, ui) {
alert('drop!');
}
}
};
var window3Endpoint = jsPlumb.addEndpoint('window3', {
anchor: "Right"
}, endpointOptions);
var window4Endpoint = jsPlumb.addEndpoint('window4', {
anchor: "Left"
}, endpointOptions);
});
Updated Fiddle

Related

Particles.js not working properly in .NET Core

NET MVC Core and I am trying to use Particles.js. I have already tried referencing a few tutorials, but am unable to solve this issue. This is how it normally looks like. https://vincentgarreau.com/particles.js/#default
I got this however, with big and super laggy buttons and also it does not occupy full screen nor does it have the hover action (whereby the circle moves away as the mouse approaches). The onclick circle works though. And the configuration shouldn't be wrong, as I downloaded the default one.
Update: Just before posting I managed to make it full screen. However, the big buttons and lagginess remains.
The following is my codes so far. I tried to search the id or class but due to the lack of documentation it is quite hard to find. Hope someone who knows it can help! Thank you very much :)
#{
ViewData["Title"] = "Home Page";
}
<div id="particles-js" style="background-color: rgb(0, 0, 0); background-image: url(""); background-size: cover; background-repeat: no-repeat; ba">
<canvas class="particles-js-canvas-el" style="width: 100%; height: 100%;"></canvas>
</div>
<script src="~/js/particles.js" data-turbolinks-track="reload" asp-append-version="true"></script>
<script>
particlesJS("particles-js", {
particles: {
number: {
value: 400,
density: {
enable: true,
value_area: 800
}
},
color: {
value: '#fff'
},
shape: {
type: 'circle',
stroke: {
width: 0,
color: '#ff0000'
},
polygon: {
nb_sides: 5
},
image: {
src: '',
width: 100,
height: 100
}
},
opacity: {
value: 1,
random: false,
anim: {
enable: false,
speed: 2,
opacity_min: 0,
sync: false
}
},
size: {
value: 20,
random: false,
anim: {
enable: false,
speed: 20,
size_min: 0,
sync: false
}
},
line_linked: {
enable: true,
distance: 100,
color: '#fff',
opacity: 1,
width: 1
},
move: {
enable: true,
speed: 2,
direction: 'none',
random: false,
straight: false,
out_mode: 'out',
bounce: false,
attract: {
enable: false,
rotateX: 3000,
rotateY: 3000
}
},
array: []
},
interactivity: {
detect_on: 'canvas',
events: {
onhover: {
enable: true,
mode: 'grab'
},
onclick: {
enable: true,
mode: 'push'
},
resize: true
},
modes: {
grab: {
distance: 100,
line_linked: {
opacity: 1
}
},
bubble: {
distance: 200,
size: 80,
duration: 0.4
},
repulse: {
distance: 200,
duration: 0.4
},
push: {
particles_nb: 4
},
remove: {
particles_nb: 2
}
},
mouse: {}
},
retina_detect: false,
});
//var count_particles, stats, update;
//stats = new Stats;
//stats.setMode(0);
//stats.domElement.style.position = 'absolute';
//stats.domElement.style.left = '0px';
//stats.domElement.style.top = '0px';
//document.body.appendChild(stats.domElement);
//count_particles = document.querySelector('.js-count-particles');
//update = function () {
// stats.begin();
// stats.end();
// if (window.pJSDom[0].pJS.particles && window.pJSDom[0].pJS.particles.array) {
// count_particles.innerText = window.pJSDom[0].pJS.particles.array.length;
// }
// requestAnimationFrame(update);
//};
//requestAnimationFrame(update);;
</script>
Update: I finally found the answer. To facilitate people who working on this in the future, make sure to use the download from the sidebar and not the one in the center.
Not this (the download in the center):
But this (the one at the bottom right side, "Download current config(json)"):

jsPlumb draggable element javascript function

The JSFiddle will clearly allow you to understand the problem.
I want the endpoints to be binded to the elements inside each container which are draggable but only the endpoints drawn first are correct. The second time the draw function is called, the positions are incorrect and the dragging is not synced.
I have a guess that the problem lie with the CSS position but I can't find it.
jsPlumb.ready(function() {
$(".scroll-box").draggable({
drag: function() {
jsPlumb.repaintEverything();
//jsPlumb.repaint($(this));
}
});
// jsPlumb.draggable($(".scroll-box"));
drawEndPoints("in-leaf", "Right");
drawEndPoints("out-leaf", "Left");
});
function drawEndPoints(classname, endpointposition) {
var endpointOptions = {
isSource: true,
isTarget: true,
endpoint: ["Dot", {
radius: 10
}],
style: {
fillStyle: 'blue'
},
maxConnections: -1,
connector: "Straight",
connectorStyle: {
lineWidth: 2,
strokeStyle: 'black'
},
scope: "blackline",
dropOptions: {
drop: function(e, ui) {
alert('drop!');
}
}
};
jsPlumb.addEndpoint($("." + classname), {
anchor: endpointposition
}, endpointOptions);
//jsPlumb.repaintEverything();
}
You are missing the jsPlumb.setContainer($("body"));
https://jsfiddle.net/mkaran/mLthybzo/
https://jsplumbtoolkit.com/community/doc/home
EDIT: a fiddle with your example https://jsfiddle.net/mkaran/aof6mq34/

Web animation reverts back after ends

I have a question regarding the browser compatability of Web Animations. I am aware that it is not working on some browsers.
However, is it possible to still use the transformation that is normally applied by the animation. My animation runs (through neon-animation from Polymer), but the result doesn't stay. It reverts back when the animation is finished.
(Small note, the $$("paper-item") is from polymer and is equivalent to querySelector("paper-item"))
I fixed this on Chrome with the following code:
_onNeonAnimationFinish: function() {
if (this.opened) {
this.$$("paper-item").style.margin = '16px auto';
this.$$("paper-item").style.width = '84vw';
this.$$("paper-item").style.height = '144px';
} else {
this.$$("paper-item").style.margin = "0px auto";
this.$$("paper-item").style.width = '72vw';
this.$$("paper-item").style.height = '72px';
}
}
As said, this is working on Chrome. Firefox and Safari are having trouble with it though. How can this be fixed?
My complete code is as following:
<!-- Custom element -->
<dom-module id="agenda-item">
<template>
<style>
paper-item {
background-color: #ffffff;
width: 72vw;
margin: 0 auto;
height: 72px;
}
</style>
<paper-item>
- content -
</paper-item>
</template>
<script>
Polymer({
is: 'agenda-item',
behaviors: [
Polymer.NeonAnimationRunnerBehavior
],
properties: {
opened: {
type: Boolean,
value: false,
reflectToAttribute: true
},
animationConfig: {
value: function() {
return {
'expand': [{
name: 'expand-list-item-animation',
node: this.$$("paper-item"),
timing: {
duration: 1000
}
}],
'collapse': [{
name: 'collapse-list-item-animation',
node: this.$$("paper-item"),
timing: {
duration: 1000
}
}]
};
}
}
},
listeners: {
'tap': 'onClick',
'neon-animation-finish': '_onNeonAnimationFinish'
},
onClick: function(event) {
if (this.opened) {
this.collapse();
} else {
this.expand();
}
},
expand: function() {
this.cancelAnimation();
this.playAnimation('expand');
this.opened = true;
},
collapse: function() {
this.cancelAnimation();
this.opened = false;
this.playAnimation('collapse');
},
_onNeonAnimationFinish: function() {
if (this.opened) {
this.$$("paper-item").style.margin = '16px auto';
this.$$("paper-item").style.width = '84vw';
this.$$("paper-item").style.height = '144px';
} else {
this.$$("paper-item").style.margin = '0px auto';
this.$$("paper-item").style.width = '72vw';
this.$$("paper-item").style.height = '72px';
}
}
});
</script>
</dom-module>
<!-- Custom animation -->
<!-- Both custom animations have the same idea and similar code -->
<script>
Polymer({
is: 'expand-list-item-animation',
behaviors: [
Polymer.NeonAnimationBehavior
],
configure: function(config) {
var node = config.node;
if (config.transformOrigin) {
this.setPrefixedProperty(node, 'transformOrigin', config.transformOrigin);
}
this._effect = new KeyframeEffect(node, [{
offset: 0.0,
'margin': '0 auto',
'width': '72vw',
'height': '72px'
}, {
offset: 0.6,
'margin': '16px auto',
'width': '84vw',
'height': '72px'
}, {
offset: 1.0,
'margin': '16px auto',
'width': '84vw',
'height': '144px'
}], this.timingFromConfig(config));
return this._effect;
}
});
</script>
EDIT:
I found the problem, but not how to solve it. It would be great to get some help.
The neon-animation-finish is not called at the moment the animation finishes. It is called just before that (not on chrome btw). Then, when the function is called to adjust the styling, it is overwritten by the animation.
You need to define a listener to the animation-finish and define what you want to see when the animation has finished like this:
listeners: {
// this event is fired when the animation finishes
'neon-animation-finish': '_onNeonAnimationFinish'
},
Have a look at the Polymer documentation at: https://github.com/PolymerElements/neon-animation/blob/master/README.md

How to show tooltip only if a region is clicked in jVectorMap, and let it open?

I'm using this jVectorMap. By default, it shows tooltip on hover.
Here is what I'm trying to achieve -
Show tooltip only on click (partially working but tooltip should be be above the mouse cursor. I couldn't figure out how to get mouse cursor position.)
Let the tooltip opens until user explicitly clicks on close.
Code: jsfiddle
$('#map').vectorMap({
map: "us_aea_en",
backgroundColor: "transparent",
regionStyle: {
initial: {
fill: "#818486"
}
},
onRegionClick: function (e, code) {
var map = $('#map').vectorMap('get', 'mapObject');
map.tip.show();
map.tip.html(code + "<p>Click to Close</p>");
},
onRegionTipShow: function (e, tip, code) {
e.preventDefault();
}
});
Desire Behavior
I got it working the way you want and updated your fiddle: http://jsfiddle.net/inanda/ufhz316z/5/
Javascript
$('#map').vectorMap({
map: "us_aea_en",
backgroundColor: "transparent",
regionsSelectable: true,
regionsSelectableOne: true,
regionStyle: {
initial: {
fill: "#818486"
},
selected: {
fill: "#C0C0C0"
}
},
onRegionClick: function (e, code) {
var map = $('#map').vectorMap('get', 'mapObject');
var customTip=$('#customTip');
customTip.css({
left: left,
top: top
})
customTip.html(map.tip.text());
customTip.show();
customTip.append(code + "<p>Click to Close</p>");
customTip.children("p").click(function(){
map.clearSelectedRegions();
customTip.hide();
})
},
onRegionTipShow: function (e, tip, code) {
e.preventDefault();
}
});
var left,top;
$('#map').vectorMap('get', 'mapObject').container.mousemove(function(e){
left = e.pageX - 40;
top = e.pageY - 60;
});
HTML
<div id="map"></div>
<div id="x"></div>
<div id="y"></div>
<div id="customTip" class="jvectormap-tip"></div>
CSS
#map {
width: 500px;
height: 400px;
}
You can highlight the selected region via fill or stroke parameters. More details can be found in the documentation of jVectorMap. Here a short example:
regionStyle: {
selected: {
stroke: '#000',
"stroke-width": 1.3,
"stroke-opacity": 1
}
},

jVectorMap on mobile requires 2 clicks

I've been using jVectorMap quite successfully-- it's a wonderful package for displaying interactive maps!
In this case, I only want some regions to be selectable, and there doesn't seem to be an option to set regions active/inactive. So instead, I set "regionsSelectable=false", and then set "selectedRegions" to the ones I want active.
This works fine (showing the correct hover attributes, etc. for "active" regions only)-- with one exception, in iOS. There, it takes two "clicks" (touches) for the "onRegionClick" handler to get invoked. On the first click, the "selectedHover" attributes are set correctly, but "handleRegion" never gets called. A second click, and "handleRegion" is called.
Initialization code looks like:
map = new jvm.WorldMap({
container: $('#mapdiv'),
map: 'world_mill_en',
regionsSelectable: false,
regionStyle: {
initial: { fill: '#0086d0' },
hover: { "fill-opacity": 1.0 },
selected: { fill: '#003a6a' },
selectedHover: { fill: '#ff7a00' }
},
onRegionClick: handleRegion,
selectedRegions:["CN","RU","US"],
...
});
function handleRegion(e,cc) {
alert("cc="+cc);
...
}
What is needed is either a way to "activate" only a few regions, or a way around this two-click problem.
I know this is a bit outdated question, but here is a hack around iOS issue for others like me who bumped to this question while searching for some hack around this.
As you already noted, iPad/iPhone are emulating hover with first "tap" .. and click with second "tap".
So to fix this ackward behavior we will do following (example on fiddle)
var lastCode = "";
var iOS = /(iPad|iPhone|iPod)/g.test( navigator.userAgent );
$('#world-map').vectorMap({
map: 'world_mill_en',
backgroundColor: 'green',
normalizeFunction: 'polynomial',
regionsSelectable: true,
regionsSelectableOne: true,
zoomOnScroll: true,
zoomButtons: true,
regionStyle: {
initial: {
fill: "white",
"fill-opacity": 1,
stroke: "none",
"stroke-width": 0,
"stroke-opacity": 1
},
hover: {
fill: "white",
"fill-opacity": 1
},
selected: {
fill: "#EC6602",
"fill-opacity": 1
},
selectedHover: {
fill: "#EC6602",
"fill-opacity": 1
}
},
onRegionClick: function(e, country){
if (lastCode && lastCode == country) {
e.preventDefault();
return;
}
var map = $("#world-map").vectorMap("get", "mapObject");
$("#world-map").vectorMap("set", "focus", country);
map.setScale(2);
if(country=="US" || country=="RU") {
map.setScale(1);
}
lastCode = country;
},
onRegionLabelShow: function (e, el, country) {
if (iOS) {
e.preventDefault();
var map = $("#world-map").vectorMap("get", "mapObject");
if (lastCode) {
map.regions[lastCode].element.setSelected(false);
}
map.regions[country].element.setSelected(true);
$("#world-map").vectorMap("set", "focus", country);
map.setScale(2);
if(country=="US" || country=="RU") {
map.setScale(1);
}
lastCode = country;
}
},
markers: [{
latLng: [37.7833, -122.4167],
name: 'San Francisco'
}]
});
In short words, we are overwriting onRegionLabelShow functionality with custom behavior (only for the iOS devices). Basically we are preventing the tooltip from showing and instead of that we are selecting the hovered (tapped) ccountry, focusing it and storing it's code in global variable.
On second tap we are detecting if the country has changed by comparing current code with last value and in that case un-selecting previously selected country and selecting new one.
It should be fairly easy to adapt the resolution to your needs.
actually, you should check onRegionTipShow:
...
handleIOSClick = function (e, el, code) {
if (istouch) {
var mapObject = $(map).vectorMap('get', 'mapObject');
map.regions[code].element.setSelected(true);
e.preventDefault();
}
},
CreateMap = function () {
if (typeof $(map) !== 'undefined'){
$(map).width(700);
$(map).height(400);
mapObject = $(map).vectorMap({
map: 'us_lcc_en',
onRegionClick: regionClicked,
onRegionTipShow: handleIOSClick,
backgroundColor: "inherit",
regionStyle: {
initial: {
fill: '#477294'
}
}
});
}
},
...

Categories