How to make a Cytoscape.js canvas respect its parent's position - javascript

I have a React component that renders a Cytoscape dagre graph once some data has been fetched from the server. It seems to render a canvas that takes up the right half of the parent <div id="cy" />. Calling cy.center() and cy.fit() centers and fits the graph itself to the parent div, but only half the visualisation is shown because the containing canvas is half off the screen.
Setting the following CSS:
position: absolute;
left: 0;
right: 0;
on the container, as in all the online examples, will center the canvas, but breaks the flow of the document. It also doesn't resolve the half size issue.
The JSX:
if (moduleStructure) {
return (
<div
id="cy-module-structure"
style={{
position: "absolute",
left: 0,
top: 0,
height: "500px",
width: "1500px",
display: "block",
}}
/>
);
}
The graph generation code. This is called by a React hook after the data has been fetched.
function generateGraph(nodes, edges) {
cytoscape.use(dagre);
const cy = cytoscape({
container: document.getElementById("cy-module-structure"),
boxSelectionEnabled: false,
autounselectify: true,
layout: {
name: "dagre",
nodeDimensionsIncludeLabels: true,
},
zoom: 1,
pan: { x: 0, y: 0 },
style: [
{
selector: "node",
style: {
content: "data(label)",
"text-valign": "center",
"text-halign": "center",
"background-color": "#11479e",
},
},
{
selector: "edge",
style: {
width: 4,
"target-arrow-shape": "triangle",
"line-color": "#9dbaea",
"target-arrow-color": "#9dbaea",
"curve-style": "bezier",
},
},
],
elements: {
nodes,
edges,
},
});
cy.ready(() => {
cy.center();
cy.fit();
cy.resize();
});
}
And finally the parent JSX:
<div className="top-flex"> // flex-direction: row:
<Diagram /> // Cytoscape component
<div className="basic-info">
<H3>TEXT</H3>
<small>INFO</small>
</div>
</div>
Ideally the graph should take up the full width of the parent div. In the screenshot, you can see the effect described above.

The problem is that a higher level style was applied text-align: center. Removing that should align things correctly.

(1) Your ordering of resize and fit is reversed. It doesn't make sense to fit if you're going to resize afterwards. Fitting happens on the available bounds.
(2) Make sure you mount Cytoscape only after componentDidMount().
(3) The container must be something like position:relative or position:absolute (definitely not position:static) such that the children of container can be positioned relative to container. Cytoscape.js will set position:relative by default, so it's sensibly set unless you override it.

Related

To resize and make the Violin chart of PotlyJS responsive

I want the violin chart (I'm using plotlyjs library) to be responsive. But also don't want it to compress so much (it is compressing according to the div it is kept in).
I have tried to turn the autosize property of violin to be false and then set the height and width. In this case the chart does not compress (stays the way I want it to be), but it loses its responsiveness. Is there a way to make this chart responsive yet no so compressed?
Here is my code:
<Plot
config = {{ displayModeBar: false }}
data={[
{
type: 'violin',
y: this.props.data,
points: 'none',
box: {
visible: true
},
boxpoints: false,
line: {
color: 'red'
},
opacity: 0.6,
meanline: {
visible: true
},
x0: "OEE"
}
]}
layout={{
title: "Comparison",
yaxis: {
zeroline: false
},
// autosize: false,
// height: 300,
// width: 500,
// responsive: true
}}
useResizeHandler= {true}
style= {{width: "100%", height: "100%"}}
/>
The div inside which violin is kept:
<div className="chart-wrapper" style={{ height: "35vh" }}>
<ViolinChart data={this.state.violinChartData} />
</div>
I got the solution to the above question.
PlotlyJS also provides a "margin" property for its charts. So providing margins will let you adjust the chart the way you want it to be
var layout = {
margin: {
l: 25,
r: 25,
b: 25,
t: 25
}
};
This is what i added to my code. Setting automargin = true will automatically increase the margin size.
More about this can be found here.

How to add slideWidth into a breakpoint in Glide.js

I have to set the slide width to a specific size if the viewport is between a range.
breakpoints: {
767: {
perView: 1,
peek: 193,
slideWidth: 277
},
1023: {
perView: 1,
peek: 212,
}
}
The documentation states that you can use slideWidth in the settings, so I'm assuming is in the breakpoints, but there's no example on how to do that and I haven't found an example of it.
The whole interface is responsive, so even if slideWidth is working behind the scenes, the width of the slide changes no matter what.
I also tried with pure CSS but Glide takes charge of course and overwrites when a resize event occurs. Also tried with pure JS and measuring the viewport myself, but again Glide.js takes charge and the interface is being offset, so the slide moves a bit and doesn't match the screen.
Here is a codepen on how to use the breakpoints https://codepen.io/tfoh/pen/zjqzZo
new Glide('#glide1', {
type: 'carousel',
perView: 3,
breakpoints: {
800: {
perView: 1
}
}
}).mount();
I manage that with css, this example make width of slides the same on any resolution, .glide-wrapper you should add manually like a glider parent div
.glide-wrapper {
max-width: 100vw;
overflow: hidden;
}
.glide {
max-width: 320px;
margin-left: auto;
margin-right: auto;
}
.glide__track {
overflow: visible!important;
}
const glide = new Glide('.glide', {
type: 'carousel',
breakpoints: {
1280: {
gap: 16,
focusAt: "center",
perView: 1,
peek: {
before: 16,
after: 16
},
},
}
}).mount({Swipe, Controls, Breakpoints });

Scroll blessed box with child elements

I have a blessed box that is set with scrollable: true
let outerBox = blessed.box({
top: '0%',
left: '0%',
width: '0%+6',
height: '100%',
scrollable: true,
tags: true,
padding: 1,
mouse: true,
style: {
fg: 'white',
bg: 'black'
}
});
Inside it I have many elements that I want to be clickable.
[array of many elements].forEach((elem, i) => {
let innerBox = blessed.box({
content: elem,
"height": "0%+1",
"top": "0%+"+i,
style: {
hover: {
bg: "black",
fg: "white"
}
}
});
innerBox.on("click", (data) => {
console.log("clicked",guild)
});
outerBox.append(server);
});
However if the elements have the style property set or listen for the click event handler, scrolling on them no longer scrolls the outer box. I have to scroll on the very edge of the box for it to actually scroll.
This works but I cannot detect clicks:
[array of many elements].forEach((elem, i) => {
let innerBox = blessed.box({
content: elem,
"height": "0%+1",
"top": "0%+"+i
});
outerBox.append(server);
});
How can I scroll the outer box with a mousewheel while still being able to detect clicks on the inner elements?
I solved this by using a List instead of a Box full of Boxes. A list is scrollable and can have selectable elements.

Accordion layout does not show the stacked closed panels at bottom

Usually an accordion panel will expand the first child panel and the rest panels' title will be stacked at the bottom. But for me there is no panels' title visible in the bottom. its just empty. See the screen shot.
But I am actually have 3 form panels there.
Ext.create('Ext.container.Viewport', {
layout: 'border',
items: [{
region: 'center',
html: '<h3>Some text. Lorem ipsom?</h3>'
},{
region: 'east',
layout: 'accordion',
width: 300,
items: [loginForm, regForm, passForm]
}]
});
Why is this? how do I fix this?
I am using Ext 4.0.7. Full source can be found here.
I hope in Accordion Layout you shoud not give height for a panel which you have given for loginForm.
height: 150,
This is caused by the header div element. Normally viewport is rendered to document.body. If it finds any existing element it can not replace it. Rather it appends the output. So what happened here is 2 components/elements are rendered. First the existing header div and then the viewport. The header div takes some space on top of the viewport. This same space is then get invisible on viewport on the bottom. To solve it, put the existing elements html as a panel in viewport. Keep its region to north.
Ext.create('Ext.container.Viewport', {
layout: 'border',
items: [{
region: 'north',
html: header.html // <------- Add html of `div#head` here
height: 300 // <------- put a height too.
},{
region: 'center',
html: '<h3>Some text. Lorem ipsom?</h3>'
},{
region: 'east',
layout: 'accordion',
width: 300,
items: [
loginForm, regForm, passForm
]
}]
});

How to adjust ExtJS window width according to its content?

I am using ExtJs.
Is there any way to adjust the width of the Ext.Window according to its items?
Height is automatically adjusted to 'auto' but width:'auto' expands it to full browser window.
var childPnl1 = { // 1
frame: true,
width: 350,
height: 50,
html: 'My First Child Panel',
title: 'First children are fun'
}
var childPnl2 = { // 2
width: 150,
html: 'Second child',
title: 'Second children have all the fun!'
}
new Ext.Window({
renderTo: Ext.getBody(),
items: [
childPnl1,
childPnl2,
{
title: '3rd',
width: 400, //Maximum
height: '150',
frame: true
}
]
});
Now I need a way so that the window adjusts its width to 400.
One way can be to iterate all the panels and then get the right most edge, but I want to avoid that.
Ofcourse it will expand to full browser window, why don't you use common variable for your
item-width and window-width? Also, it will give you guarantee that your window size neither be large or small than your item-width. Sometimes in different cases, autoWidth behaves different. So it is preferable to use manual width.

Categories