How to avoid jsPlumb connectors break off while dragging the dynamically created divs - connector

I am new to jsPlumb. I have created dynamic divs by reading a table from database and I have connected these divs by using JsPlumb connectors. The divs have been made draggable. The connectors are showing up correctly when the page loads, but when I drag or move the divs the connectors breaks off and moved to top. If I create a static divs which are not coming from database then the connectors are working perfectly and when I drag/move the divs then the connectors are also moving along the divs connected to source and target divs.
After doing a complete search on google and by going through jsPlumb documents, I did not find any solution for this.
Can anyone tell me as what should be done to have the connectors stay connected to source and destination even when we drag or move the divs.
Here is what I have done:
JsPlumb Code for one connection:
jsPlumb.ready(function() {
jsPlumb.connect({
source: "FDiv1",
target: "IDiv1",
connector: ["Flowchart"],
anchors: ["RightMiddle", "LeftMiddle"],
paintStyle: {
lineWidth: 2,
strokeStyle: "rgb(189, 11, 50)",
outlineColor: "#666",
outlineWidth: 1
},
hoverPaintStyle: { strokeStyle: "#7ec3d9" },
detachable: false,
endpoint: "Blank",
endpointsOnTop: false,
deleteEndpointsOnDetach: false,
endpointStyle: { fillStyle: "#a7b04b" },
overlays: [ "Arrow" ]
});
jsPlumb.draggable($(".bg"));
});
I have hardcoded the source and target here which later I should be getting these dynamically to connect all other divs.
Here is the dynamic divs code in code behind.
foreach (DataRow dt in ds.Tables[0].Rows)
{
HtmlGenericControl myDiv = new HtmlGenericControl("div");
HtmlGenericControl myDiv2 = new HtmlGenericControl("div");
//********Source Div**************
myDiv.ID = "FDiv" + j;
myDiv.Attributes.Add("class", "bg");
myDiv.Style.Add(HtmlTextWriterStyle.MarginLeft, "30px");
myDiv.Style.Add(HtmlTextWriterStyle.MarginTop, top + "px");
myDiv.InnerHtml = "Filename: " + dt["Column1"].ToString() + "<br>" + myDiv.ID;
PlaceHolder1.Controls.Add(myDiv);
//************Target Div****************
myDiv2.ID = "IDiv" + j;
myDiv2.Attributes.Add("class", "bg");
myDiv2.Style.Add(HtmlTextWriterStyle.MarginLeft, "260px");
myDiv2.Style.Add(HtmlTextWriterStyle.MarginTop, top + "px");
myDiv2.InnerHtml = "Filename: " + dt["Column2"].ToString() + "<br>" + myDiv2.ID;
PlaceHolder1.Controls.Add(myDiv2);
top = top + 140;
j = j + 1;
}

Instead of making the DIV draggable as jsPlumb.draggable($(".bg"));
Try making the DIV draggable during its creation.
i.e.
Source Div
myDiv.ID = "FDiv" + j;
myDiv.Attributes.Add("class", "bg");
myDiv.Style.Add(HtmlTextWriterStyle.MarginLeft, "30px");
myDiv.Style.Add(HtmlTextWriterStyle.MarginTop, top + "px");
myDiv.InnerHtml = "Filename: " + dt["Column1"].ToString() + "<br>" + myDiv.ID;
jsPlumb.draggable($('#FDiv' + j)); // make it draggable
PlaceHolder1.Controls.Add(myDiv);
`
||y for target DIV

I had a similar issue with dynamically created divs and solved it by not using jsPlumb.draggable(element) but instead jQuery and jsPumb.repaint(element) as follows (the example is a bit overkill with the use of repaint but you get the picture):
element.draggable({
step: function () {
jsPlumb.repaint(element);
},
drag:function(){
jsPlumb.repaint(element);
},
stop:function(){
jsPlumb.repaint(element);
}
});
Hope this helps you.

Related

What code will force a reselection in TinyMCE 4.6?

I'm having a problem with TinyMCE 4.6. I've implemented a custom button that bumps the font size of selected text:
ed.addButton('finc', {
image: '/tinymce/plugins/zackel/button_images/big.png',
title: '+ font size',
id : 'finc',
onclick:function(editor,url) {
console.log("************ In finc: ", ed);
var delta;
var currentFontSize = new Number($(ed.selection.getNode()).css('font-size').replace('px',''));
console.log("************ finc: currentFontSize = " + currentFontSize);
var node = ed.selection.getNode(); // <======= LINE 565
var nodeName = node.nodeName; // for example 'DIV ' or 'P'
console.log("************ finc: node is ", node, "nodeName = " + nodeName);
if (currentFontSize >= 24) {
delta = 2;
}
else {
delta = 1;
}
currentFontSize = currentFontSize + delta;
console.log("************ finc: New font size = " + currentFontSize);
ed.formatter.register('incfont', {
inline : 'span',
styles : {'font-size' : currentFontSize + 'px'}
});
ed.formatter.apply('incfont');
console.log("********** finc: posting to val box " + currentFontSize);
$("div#px_val button").text(currentFontSize + 'px'); // show value in value box
}
});
If the text is initially in a P the button works fine but puts the text into a span inside the P when it's done. If I then just hit the button again it fails because the node it brings back on line 565 is still the P, which still has the original font size. So if he initial font size is 16, it goes to 17 but then every bump after that stays at 17. If I deselect the text after bumping it and reselect it, line 565 gets the span and the bumps work every time.
How can I force a reselection from my code, so 565 finds the span the second time instead of the P, without me deselecting and reselecting the text?
Thanks
It seems to me that I understand you problem, but i believe that the text re-selection should not happen every time you apply the formatting - just only in the case TinyMCE is adding the new SPAN.
Here is my proposal:
var delta;
var currentFontSize = new Number($(ed.selection.getNode()).css('font-size').replace('px',''));
var node = ed.selection.getNode();
var nodeName = node.nodeName; // for example 'DIV ' or 'P'
if (currentFontSize >= 24) {
delta = 2;
}
else {
delta = 1;
}
currentFontSize = currentFontSize + delta;
ed.formatter.register('incfont', {
inline : 'span',
styles : {'font-size' : currentFontSize + 'px'}
});
var cnt = ed.selection.getContent({format : 'html'});
var lenBefore = $(cnt).length;
ed.formatter.apply('incfont');
var cnt = ed.selection.getContent({format : 'html'});
var lenAfter = $(cnt).length;
if(lenAfter > lenBefore) {
var newText = ed.selection.selectedRange.startContainer;
var rng = ed.dom.createRng();
rng.setStart(newText, 0);
rng.setEnd(newText, newText.nodeValue.length);
ed.selection.setRng(rng);
ed.nodeChanged();
}
Explanation:
when you apply the formatter for the first time, TinyMCE is adding the SPAN and you will find the new selection inside the ed.selection.selectedRange.startContainer node of type text. This is the same as the first child node of type text of the newly inserted SPAN. For subsequent actions, there shall be no need to do any re-selection.
Moreover, IMHO i feel somehow unusual to change the font size in mouse click, i would prefer a standard plugin button which works only with a already existing text selection (but this is up to you):
Of course, the main question of the re-selection is solved, and the plugin will work repeatedly with subsequent mouse clicks also by using a plugin button.
Just in case, as said before, you may also check at the very top if there is any content:
var hasContent = ed.selection.getContent({format : 'text'}.length > 0);
if(!hasContent) return;
So i believe the whole stuff should do the job but anyway, i feel there is still room for some improvements, for example if you need also to reduce the font size, and thus you will also need to delete the already existing - but no longer necessary - SPAN which contain the formatting.

How to move CSS background based on cursor/finger position without using background-position property?

I'm working on a small app where the user move the background with his mouse or his finger on the screen.
You can find a demo here: http://kaleidoscope-experiment.herokuapp.com/
The background-position is defined by the position of the cursor/finger using this kind of code:
// mobile
position = e.touches[0].pageX + 'px ' + e.touches[0].pageY + 'px';
// desktop
position = e.pageX + 'px ' + e.pageY + 'px';
However, I have significant lags on mobile and tablet and the background is "clipping".
Do you know if there is any alternative to background-position (transform?), to move the background based on the cursor/mouse position?
If you want to roll your own just use a combination of the jQuery mousemove function in combination with CSS3 transforms. Something along the lines of this:
$( "#target" ).mousemove(function( event ) {
var msg = "Handler for .mousemove() called at ";
msg += event.pageX + ", " + event.pageY;
console.log( "<div>" + msg + "</div>" );
$("#movingobject").css('transform', 'translate(' + event.pageY /4 + 'px,' + -event.pageX /4+ 'px)');
});
Here is the reference fiddle that i got from stackoverflow
http://jsfiddle.net/ZmZhw/
There are number of js plugin that are available which will give u some smooth transition and performance also.

How to move popup div along with marker in leaflet

I have a map drawn using leaflet. In that map I have drawn several markers at different locations. On clicking the marker I am creating a popup div that shows some message.
I have the code:
markers.on("click", function(d) {
div.html("This is Some info").style(
"left", (d3.event.pageX) + "px").style(
"top", (d3.event.pageY - 80) + "px");
}
So the div appears in the location where I clicked i.e. at the location of the marker.
Now if I drag the map the markers move along with the map but the div remains at the same location.
How can I change the style of div with drag event so that the div also moves along with marker?
I was trying the following code in the drag event method:
if(d.code==clickedcode)
{
console.log((map.latLngToLayerPoint([ d.lat, d.lon ]).x) + "px , "
+(map.latLngToLayerPoint([ d.lat, d.lon ]).y - 80) + "px");
div.style["left"]=(map.latLngToLayerPoint([ d.lat, d.lon ]).x) + "px";
div.style["top"]=(map.latLngToLayerPoint([ d.lat, d.lon ]).y - 80) + "px";
}
But it still shows the same pixel position as previous time.
You could try using the map 'drag' event to calculate the shift and then apply that to your div location. Something along these lines...
var startCoords;
var startLat;
var startLng;
var movedCoords;
var shiftLat;
var shiftLng;
map.on('dragstart', function() {
startCoords = map.getCenter();
startLat = startCoords.lat;
startLng = startCoords.lng;
console.log("STARTED FROM: " + startLat + "," +startLng);
});
map.on('drag', function() {
movedCoords = map.getCenter();
shiftLat = startLat - movedCoords.lat;
shiftLng = startLng - movedCoords.lng;
console.log("Shifted: " + shiftLat + "," + shiftLng);
//apply shift to custom div here...
});

Auto fit tag clouds in a div

I have some tag clouds placed within a div. For each tag cloud there is a thumbs down icon and I used sliding tag css from http://www.cssflow.com/snippets/sliding-tags
If a tag cloud is greater than 80px, it does not fit inside that div. I used word wrap and also fittext plugin from jquery but I could not manage to make it work. Could you suggest what could be the possible solution for it?
I have created fiddle for it: http://jsfiddle.net/aexqoe8n/1/
In Js side :
resultDiv = document.getElementById('tokenCloudResultDiv');
resultDiv.innerHTML = '';
resultDiv .innerHTML="<ul class='tags blue' style='list-style-type: none;padding:5px;'>";
for (i in json) {
addToken(resultDiv, i, json[i]);
}
resultDiv.innerHTML=resultDiv.innerHTML+"</ul>";
function addToken(target, key, result) {
var str;
var weight;
if(result['tagWeight']>80)
$("#tokenCloudResultDiv").fitText(1.2);
weight= "style='font-size: " + result['tagWeight'] + "px;'";
if(addedAutomatically)
str = "<li><div><a " + weight + " >" + result['tagName'] +"</a><span class='thumbsDownIcon' id ='" + tagId + "' style='display:block;cursor:pointer;' ></span></div></li>";
target.innerHTML += str;
}

adding tooltip to datagrid headers in dojo

I have a dojo datagrid which is poulated dynamically. I want to add tooltip to table headers of this datagrid. How can i do that?My datagrid simply has the structure of table and table headers. the fields get populated dynamically.
Thanks,
Sreenivas
Easiest Way
The easiest way, (Without overriding the template) would be to add a domNode to your layout header definition. So for example, when you are setting the "name" for your column in the layout, you can have something like ...
var layout = [
{
cells: [
{
name:"<i id="sometooltip" class='icon-large icon-edit'></i> Col",
field: "_item",
formatter: lang.hitch( this, this.formatter )
}
]
}];
What you then want to do is in your formatter, you want to check to see if "sometooltip" has be initialized as a tooltip, and do your connect.. You can use any tooltip.. not just dijit.Tooltip.
There are a few words of caution though. Because the formatter will run every time there is a redraw on your grid, you might want to think up better ways of creating your tooltip. For instance, you might want to add it to onGridRowHeaderHover, or you might want to just use CSS3 and use [title] attribute to create a CSS3 header.
Also. You can't just create the tooltip once, because the header is constantly rebuilt every redraw/change of data.
The Correct Way
The correct way would be to override the Grid template for the header, and include your tooltip in there. You would then extend the header equivalent of onStyleRow (which I can't remember), but basically the method that places the headers, and create your tooltip then.
I would definitely use the second option by overriding the template. Because otherwise you will find the grid glitchy.
For a pre-AMD Dojo version this is the monkey patch that we included in our globally scoped javascript resource. My other answer was after we switched to an AMD Dojo version.
// HeaderBuilder.generateHtml
// If showTooltips is true, the header contents will be used as the tooltip text.
var old_HeaderBuilder_generateHtml = dojox.grid._HeaderBuilder.prototype.generateHtml;
dojox.grid._HeaderBuilder.prototype.generateHtml = function(inGetValue, inValue){
var html = this.getTableArray(), cells = this.view.structure.cells;
dojox.grid.util.fire(this.view, "onBeforeRow", [-1, cells]);
for(var j=0, row; (row=cells[j]); j++){
if(row.hidden){
continue;
}
html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
for(var i=0, cell, markup; (cell=row[i]); i++){
cell.customClasses = [];
cell.customStyles = [];
if(this.view.simpleStructure){
if(cell.headerClasses){
if(cell.headerClasses.indexOf('dojoDndItem') == -1){
cell.headerClasses += ' dojoDndItem';
}
}else{
cell.headerClasses = 'dojoDndItem';
}
if(cell.attrs){
if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
}
}else{
cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
}
}
markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
// content
markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
// set the tooltip for this header to the same name as the header itself
try {
markup[5] = markup[5].replace("class","title='"+cell.name+"' class");
} catch(e) {
console.debug(e);
}
// styles
markup[3] = cell.customStyles.join(';');
// classes
markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
html.push(markup.join(''));
}
html.push('</tr>');
}
html.push('</table>');
return html.join('');
};
I had a similar requirement. I wanted each DataGrid column header to use the name given to the column as the tooltip since our DataGrids weren't always showing the full column name due to the columns' widths sometimes being squeezed. I added a monkey patch (below) that is done with an AMD Dojo version:
require(
[
"dojo/dom",
"dojox/grid/DataGrid",
"dijit/_Widget",
"dijit/form/FilteringSelect",
"dijit/form/MultiSelect",
"dijit/layout/ContentPane",
"dijit/layout/TabContainer",
"dojox/grid/_Grid",
"dijit/MenuItem",
"dijit/MenuSeparator",
"dojox/grid/_Builder",
"dojox/grid/cells/_base",
"dojox/grid/util",
"dojo/parser",
"dojo/_base/array",
"dojo/_base/lang",
"dojo/ready",
"dojo/query",
"dijit/registry",
],
function(dom, dojox_grid_DataGrid, dijit__Widget, dijit_form_FilteringSelect,
dijit_form_MultiSelect, dijit_layout_ContentPane, dijit_layout_TabContainer,
dojox_grid__Grid, MenuItem, MenuSeparator, dojox_grid__Builder,
dojox_grid_cells__Base, dojox_grid_util,
parser, array, dojoLang, ready, dojoQuery, registry) {
var old_HeaderBuilder_generateHtml = dojox_grid__Builder._HeaderBuilder.prototype.generateHtml;
dojox_grid__Builder._HeaderBuilder.prototype.generateHtml = function(inGetValue, inValue){
var html = this.getTableArray(), cells = this.view.structure.cells;
dojox_grid_util.fire(this.view, "onBeforeRow", [-1, cells]);
for(var j=0, row; (row=cells[j]); j++){
if(row.hidden){
continue;
}
html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
for(var i=0, cell, markup; (cell=row[i]); i++){
cell.customClasses = [];
cell.customStyles = [];
if(this.view.simpleStructure){
if(cell.headerClasses){
if(cell.headerClasses.indexOf('dojoDndItem') == -1){
cell.headerClasses += ' dojoDndItem';
}
}else{
cell.headerClasses = 'dojoDndItem';
}
if(cell.attrs){
if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
}
}else{
cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
}
}
markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
// content
markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
// set the tooltip for this header to the same name as the header itself
markup[5] = markup[5].replace("class","title='"+cell.name+"' class");
// styles
markup[3] = cell.customStyles.join(';');
// classes
markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
html.push(markup.join(''));
}
html.push('</tr>');
}
html.push('</table>');
return html.join('');
};
}
);
Note that if there's any chance that any markup may be added to the cell.name then you'll need to add a condition that will somehow extract just the text from it to be the tooltip, or somehow generate a tooltip that won't throw a rendering error, or avoid setting a tooltip altogether for that column.

Resources