Have a draggable item in jsPlumb which is made of multiple items - jsplumb

I'd like to create a single draggable item in jsPlumb which is actually composed of multiple items: a "main item" which has an anchor which is a connection target (isTarget: true), and multiple "sub items" which display stacked up, each of which has an anchor which is a connection source. Something like this:
Subthings should always be presented in the way above; they aren't draggable around inside the item, nor are they draggable to other items. Dragging anywhere on the main item or any subitem drags the whole group around from place to place.
Am I best to model this as separate things in a jsPlumb.Group, or is this really all just one "wrapper" div with many divs inside it? If it's the latter, how do I add anchors to the main and subitems within the wrapper, if it's the wrapper that I tell jsPlumb about?

As far as I can tell, this Just Works.
const a = document.createElement("article");
const d = document.createElement("div");
const p = document.createElement("p");
a.appendChild(d);
a.appendChild(p);
pane.appendChild(a);
jsPlumb.draggable(a);
var endpoint1 = jsPlumb.addEndpoint(d, { isTarget:true, anchors: ["Top"] });
var endpoint2 = jsPlumb.addEndpoint(p, { isSource:true, anchors: ["Right"] });
Create a "wrapper" (here a, an article), and mark it draggable; append subitems to it, and add Endpoints to them; everything works. Done.

Related

Scroll one page to the right in Cypress

How could I scroll one page to the right in Cypress?
E.g. I have a horizontally scrollable area. The area contains elements a, b and if I scroll to the right a and b get destroyed, while c and d get added.
My attempt is to find out the width of the scrollable view and then scroll that amount to the right. But the width does not get retrieved before the scrollTo gets called.
Here is what I am trying to do:
const width = cy.getCy("scroll-viewport").invoke("width");
cy.getCy("scroll-viewport").scrollTo(width, 0);
Your code sample has some mystery about it, for example what is cy.getCy().
I can show you how to do it with standard code, and you can adapt from there.
Assuming scroll-viewport is a selector for the scroll container (the owner of the scroll bar)
cy.get("scroll-viewport").then($scrollContainer => {
const width = $scrollContainer[0].offsetWidth;
$scrollContainer[0].scrollTo(width, 0);
})
Note $scrollContainer[0].scrollWidth gives you the total width after scrolling, in case you need that.

Plotly.js, show tooltips outside of chart container

I need to implement a plotly.js chart on a page with a very restricted width. As a result, a tooltip is partially cut. Is it possible to cause tooltip not to be limited by plotly.js container size?
My code example at codepen: https://codepen.io/anatoly314/pen/gOavXzZ?editors=1111
//my single trace defined as following but it's better to see example at codepen
const yValue1 = [1000];
const trace1 = {
x: [1],
y: yValue1,
name: `Model 1`,
text: yValue1.map(value => Math.abs(value)),
type: 'bar',
textposition: 'outside'
};
It is, by design, not possible for any part of the chart to overflow its container.
I would say it is wrong to say that by design this is not possible! It is a bit hacky, but when you add the following lines, it shows the label outside of svg:
svg.main-svg,svg.main-svg *
{
overflow:visible !important;
}
The answer given by rokdd works. However the css selector should be more specific, otherwise it's natural that you will introduce subtle bugs (particularly if you need to scroll the content where the plotly chart is contained).
If we look at the DOM tree constructed by Plotly, we find that the tooltips are created inside the <g class="hoverlayer"></g> element (which is a direct child of one of the three <svg class="main-svg"></svg>). So that parent (that svg.main-svg element) is only one that needs to affected.
The ideal css selector in this case would be the :has selector. However it's still not supported (as of 2022): https://css-tricks.com/the-css-has-selector/
So the next simplest thing is to use a little bit of javascript right after we call Plotly.newPlot:
// get the correct svg element
var mainSvgEl = document.querySelector('#positive g.hoverlayer').parentElement;
mainSvgEl.style['overflow'] = 'visible';
Or in a more generic way (works for any chart):
Array.from(document.querySelectorAll('g.hoverlayer')).forEach(hoverEl => {
let mainSvgEl = hoverEl.parentElement;
mainSvgEl.style['overflow'] = 'visible';
});

Positioning multiple fixed sticky elements with Waypoints

I'm using Waypoints and their Sticky shortcut to 'stick' an element with the id stick-this to the top of the viewport once it gets scrolled past. I am having some difficulty positioning the element past another fixed element on the screen, however.
There is a <div> with a class .header which always remains fixed. I am trying to position the top of the new element to the height() of the .header element so they are 'stacked' on top of one another and both visible. This is the code I am using to accomplish this:
var sticky = new Waypoint.Sticky({
element: $('#stick-this')[0],
handler: function() {
$(".stuck").css({ "top" : $(".header").height() });
}
})
So, essentially, once the #stick-this is scrolled past, it becomes sticky with a position:fixed class and the top is dynamically determined by the height() of .header.
This works great until I scroll back up, and the top style is still applied to this element, in spite of the stuck class not being applied anymore.
So when I scroll past, the element ends up like this
<div id="stick-this" class="stuck" style="top:70px /*or whatever the height() ends up being */">
and when I scroll back up the element ends up like this with the top property still in place
<div id="stick-this" class="" style="top:70px /*I need this back to 0px */">
Is it possible to have a function called when the "sticky" is removed, so that the inline style property can be set to top:0px or something like that?
For anyone else struggling with this, I ended up dynamically writing the CSS when the sticky element's class is initiated and inserting it into the head:
var sticky = new Waypoint.Sticky({
element: $('#stick-this')[0],
offset: $('.header').outerHeight(true),
handler: function(direction) {
$("<style>")
.prop("type", "text/css")
.html("\
.stuck {\
position: fixed;\
top:" + $(".header").height() + "px;\
}")
.appendTo("head");
}
})
so, the class will be added with the correct top positioning, and once the class is removed, the top property is inherently returned back to 0px.
It's important to have the \ after each line break in the .html() portion of this code in order for it to work.

How do I clone a Kinetic.node without its children?

I have a Kinetic.Stage and 2 layers: layer1 and layer2. I drag elements from layer1 to drop them in layer2, knowing that I made a design of a grid in layer2. I need to clone layer2 in its initial state, I mean without the shapes and images that have been drawn on it, just an empty grid.
document.getElementById('buttonAdd').addEventListener('click', function () {
var cloneLayer = layer2.clone({id: layer2.attrs.id + 1});
cloneLayer.draw();
stage.draw();
});
This code clones the whole thing: the layer and its children. What should I add, in order to remove children?
Things I tried and failed:
cloneLayer.destroyChildren();
var x = cloneLayer.getChildren();
x.hide();
"...just an empty grid". You can always create an empty grid with:
var newLayer=new Kinetic.Layer();
stage.add(newLayer);

How to turn a raw DOM element in to a D3 selection?

Scenario: I have several svg elements on a page, each displaying a different graph. When a graph receives a mouse click it triggers an event handler wherein this corresponds to the raw svg element that was clicked. When this happens, I want to select the graph's path element with D3 in order modify it.
I know that I could give each graph an ID and then use that to make a D3 selection, e.g.
function on_click( event ) {
var path = d3.select( '#' + this.id ).select( 'path' );
path.do_stuff...
}
but I wondered whether there was an equivalent of jQuery's feature of turning raw DOM elements in to a jQuery object, e.g.
jQuery( my_raw_dom_element ).do_stuff...
Yes, you can simply do
d3.select(my_raw_dom_element);

Resources