how to update dagreD3 node style without re-rendering graph - dagre-d3

Is there a way to change the style of a node without having to re-render the graph, like in the last code block below?
var g = new dagreD3.graphlib.Graph({compound:true})
.setGraph({}).setDefaultEdgeLabel(function() { return {}; });
g.setNode('step1', {label: 'Step 1', style: "fill:gray" });
g.setNode('step2', {label: 'Step 2', style: "fill:gray" });
g.setNode('step3', {label: 'Step 3', style: "fill:gray" });
g.setEdge('step1', 'step2');
g.setEdge('step2', 'step3');
var render = new dagreD3.render();
var svg = d3.select("svg").append("g");
render(d3.select("svg g"), g);
// example node color change
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
sleep(2000).then(() => {
// ????? another way to do this without calling render()?
g.node('step1').style = "fill:blue";
render(d3.select("svg g"), g);
});

To update a D3 node without calling render again:
nodeid = "step1";
d3.select('#' + nodeid).attr('style', 'fill:blue');
Example:
svg.selectAll("g.node").on("click", function (id) {
d3.select('#' + id).attr('class', 'bluebackground');
});

Related

override one value with a new value gives value undefined

To summarize what I want to do:
Update the state depending on the previous state
I have searched in vain for a solution to the above problems. Found 3 solutions, unfortunately without any success.
1)
const Form = (props) => {
const [newValue, setNewValue] = useState(0);
const submitHandler = (e) => {
e.preventDefault();
const incrementOne = {
value: setNewValue((prevState) => {
return {...prevState, newValue: newValue + 1}
})
};
console.log(incrementOne);
};
const submitHandler = (e) => {
e.preventDefault();
const incrementOne = {
value: setNewValue(newValue + 1),
};
console.log(incrementOne);
};
3
const submitHandler = (e) => {
e.preventDefault();
const incrementOne = {
value: setNewValue(prevState => prevState + 1),
};
console.log(incrementOne);
};
Thank you in advance for your time and effort
Sincerely
/ Peter
In all your examples you are creating an object with a value property. You assume that is supposed to get it's value from calling set function returned by useState. However, the result of calling this function is updating the state, and re-rendering. The function itself doesn't return anything (undefined).
const incrementOne = {
value: setNewValue((prevState) => {
return {...prevState, newValue: newValue + 1}
})
};
You should call the setNewValue function when you want to update the value. You can calculate the new state using the previous one:
setNewValue(newValue + 1);
Or use a functional update to avoid depending on the state directly:
setNewValue(prevState => prevState + 1);
Note that the new value is only available after the component re-renders.
Example:
const { useState } = React;
const Form = (props) => {
const [newValue, setNewValue] = useState(0);
const submitHandler = () => {
setNewValue(prevState => prevState + 1);
};
const incrementOne = {
value: newValue,
};
console.log(incrementOne);
return (
<div>
<div>{newValue}</div>
<button onClick={submitHandler}>Submit</button>
</div>
);
}
ReactDOM.render(
<Form />,
root
)
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>

How to make a context menu in a custom ckeditor5 widget?

I made a inline widget similar a placeholder (ckeditor4), but now I want to render a dropdown when the widget is selected to show options values to replace the placeholder. I trying use BalloonPanelView but no success until now, someone have a idea about how to make it?
this.editor.editing.view.document.on('click', (evt, data) => {
evt.stop();
const element = data.target;
if (element && element.hasClass('placeholder')) {
if (!element.getAttribute('data-is-fixed')) {
const balloonPanelView = new BalloonPanelView();
balloonPanelView.render();
['option1', 'option2', 'option3'].forEach((value) => {
const view = new View();
view.set({
label: value,
withText: true
});
balloonPanelView.content.add(view);
});
balloonPanelView.pin({
target: element
});
}
}
});
I found the solution using ContextualBalloon class:
import ContextualBalloon from "#ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon";
// Define ballon
const balloon = editor.plugins.get(ContextualBalloon);
const placeholderOptions = // Here I defined list with buttons '<li><button></li>'
// Finnaly render ballon
balloon.add({
view: placeholderOptions,
singleViewMode: true,
position: {
target: data.domTarget
}
});

Cypress check is element has scroll bar visible

I have list that should have 10 elements, if the list contains 11 elements i need to show scroll, the container is fixed size.
Everything is ok but how i can check that scroll is exist?
cy.get('[data-testid=list-box]')
You could get the count of elements and if the length of the list is less than or equal to 10 do some action, else check for the visibility of scrollbar. Please try below test and let me know
it('Check the length of the list', () => {
cy.get('[data-testid=list-box]')
.then(list => {
const listCount = Cypress.$(list).length;
if(listCount <= 10){
// do some action if the list count is less than 10..
}else{
cy.get('#scrollbar_Id').should('be.visible');
}
});
})
I'm doing this by measuring the height and scrollHeight with jQuery.
it("should force scroll within a large body", () => {
cy.get(".lorem-ipsum-header").click();
cy.get(".section-body")
.should("have.length", 1)
.eq(0)
.should("contain.text", "Lorem ipsum")
.then(($body) => {
cy.wrap($body).invoke("outerHeight").should("eq", 583);
cy.wrap($body).invoke("prop", "scrollHeight").should("eq", 1892);
});
});
Here I'm getting the last element. Then used cypress scrollIntoView() to scroll to that last element. And using should() to see it's visible or not.
cy.get('Selector')
.last()
.within(($element) => {
if (!$element.is(':visible')) {
cy.wrap($element).scrollIntoView();
}})
.should('be.visible');
Basically, we get the element from the jquery wrapper and then test if it is scrollable by comparing scrollWidth and actualWidth
export enum ScrollType {
scrollable='scrollable',
nonScrollable='non-scrollable',
}
export const isXScrollable = (element: HTMLElement) => {
return element.scrollWidth > element.clientWidth
};
export const isYScrollable = (element: HTMLElement) => {
return element.scrollHeight > element.clientHeight;
}
export const isScrollable = (element: HTMLElement) => {
return isXScrollable(element) || isYScrollable(element)
}
describe('Test',() => {
it('check that max of only 4 lines to be shown in the text area, and then it should add the scroll', () => {
mount(<Textarea defaultValue="Line 1" id="textbox-abc2" ></Textarea>);
const textbox = cy.get('#textbox-abc2');
textbox.type('{enter}Line 2{enter}Line 3{enter}Line 4');
textbox.then(a => {
const scrollable = isYScrollable(a[0]) ? ScrollType.scrollable: ScrollType.nonScrollable
expect(scrollable).to.eq(ScrollType.nonScrollable);
})
textbox.type('{enter}Line 5');
textbox.then(a => {
const scrollable = isYScrollable(a[0]) ? ScrollType.scrollable: ScrollType.nonScrollable
expect(scrollable).to.eq(ScrollType.scrollable);
})
})
})

How to select all features in cluster layer in openlayers 3

I've got a simple code and a simple map with adding features and clustering them all together. Straight from example:
var vectorSource = new ol.source.Vector({
projection: 'EPSG:4326'
});
var clusterSource = new ol.source.Cluster({
distance: 30,
source: vectorSource
});
var styleCache = {};
var clusters = new ol.layer.Vector({
source: clusterSource,
style: function(feature, resolution) {
var size = feature.get('features').length;
var style = styleCache[size];
var src;
if (!style) {
if( size == 1 ){
src = 'images/location-single.png';
}else{
src = 'images/location-multi.png';
}
style = [
new ol.style.Style({
image: new ol.style.Circle({
radius: 5,
fill: new ol.style.Fill({
color: '#5bc0de'
})
})
}),
new ol.style.Style({
image: new ol.style.Icon(({
// scale: 1 + rnd,
// rotateWithView: (rnd < 0.9) ? true : false,
// rotation: 360 * rnd * Math.PI / 180,
anchor: [0.45, 1],
anchorXUnits: 'fraction',
anchorYUnits: 'fraction',
// opacity: rnd,
src: src
})),
text: new ol.style.Text({
text: size.toString(),
fill: new ol.style.Fill({
color: '#000'
})
})
})
];
styleCache[size] = style;
}
return style;
}
});
var map = new ol.Map({
target: 'map', // The DOM element that will contains the map
renderer: 'canvas', // Force the renderer to be used
layers: [
// Add a new Tile layer getting tiles from OpenStreetMap source
new ol.layer.Tile({
source: new ol.source.OSM()
}),
clusters
],
// Create a view centered on the specified location and zoom level
view: new ol.View({
center: ol.proj.transform([2.1833, 41.3833], 'EPSG:4326', 'EPSG:3857'),
zoom: 6
})
});
Now i got cluster function working fine. But i need to show coordinates for every point in the cluster, i've tryed to use map.forEachFeatureAtPixel, but it doesent work for ALL the features in the cluster. How do i select them all?
Oh. I think i got it! A cluster is a feature and got its properties. so we can GET all features in a cluster by using .getProperties()
as in:
map.on('singleclick', function(event) {
map.forEachFeatureAtPixel(event.pixel, function(feature) {
var featuresInCluster = feature.getProperties().features;
});
});
But i would really like to know if is there another way?
/***First create a select interaction object by assigning the cluster layer you created**/
var select = new ol.interaction.Select({
layers: [clusters]
});
/**Then add the created select object**/
map.addInteraction(select);
var selectedFeatures = select.getFeatures();
/**Then write this code**/
selectedFeatures.on('add', function (event) {
// event.target only contains the clustered point
var feature = event.target.item(0);
console.log(feature)
});
/***HOPE IT WILL WORK**//

DOJO onclick on a pie chart slice for drill down

I tried to find several places how this work but could not.
The requirement is to drill down by clicking on the slice of the pie to next level. I can get the onclick even but not sure how to get the value from the chart. Everywhere it is pointing to http://www.sitepen.com/blog/2008/05/27/dojo-charting-event-support-has-landed/ but nowhere any live demo is given. Till now i have managed to get the onclick.
chart.addSeries("Monthly Sales - 2010", chartData);
var h = chart.connectToPlot("default", function(o){
if(o.type == "onclick"){
alert("clicked!");
}
});
var store = new dojo.store.Memory({data: [
{ id: '2', value: 10, usedForDrillDown:'x' },
{ id: '3', value: 5, usedForDrillDown: 'y' },
{ id: '4', value: 8, usedForDrillDown:'z' }
]});
// adapter needed, because the chart uses the dojo.data API
var storeAdapter = new dojo.data.ObjectStore({
objectStore: store
});
var ds = new dojox.charting.DataSeries(
storeAdapter/*, { query: { needed if the store contains more than data points } }*/);
var chart = new dojox.charting.Chart("chart");
chart.addPlot("default", { type: "Pie" });
chart.addSeries("default", ds);
chart.connectToPlot("default", function(evt) {
if(evt.type == "onclick"){
var itm = evt.run.source.items[evt.index];
console.dir(itm);
}
});
chart.render();

Resources