Set Container Element of a jsPlumb Line - javascript

I have two small green divs within my canvas. It can be drag within the canvas with an id myid_templates_editor_canvas, with the use of the code below:
myid_templates_editor_make_draggable('div1');
myid_templates_editor_make_draggable('div2');
// Make an element draggable within the canvas
function myid_templates_editor_make_draggable(id){
jQuery('#' + id).draggable({
cursor: 'move',
cursorAt: { top: 56, left: 56 },
containment: '#myid_templates_editor_canvas',
});
}
See images below:
I have made a line between 2 draggable divs using jsPlumb.
var jsPlumb_instance = jsPlumb.getInstance();
var endpointOptions = {
anchor:'BottomCenter',
maxConnections:1,
endpoint:['Rectangle',{width:'0px', height:'0px' }],
paintStyle:{fillStyle:'black'},
connectorStyle : { lineWidth: '1px' , strokeStyle: 'black' },
connector : ['Straight'],
setDragAllowedWhenFull:true,
};
div1Endpoint = jsPlumb_instance.addEndpoint('div1', endpointOptions);
div2Endpoint = jsPlumb_instance.addEndpoint('div2', endpointOptions);
jsPlumb_instance.connect({
source:div1Endpoint,
target:div2Endpoint,
});
jsPlumb_instance.draggable('div1');
jsPlumb_instance.draggable('div2');
I dont want the line outside the canvas border. See 3rd picture.
I want the line to be contained within the canvas with an id myid_templates_editor_canvas.See the image below:
I tried changing part of the code above with the the code below, with no luck.
jsPlumb_instance[id].draggable(id1, {containment:'#myid_templates_editor_canvas'});
jsPlumb_instance[id].draggable(id2 , {containment:'#myid_templates_editor_canvas'});
Yes, the two points was somehow constrained because the length of the maximum line was limited but still goes out of the border of the canvas.Below is the html set-up of the canvas and two points.
<table>
<tr>
<td>
<canvas id="myid_templates_editor_canvas"></canvas>
<div id="div1"></div>
<div id="div2"></div>
</td>
</tr>
</table>

I worked with jsPlumb for quite long already and I remembered it need to refer to a lot of library.
Because jsPlumb using draggable feature from jQuery UI, you can read this article for understanding how it is being worked.
https://jqueryui.com/draggable/#constrain-movement
In your case, myid_templates_editor_canvas will not be consider as the containment, it is for drawing only. So I suggest you to modify your html as below try, let me know your result as well.
I put an ID for table element and it will be the containment for 2 end points. The containment must be an element that contains child element - in the other words - parent element.
myid_templates_editor_make_draggable('div1');
myid_templates_editor_make_draggable('div2');
// Make an element draggable within the canvas
function myid_templates_editor_make_draggable(id){
jQuery('#' + id).draggable({
cursor: 'move',
cursorAt: { top: 56, left: 56 },
containment: '#main-container',
});
}
<table id="main-container">
<tr>
<td>
<canvas id="myid_templates_editor_canvas"></canvas>
<div id="div1"></div>
<div id="div2"></div>
</td>
</tr>
</table>

Actually you can set containment via jsPlumb. See my jsFiddle. The reason why your solution did not work is that you have set draggable via jsPlumb, not jQuery. They do not know about it other, so can not work together. You need to provide options to draggable function:
jsPlumb_instance.draggable(element, { containment:true });
To know more about draggable in jsPlumb see help. You can set containment container explicitly when you get instance of jsPlumb:
var jsPlumb_instance = jsPlumb.getInstance({ Container:"inner" });
You can also specify DragOptions and DropOptions if you need (more info).
It is better to set draggable via jsPlumb, as a plus, then no need to call repaint after dragging is finished. A huge performance benefit with a lot of elements.
A common feature of interfaces using jsPlumb is that the elements are
draggable. You should use the draggable method on a jsPlumbInstance to
configure this:
myInstanceOfJsPlumb.draggable("elementId");
...because if you don't, jsPlumb won't know that an element has been
dragged, and it won't repaint the element.

I had made a solution to my problem. I changed my code above to to code below:
myid_templates_editor_make_draggable('div1');
myid_templates_editor_make_draggable('div2');
//Make an element draggable within the canvas
function myid_templates_editor_make_draggable(id){
jQuery('#' + id).draggable({
cursor: 'move',
cursorAt: { top: 56, left: 56 },
containment: '#myid_templates_editor_canvas',
drag: function(e, ui){
jsPlumb_instance.repaintEverything();
},
});
}
I had also omit the line of code that make JsPlumb two endpoints draggable.
var jsPlumb_instance = jsPlumb.getInstance();
var endpointOptions = {
anchor:'BottomCenter',
maxConnections:1,
endpoint:['Rectangle',{width:'0px', height:'0px' }],
paintStyle:{fillStyle:'black'},
connectorStyle : { lineWidth: '1px' , strokeStyle: 'black' },
connector : ['Straight'],
setDragAllowedWhenFull:true,
};
div1Endpoint = jsPlumb_instance.addEndpoint('div1', endpointOptions);
div2Endpoint = jsPlumb_instance.addEndpoint('div2', endpointOptions);
jsPlumb_instance.connect({
source:div1Endpoint,
target:div2Endpoint,
});
Hope it helps everyone that is going through the same problem with me.

Related

Reusing SVG.js code for various SVG's

I'm getting to grips with SVG.js
I have a pattern effect that I've created and would like to use in a number of SVG's.
I can create it in one SVG with the following code...
$( document ).ready(function() {
var draw = SVG('geo').size(1200, 1700);
// 100 lines of js creating geometric pattern, effectively this...
var rect = draw.polygon(coordinates).fill('#fff').stroke({ width: 1, color:'#fff'}).opacity(0)
});
This creates an SVG with ID geo. But I'd like to use this code again to generate various SVG's, ideally with different options (colour etc).
SVG('geo') refers to a particular SVG, how do I make it so I can apply this to any SVG I want on the page?
Hope that made sense
You can define a function that does this repeatedly. Something like the following:
function create_svg(dom_id, width, height, coord) {
var draw = SVG(dom_id).size(width, height);
var rect = draw.polygon(coord)
.fill('#fff')
.stroke({
width: 1,
color: '#fff'
})
.opacity(0);
}
$(function() {
create_svg('geo', 1200, 1700, coordinates);
create_svg('geo2', 1000, 1500, other_coordinates);
)};
If you need to use the created SVGs further, later on in the code, you could make the create_svg function return the created SVG object to a variable in your document.ready function.

jQuery Hide Class

I have a web page that is loading images and scans across about 600+ images as the user presses next or previous. This is working fine. However, the image load time is slow so the idea is to put a processing while in place of the images until they are fully loaded. I can get the processing wheel to load perfectly fine but I cannot get it to hide once the image or document is loaded. I have tried doing this two different ways:
Attempt 1:
$('#centerImage').ready(function () {
$('.spinner').css('display', 'none');
});
Attempt 2:
$('#centerImage').ready(function () {
$('.spinner').hide();
});
I have also tried replacing the selector #centerImage on the .ready() function with document but still don't see the Processing Wheel get hidden.
What I find strange is that when I try and hide an ID instead of a Class, it works perfectly fine. I tried a 'Try Me' on W3 Schools with a simple example and hiding a class with the .hide() doesn't work there either.
Google isn't returning anything specific to any limitations with jQuery hiding classes. Is this possible or am I approaching this the wrong way?
NOTE: I'm using spin.js for the processing wheel.
All Code:
JavaScript:
EDIT: Added .load instead of .ready
var previousImage = document.getElementById("previousImage");
var centerImage = document.getElementById("centerImage");
var nextImage = document.getElementById("nextImage");
previousImage.setAttribute("src", "../.." + document.getElementById("MainContent_lblPreviousImage").innerHTML);
centerImage.setAttribute("src", "../.." + document.getElementById("MainContent_lblCenterImage").innerHTML);
nextImage.setAttribute("src", "../.." + document.getElementById("MainContent_lblNextImage").innerHTML);
$('#centerImage').load(function () {
$('.spinner').hide();
});
HTML/ASP.NET:
<div id="images">
<img id="previousImage" onload="showProgress()" alt="" src=""/>
<img id="centerImage" onload="showProgress()" alt="" src=""/>
<img id="nextImage" onload="showProgress()" alt="" src=""/>
</div>
Show Progress JavaScript File:
function showProgress () {
var opts = {
lines: 13, // The number of lines to draw
length: 20, // The length of each line
width: 10, // The line thickness
radius: 30, // The radius of the inner circle
corners: 1, // Corner roundness (0..1)
rotate: 0, // The rotation offset
direction: 1, // 1: clockwise, -1: counterclockwise
color: '#000', // #rgb or #rrggbb or array of colors
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false, // Whether to use hardware acceleration
className: 'spinner', // The CSS class to assign to the spinner
zIndex: 2e9, // The z-index (defaults to 2000000000)
top: '50%', // Top position relative to parent
left: '50%' // Left position relative to parent
};
var target = document.getElementById('images');
var spinner = new Spinner(opts).spin(target);
}
Thanks in advance for any helpful input.
As #Barmar $("#centerimage").ready() is the same as $(document).ready(). There's no separate ready event for each element, it just applies to the whole DOM.
Ready is used to check if the DOM is ready and the load is used to check if the Content is loaded.
Use load instead of ready:
$('#centerImage').load(function () {

Setting Fancybox2 width/height dynamically

I am trying to use fancybox v2 to show a div whose contents are generated dynamically. I set the size of the div quite late in the scheme of things. I have tried the examples from fancybox's documentation for displaying divs whose size is fixed. It looks like this:
<a id="fancy" href="#showdiv">Show contents of div.</a>
<div id="showdiv">...</div>
<script>
$(document).ready(function() {
$("#fancy").fancybox({autoSize:false, width: W, height: H, ...});
});
</script>
What I want is W=$("#showdiv").width and H=$("#showdiv").height. Obviously, H and W are not available to me at document ready. How do I go about doing this?
EDIT: Here is the html for the content div:
<div id="hidediv" style="display:none">
<div id="showdiv" style="display:block;position:relative">
<canvas id="mycanvas" style="position:relative;display:block"></canvas>
</div>
</div>
In a click handler of the anchor "#fancy" I do:
function onclick() {
var jcanvas = $("#mycanvas").css('width', some_width).css('height', some_height);
// draw on canvas
}
"#fancy" is the one associated with Fancybox.
Assuming that this function handles the response of your HTTP POST
function onclick() {
// set size of canvas
var jcanvas = $("#mycanvas").css({
"width": some_width, // variable from response ?
"height": some_height
});
// draw on canvas
}
... then call that function using the fancybox afterLoad callback like
$("#fancy").fancybox({
fitToView: false, // the box won't be scaled to fit the view port (optional)
afterLoad: onclick()
});
EDIT :
Another option is to handle both, the canvas and fancybox within the same function using jQuery .on() so if you have
<a id="fancy" href="#showdiv">Show contents of div</a>
use this script :
$("#fancy").on("click", function () {
// do HTTP POST
// on success, get size form response
var some_width = 300,
some_height = 180;
// set canvas size
var jcanvas = $("#mycanvas").css({
// variables from response
"width": some_width,
"height": some_height
});
// draw on canvas
//
// then open fancybox ($(this) = #showdiv )
$.fancybox($(this),{
// API options etc
fitToView: false
});
});
in this case you don't need any callback.
NOTE : .on() requires jQuery v1.7+
See JSFIDDLE for documentation purposes.

Drag and drop SVGs with Raphael JS

Looking for some advice (example would be great) on dragging and dropping SVGs using RaphaelJS.
I have found how to drag an object created withint Raphael
window.onload = function() {
var R = Raphael("canvas", 500, 500);
var c = R.circle(100, 100, 50).attr({
fill: "hsb(.8, 1, 1)",
stroke: "none",
opacity: .5
});
var start = function () {
...
},
move = function (dx, dy) {
...
},
up = function () {
...
};
c.drag(move, start, up);
};​
But I need to be able to adapt this to work with a seperate SVG file(s) so for example
myPage.html has myImage.svg, I need to be able to drag myImage.svg around the 'canvas'.
I'm thinking something like
var c = R.SOMEMETHOD('myImage.svg');
...
c.drag(move, start, up);
For example.
Is there a way to do this and if so, an example would be brilliant!
This magic method doesn't exist in RaphaelJS. But there is a way to accomplish this. You can have a look at the raphael-svg-import project on GitHub which works well for basic svgs
Then, you'll want to use a grouping facility as you cannot use the Set functionnality of RaphaelJS
1 - import your SVG
2 - As you import, mark the elements so they belong to the same group
Enjoy !!

Extjs Ext.ComboBox autosize over existing content

I have a problem when apply an Ext.ComboBox over an existing html select item, even if the existing content makes the html select about 20px (by it's content non static width is set), the Ext.ComboBox will resize to a sort of default, large, width value.
There's a way to auto resize the Ext.ComboBox based on the existing items and no using the default width?
Even if I know which best tool Ext is, this issue will let my colleagues to discard Extjs.
Thanks in advance
You can't technically make a combo "auto width" -- Ext actually converts the <select> into a regular <input> behind the scenes, and <input> elements have to have a width/size specified. However, you can trick Ext into sizing the combo based on the existing <select> which should give you the same end result. Here's an example from the Ext combo demo page, where I have modified the width config value:
var converted = new Ext.form.ComboBox({
typeAhead: true,
triggerAction: 'all',
transform:'state',
width: Ext.fly('state').getWidth(),
forceSelection:true
});
The obvious caveat would be that if you subsequently modify the list after it's rendered, the combo will not resize itself automatically and you'd have to figure out a way to resize it yourself.
Use this code:
Ext.ux.ResizableComboBox = Ext.extend(Ext.form.ComboBox, {
initComponent: function(){
Ext.ux.ResizableComboBox.superclass.initComponent.call(this);
this.on('render', this.resizeToFitContent, this);
},
resizeToFitContent: function(){
if (!this.elMetrics){
this.elMetrics = Ext.util.TextMetrics.createInstance(this.getEl());
}
var m = this.elMetrics, width = 0, el = this.el, s = this.getSize();
this.store.each(function (r) {
var text = r.get(this.displayField);
width = Math.max(width, m.getWidth(text));
}, this);
if (el) {
width += el.getBorderWidth('lr');
width += el.getPadding('lr');
}
if (this.trigger) {
width += this.trigger.getWidth();
}
s.width = width;
this.setSize(s);
this.store.on({
'datachange': this.resizeToFitContent,
'add': this.resizeToFitContent,
'remove': this.resizeToFitContent,
'load': this.resizeToFitContent,
'update': this.resizeToFitContent,
buffer: 10,
scope: this
});
}
});Ext.reg('resizable-combo', Ext.ux.ResizableComboBox);
In addition to what bmoeskau suggests, you can use an xtemplate for your combo's items. This will give you the ability to change the look of the item. You can wrap text, add images, etc.
add a listener to the afterrender event and set the width if the list (the div that drops down ) to auto e.g.
afterrender: function(combo){
combo.list.setSize('auto', 0);
combo.innerList.setSize('auto', 0);
}
The reason I am using afterrender and not render is because if you set lazyInit to false it will set the list width, so in afterrender you override that setWidth
I'm pretty sure you can get ExtJs to render whatever html items you need to, in the way you want them to be rendered.
here's some code from the Examples/Form/Combos.js file:
var converted = new Ext.form.ComboBox({
typeAhead: true,
triggerAction: 'all',
transform:'state',
width:20, //<-- set this config value!
forceSelection:true
});
in the code that you're using to transform the combo, just specify a width for the ExtJs combo.

Categories

Resources