Jsplump dynamically draw state machine diagram - javascript

I am using jsplumb to draw dynamic state machine diagram. On click of a button I need to add new box in a drawing area and allow user to position it as per their need.
I am not getting any proper easy to understand documentation for this. I tried few things:
var i=8;
function AddDiv() {
var obj = new Date();
var Div = $('<div/>', {
'class':'box ui-draggable ui-draggable-handle ui-droppable',
'id':'box_'+i,
'html':'BOXESNEW'
}).appendTo('.statemachine_cont');
jsPlumb.addEndpoint($(Div), targetEndpoint);
$(Div).draggable(
{
drag: function(){
jsPlumb.repaint($(this)); // (or) jsPlumb.repaintEverything(); to repaint the connections and endpoints
// jsPlumb.addEndpoint($(this));
}
});
$(Div).addClass('box ui-draggable ui-draggable-handle ui-droppable');
}
var a = $("#a");
//Setting up drop options
var targetDropOptions = {
activeClass: 'dragActive'
};
//Setting up a Target endPoint
var targetColor = "#BEBEBE";
var targetEndpoint = {
anchor: "BottomCenter", //Placement of Dot
endpoint: ["Dot", { radius: 8}], //Other types are rectangle, Image, Blank, Triangle
paintStyle: { fillStyle: targetColor }, //Line color
isSource: true, //Starting point of the connector
// scope: "green dot",
connectorStyle: { strokeStyle: "#5C96BC", lineWidth: 2 }, // Means Bridge width and bridge color
connector: ["Bezier"], //Other properties Bezier
maxConnections: -1, //No upper limit
isTarget: true, //Means same color is allowed to accept the connection
dropOptions: targetDropOptions //Means when the drag is started, other terminals will start to highlight
};
jsPlumb.bind("ready", function () {
//Set up endpoints on the divs
jsPlumb.addEndpoint($(".box ui-draggable ui-draggable-handle ui-droppable"), targetEndpoint);
jsPlumb.addEndpoint($(".box ui-draggable ui-draggable-handle ui-droppable"), sourceEndpoint);
jsPlumb.draggable($(".box ui-draggable ui-draggable-handle ui-droppable"));
jsPlumb.animate($("#a"), { "left": 50, "top": 100 }, { duration: "slow" });
});
Not sure what I have done is correct, I referred to some online code available and modified it.
My issue here is: Onclick of a button I am able to add a new box and also able to drag a connection from that box. But when I try to drag that box (i.e change its position), the connection does not move. Box is moved but I am unable to move the connection with the box.
When I try to move the newly added box or the box connected to new one, both the boxes can be moved but the connection remains static and doesn't move. where as if other boxes are moved it moves along with the connections. I have added a image of that for reference.
1st image shows how newly added box and new connection appears. 2nd image shows how moving of the box creates the issue.

Here is how I manged to get it working. I modified my entire code
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title> - jsFiddle demo</title>
<script type='text/javascript' src='js/jquery-1.10.1.js'></script>
<link rel="stylesheet" type="text/css" href="css/demo-all.css">
<link rel="stylesheet" type="text/css" href="css/demo.css">
<script type='text/javascript' src="js/jquery.ui.touch-punch-0.2.2.min.js"></script>
<script type='text/javascript' src="js/jquery-ui-1.9.2.min.js"></script>
<script type='text/javascript' src="js/jquery.jsPlumb-1.7.2-min.js"></script>
<style type='text/css'>
.hidden { display: none; }
</style>
<script type='text/javascript'>
$(window).load(function(){
function cloneWindow(instance) {
var $jspContainer = $("#statemachine-demo"),
divid = "fromTemplate_" + new Date().getTime().toString()
$cloneElement = $("<div class='w'>New Window <div class='ep'></div></div>").attr("id", divid);
$jspContainer.append($cloneElement);
instance.draggable(divid);
instance.makeSource($cloneElement, {
filter: ".ep", // only supported by jquery
anchor: "Continuous",
connector: ["StateMachine", {
curviness: 1
}],
connectorStyle: {
strokeStyle: "#5c96bc",
lineWidth: 2,
outlineColor: "transparent",
outlineWidth: 4
},
maxConnections: 10,
onMaxConnections: function (info, e) {
alert("Maximum connections (" + info.maxConnections + ") reached");
}
});
instance.bind("connection", function (info) {
info.connection.getOverlay("label").setLabel(info.connection.id);
});
instance.makeTarget($cloneElement, {
anchor:"Continuous",
dropOptions:{ hoverClass:"dragHover" }
});
}
jsPlumb.ready(function () {
$("#addwindow").click(function() {
cloneWindow(instance);
});
// setup some defaults for jsPlumb.
var instance = jsPlumb.getInstance({
Endpoint: ["Dot", {
radius: 2
}],
HoverPaintStyle: {
strokeStyle: "#1e8151",
lineWidth: 2
},
ConnectionOverlays: [
["Arrow", {
location: 1,
id: "arrow",
length: 14,
foldback: 0.8
}],
["Label", {
label: "Drag this and drop it on another element to make a connection.",
id: "label",
cssClass: "aLabel"
}]
],
Container: "statemachine-demo"
});
jsPlumb.importDefaults({
filter: ".ep",
anchor: "Continuous",
connector: ["StateMachine", {
curviness: 1
}],
connectorStyle: {
strokeStyle: "#5c96bc",
lineWidth: 2,
outlineColor: "transparent",
outlineWidth: 4
},
maxConnections: 10,
dropOptions: {
hoverClass: "dragHover"
}
});
var windows = jsPlumb.getSelector(".statemachine-demo .w");
// initialise draggable elements.
instance.draggable(windows);
// bind a click listener to each connection; the connection is deleted. you could of course
// just do this: jsPlumb.bind("click", jsPlumb.detach), but I wanted to make it clear what was
// happening.
instance.bind("click", function (c) {
instance.detach(c);
});
// bind a connection listener. note that the parameter passed to this function contains more than
// just the new connection - see the documentation for a full list of what is included in 'info'.
// this listener sets the connection's internal
// id as the label overlay's text.
instance.bind("connection", function (info) {
info.connection.getOverlay("label").setLabel(info.connection.id);
});
// suspend drawing and initialise.
instance.doWhileSuspended(function () {
// make each ".ep" div a source and give it some parameters to work with. here we tell it
// to use a Continuous anchor and the StateMachine connectors, and also we give it the
// connector's paint style. note that in this demo the strokeStyle is dynamically generated,
// which prevents us from just setting a jsPlumb.Defaults.PaintStyle. but that is what i
// would recommend you do. Note also here that we use the 'filter' option to tell jsPlumb
// which parts of the element should actually respond to a drag start.
instance.makeSource(windows, {
filter: ".ep", // only supported by jquery
anchor: "Continuous",
connector: ["StateMachine", {
curviness: 1
}],
connectorStyle: {
strokeStyle: "#5c96bc",
lineWidth: 2,
outlineColor: "transparent",
outlineWidth: 4
},
maxConnections: 10,
onMaxConnections: function (info, e) {
alert("Maximum connections (" + info.maxConnections + ") reached");
}
});
// initialise all '.w' elements as connection targets.
instance.makeTarget(windows, {
dropOptions: {
hoverClass: "dragHover"
},
anchor: "Continuous"
});
// and finally, make a couple of connections
instance.connect({
source: "opened",
target: "phone1"
});
instance.connect({
source: "phone1",
target: "inperson"
});
instance.connect({
source: "phone1",
target: "phone1"
});
});
});
});
</script>
</head>
<body>
<div class="demo statemachine-demo" id="statemachine-demo" style="border:2px solid;border-radius:25px;">
<button type="button" id="addwindow">Add Window</button>
<div class="w" id="opened">BEGIN
<div class="ep"></div>
</div>
<div class="w" id="phone1">PHONE INTERVIEW 1
<div class="ep"></div>
</div>
<div class="w" id="phone2">PHONE INTERVIEW 2
<div class="ep"></div>
</div>
<div class="w" id="inperson">IN PERSON
<div class="ep"></div>
</div>
<div class="w" id="rejected">REJECTED
<div class="ep"></div>
</div>
<div class="w hidden" id="template_newwindow">
<div class="ep"></div>
</div>
</div>
</body>
</html>

Div is already a jquery object, there is no need to wrap it again.
Option 1
Div.draggable(
{
drag: function(){
jsPlumb.repaintEverything();
}
});
Option 2
jsPlumb.draggable(Div.attr('id'));

Related

Highcharts - Suppress points being dragged on drag event

I'm new to Highcharts - it seems you can only trigger drag events if the appropriate dragDrop events are defined and enabled on a series. E.g. https://api.highcharts.com/highcharts/plotOptions.series.dragDrop
How can I suppress the points actually being moved around in my chart? I have tried setting allowPointSelect: false and disabling both draggableX and draggableY but of course doing that don't fire any drag events. I have also tried event.preventDefault but no luck
What I'm basically looking for is to have a user drag over a range in a line/area chart from startX/Y to endX/Y and display the results to the user (which I can successfully get using mouseOver - a nice feature!)
For such a feature, you don't need to use draggable-points module. A simple custom solution with a crosshair and dynamically added/removed plot-lines will be enough. For example:
chart: {
animation: false,
events: {
load: function() {
const chart = this;
this.series[0].points.forEach(point => {
point.graphic.on('mousedown', function() {
chart.draggedPoint = point;
chart.xAxis[0].update({
plotLines: [{
width: 2,
color: 'grey',
dashStyle: 'ShortDash',
value: point.x
}]
});
});
});
document.body.addEventListener('mouseup', function() {
chart.draggedPoint = null;
chart.xAxis[0].update({
plotLines: []
});
});
}
}
}
Live demo: https://jsfiddle.net/BlackLabel/rsuj93at/
API Reference: https://api.highcharts.com/highcharts/tooltip.formatter

Stopping of spinner with javaScript - SpinJs

I can start spinner, but dont know how to stop it. Pls help:
//On button click load spinner and go to another page
$("#btn1").click(function () {
//Loads Spinner
$("#loading").fadeIn();
var opts = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 4, // The line thickness
radius: 10, // The radius of the inner circle
color: '#000', // #rgb or #rrggbb
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false // Whether to use hardware acceleration
};
var trget = document.getElementById('loading');
var spnr = new Spinner(opts).spin(trget);
});
$("#btn2").click(function () {
//Write code to stop spinner
});
<button id="btn1">Start</button>
<button id="btn2">Stop</button>
<div id="loading">
<div id="loadingcont">
<p id="loadingspinr">
</p>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js" type="text/javascript"></script>
Refernces:
http://spin.js.org/
Stop Spinner.js
Use this Code.
$("#btn2").click(function () {
//Write code to stop spinner
$('#loading').fadeOut();
});
Just destroy it, for instance - it will disappear
$("#btn2").click(function () {
document.getElementById('loading').innerHTML='';
});
$(trget).data('spinner', spnr);
$('loading').data('spinner').stop();
//On button click load spinner and go to another page
$("#btn1").click(function () {
//Loads Spinner
$("#loading").fadeIn();
var opts = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 4, // The line thickness
radius: 10, // The radius of the inner circle
color: '#000', // #rgb or #rrggbb
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false // Whether to use hardware acceleration
};
var trget = document.getElementById('loading');
var spnr = new Spinner(opts).spin(trget);
});
$("#btn2").click(function () {
//Write code to stop spinner
$('#loading').fadeOut();
});
<button id="btn1">Start</button>
<button id="btn2">Stop</button>
<div id="loading">
<div id="loadingcont">
<p id="loadingspinr">
</p>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js" type="text/javascript"></script>
make the var spnr for accessible both the functions,
spnr = new Spinner(opts).spin(trget);
----------
$("#btn2").click(function () {
//Write code to stop spinner
spnr.stop();
});

Saving image as Base64 string in Javascript using LiterallyCanvas

I've taken a demo from the open source LiterallyCanvas, where you can take an image from your desktop and draw on it, then click save to get it as a base64 string. I've modified the code a bit and it currently allows me to draw an arrow, ellipsis and free drawing. But since the code sets the image as a background image, when I hit save, the base64 string only saves with the drawings I made, not the image I chose as well.
Can anyone tell me where I've gone wrong? I assume it's because I just set the background, but I don't know how to save that as well. I basically want the program to load an image, draw perhaps an arrow on it, then save the image with the arrow on it as well. As a Base64 string.
Here is the current code:
<html><head>
<title>Canvas</title>
<link href="../_assets/literallycanvas.css" rel="stylesheet">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
</head>
<body>
<div class="fs-container">
<div class="literally toolbar-hidden toolbar-hidden toolbar-hidden toolbar-hidden toolbar-hidden">
<div class="lc-drawing" style="background-color: transparent;">
<canvas width="1158" height="600" style="width: 1158px; height: 600;"></canvas>
<canvas width="1158" height="600" style="background-color: transparent; width: 1158px; height: 600;"></canvas>
</div>
</div>
<div class="toolset">
<span class="toolLabel">Actions:</span>
<input type='file' id='getval' name="background-image" onchange="readURL(event)" /><br/><br/>
Save
Cancel
</div>
<div class="toolset">
<span class="toolLabel">Tools:</span>
Pencil
Arrow
Ellipse
</div>
<div class="toolset" id="tools-colors">
<span class="toolLabel">Colors:</span>
Red
</div>
<script src="../_js_libs/jquery-3.0.0.js"></script>
<script src="../_js_libs/literallycanvas-core.js"></script>
<script type="text/javascript">
var lc = null;
var tools;
var strokeWidths;
var colors;
var setCurrentByName;
var findByName;
function readURL(event){
var getImagePath = URL.createObjectURL(event.target.files[0]);
$('.lc-drawing').css('background-image', 'url(' + getImagePath + ')'),
$('.lc-drawing').css('background-repeat', 'no-repeat');
}
// the only LC-specific thing we have to do
var containerOne = document.getElementsByClassName('literally')[0];
var showLC = function() {
lc = LC.init(containerOne, {
snapshot: JSON.parse(localStorage.getItem('drawing')),
defaultStrokeWidth: 10,
strokeWidths: [10, 20, 50],
secondaryColor: 'transparent'
});
window.demoLC = lc;
var save = function() {
localStorage.setItem('drawing', JSON.stringify(lc.getSnapshot()));
}
lc.on('drawingChange', save);
lc.on('pan', save);
lc.on('zoom', save);
$("#open-image").click(function() {
window.open(lc.getImage({
scale: 1, margin: {top: 10, right: 10, bottom: 10, left: 10}
}).toDataURL());
});
$("#change-size").click(function() {
lc.setImageSize(null, 200);
});
$("#reset-size").click(function() {
lc.setImageSize(null, null);
});
$("#clear-lc").click(function() {
lc.clear();
});
tools = [
{
name: 'pencil',
el: document.getElementById('tool-pencil'),
tool: new LC.tools.Pencil(lc)
},{
name: 'arrow',
el: document.getElementById('tool-arrow'),
tool: function() {
arrow = new LC.tools.Line(lc);
arrow.hasEndArrow = true;
return arrow;
}()
},{
name: 'ellipse',
el: document.getElementById('tool-ellipse'),
tool: new LC.tools.Ellipse(lc)
},{
name: 'tool-rectangle',
el: document.getElementById('tool-rectangle'),
tool: new LC.tools.Rectangle(lc)
}
];
colors = [
{
name: 'black',
el: document.getElementById('colorTool-black'),
color: '#000000'
},{
name: 'red',
el: document.getElementById('colorTool-red'),
color: '#ff0000'
}
];
setCurrentByName = function(ary, val) {
ary.forEach(function(i) {
$(i.el).toggleClass('current', (i.name == val));
});
};
findByName = function(ary, val) {
var vals;
vals = ary.filter(function(v){
return v.name == val;
});
if ( vals.length == 0 )
return null;
else
return vals[0];
};
// Wire tools
tools.forEach(function(t) {
$(t.el).click(function() {
var sw;
lc.setTool(t.tool);
setCurrentByName(tools, t.name);
setCurrentByName(strokeWidths, t.tool.strokeWidth);
$('#tools-sizes').toggleClass('disabled', (t.name == 'text'));
});
});
setCurrentByName(tools, tools[0].name);
// Wire Stroke Widths
strokeWidths.forEach(function(sw) {
$(sw.el).click(function() {
lc.trigger('setStrokeWidth', sw.size);
setCurrentByName(strokeWidths, sw.name);
})
})
setCurrentByName(strokeWidths, strokeWidths[0].name);
// Wire Colors
colors.forEach(function(clr) {
$(clr.el).click(function() {
lc.setColor('primary', clr.color)
setCurrentByName(red, red);
})
})
setCurrentByName(red, red);
};
$(document).ready(function() {
$(document).bind('touchmove', function(e) {
if (e.target === document.documentElement) {
return e.preventDefault();
}
});
showLC();
});
$('#hide-lc').click(function() {
if (lc) {
lc.teardown();
lc = null;
}
});
$('#show-lc').click(function() {
if (!lc) { showLC(); }
});
</script>
Use the getImage() function from the Literallycanvas instance to get a drawn canvas and then you can call toDataURL() to get the base64 string.
Read more in their docs: http://literallycanvas.com/examples/export.html
Regardless of what’s displayed in the viewport, you can export the complete drawing, or any subset of the drawing, using getImage().
These examples export your drawing as a PNG in a new window. The conversion to PNG is handled by the built-in canvas function toDataURL(). To learn more about what image formats are available, refer to Mozilla’s canvas element reference.
I personally use file-saver to download the image instead of using the base64 myself:
lc.getImage().toBlob(
blob => {
saveAs(blob, fileName);
},
"image/jpeg",
1
);

use specific kendo chart library files instead of kendo.all.min.js

I am using Kendo chart in my application, for this "kendo.all.min.js" is used
but size of this file is 2.5 MB, and i want to optimize the speed performance of application therfore i want only specific kendo chart library,
I am using following library instead of kendo.all.min.js.
<script src="scripts/kendo/kendo.core.min.js"></script>
<script src="scripts/kendo/kendo.data.min.js"></script>
<script src="scripts/kendo/kendo.userevents.min.js"></script>
<script src="scripts/kendo/kendo.color.min.js"></script>
<script src="scripts/kendo/kendo.pdf.min.js"></script>
<script src="scripts/kendo/kendo.drawing.min.js"></script>
<script src="scripts/kendo/kendo.dataviz.core.min.js"></script>
<script src="scripts/kendo/kendo.dataviz.themes.min.js"></script>
<script src="scripts/kendo/kendo.dataviz.chart.min.js"></script>
<script src="scripts/kendo/kendo.dataviz.chart.polar.min.js"></script>
<script src="scripts/kendo/kendo.dataviz.chart.funnel.min.js"></script>
And When i run application it throws error "Origin are not define"
$("#chart").kendoChart({
legend: {
position: "bottom",
item: {
visual: createLegendItem
}
},
seriesDefaults: {
type: "line",
style: "smooth",
visual: function (e) {
return createColumn(e.rect, "#6e6e78");//#0099CC")// e.options.color);
}
},
series: [{
type: "column",
data: a,b,c,d,
labels: {
visible: true,
position: "outsideEnd",
visual: function (e) {
console.log(e);
var rect;
//if (checkScreenSize()) {
// rect = new kendo.geometry.Rect(
// [e.rect.origin.x, e.rect.origin.y], // Position of the top left corner
// [25,25] // Size of the rectangle
// );
//} else {
rect = new kendo.geometry.Rect(
[e.rect.origin.x - position, e.rect.origin.y], // Position of the top left corner
[size, size] // Size of the rectangle
);....
Please let me know where i am wrong and which files i missed to include.
use kendo.custom.min.js file before above files, it will work

Created function not found

I'm trying to create a simple function, but at runtime firebug says the function does not exist.
Here's the function code:
<script type="text/javascript">
function load_qtip(apply_qtip_to) {
$(apply_qtip_to).each(function(){
$(this).qtip(
{
content: {
// Set the text to an image HTML string with the correct src URL to the loading image you want to use
text: '<img class="throbber" src="/projects/qtip/images/throbber.gif" alt="Loading..." />',
url: $(this).attr('rel'), // Use the rel attribute of each element for the url to load
title: {
text: 'Nieuwsbladshop.be - ' + $(this).attr('tooltip'), // Give the tooltip a title using each elements text
//button: 'Sluiten' // Show a close link in the title
}
},
position: {
corner: {
target: 'bottomMiddle', // Position the tooltip above the link
tooltip: 'topMiddle'
},
adjust: {
screen: true // Keep the tooltip on-screen at all times
}
},
show: {
when: 'mouseover',
solo: true // Only show one tooltip at a time
},
hide: 'mouseout',
style: {
tip: true, // Apply a speech bubble tip to the tooltip at the designated tooltip corner
border: {
width: 0,
radius: 4
},
name: 'light', // Use the default light style
width: 250 // Set the tooltip width
}
})
}
}
</script>
And I'm trying to call it here:
<script type="text/javascript">
// Create the tooltips only on document load
$(document).ready(function()
{
load_qtip('#shopcarousel a[rel]');
// Use the each() method to gain access to each elements attributes
});
</script>
What am I doing wrong?
You are missing a ), closing the each call.
Change last line in the function declaration to
);}
For similar problems in the future, try pasting your code into http://www.jslint.com/

Categories

Resources