How to split a stream with some predicate - reactive-programming

Here it is written how to split a stream into many ones by some border mark. It is accomplished with .window and .filter.
in a-b-c-X-d-e-f-g-h-X-i-X-j-k-l-m-n-
out v a-b-c-X
v -d-e-f-g-h-X
v -i-X
v -j-k-l-m-n-
But how to split a stream before a border mark? Like this:
in a-b-c-X-d-e-f-g-h-X-i-X-j-k-l-m-n-
out v a-b-c
v X-d-e-f-g-h
v X-i
v X-j-k-l-m-n-

The answer you refer to doesn't actually include the markers in any of the output streams, only the items that come between them. As suggested by user3743222 in the comments, if you wanted them in the output streams, you could simply put them back in. Something like this:
const marker = 'X';
const [ incisions, items ] = input.partition(x => x === marker);
const streams = items.window(incisions);
const first = streams.take(1);
const rest = streams.skip(1);
const whatYouWant = first.concat(rest.map(x => Rx.Observable.just(marker).concat(x)));
However, one of the less-used overloads of window is actually capable of doing this directly:
const closing = input.filter(x => x === 'X').share();
const opening = Rx.Observable.just(null).concat(closing);
const streams = input.window(opening, () => closing);

Related

iterate through a list of widgets based on a list of objects in a formula

I am trying to display a certain series of widgets based on objects contained in a formula. Here is how I am assigning the widgets to a variable based on their type.
var l = TankFormulaLength(length: tankSpec.tankSpecs.imperialLength);
var w = TankFormulaWidth(width: tankSpec.tankSpecs.imperialWidth);
var h = TankFormulaHeight(height: tankSpec.tankSpecs.imperialHeight);
var d = TankFormulaDiameter(diameter: tankSpec.tankSpecs.imperialDiameter);
List<Widget> tankMeasurements = [l, w, h, d];
Here is where these are being used.
Column(children: <Widget>[
...tankFormula(tankMeasurements,
tankSpec.tankSpecs.formula),
],
),
The formula is pulled from an api call that happens based on a tank specification and is delivered as show below..currently I am printing it to the console so I can see what formula each tank spec is using.
in my tankFormula function, I want to take the specific formula and use it to iterate through my list of widgets and only return the ones specific to the formula. Currently I am able to make all of them show up, because they are not being filtered.
List<Widget> tankFormula(formulaComponents, formula) {
List<Widget> calculatedFormula = [];
print(formula);
return formulaComponents;
}
I am unsure how to get the end result I am looking for. As shown in the screenshot below, I only needs the fields from the formula, 'Length' and 'Diameter', to show up as those are the only ones used in this particular formula for this specific tank specification. In other instances, it could be some of the additional fields i.e. 'Width or 'Height'. Again, based on the formula returned from the API. The additional fields 'Product', 'Tank Capacity', and 'Sensor Offset', will always be displayed.
I am aware that calculatedFormula is not being used. I created this variable to hold the returned List of Widgets that will be displayed on the screen. I am stuck and unsure how to move forward. Thank you sincerely for your help in advance!
Is this perhaps what you're looking for?
Widget build(BuildContext context) {
return Column(
children: [
if (list.contains('l')) TankFormulaLength(),
if (list.contains('h')) TankFormulaHeight(),
if (list.contains('w')) TankFormulaWidth(),
if (list.contains('d')) TankFormulaDiameter(),
],
);
}
This assumes that list is your array of strings, which can look like:
var list = ['l', 'h', 'w', 'd'];
The solution by "void void" is perfectly legit. If you want, for some reason, to iterate over the list, then this is a separate approach.
return Column(
children: list.map<Widget>((e) {
switch(e) {
case 'l': return TankFormulaLength(...);
case 'h': return TankFormulaHeight(...);
case 'w': return TankFormulaWidth(...);
case 'd': return TankFormulaDiameter(...);
}
return const SizedBox.shrink();
).toList(),
);
Here is how I solved this problem. Because I was receiving a specific value from the api for each portion of the formula I needed to make sure I was passing that down to my custom widget through the function I had created and then checking to see which variables the formula contains.
List<Widget> tankFormula(l, w, h, d, formula) {
List<Widget> calculatedFormula = [];
if (formula.contains('l')) {
calculatedFormula.add(TankFormulaLength(length: l));
}
if (formula.contains('w')) {
calculatedFormula.add(TankFormulaWidth(width: w));
}
if (formula.contains('h')) {
calculatedFormula.add(TankFormulaHeight(height: h));
}
if (formula.contains('d')) {
calculatedFormula.add(TankFormulaDiameter(diameter: d));
}
print(formula);
return calculatedFormula;
}

How can i stop this onClick event from rerendering the entire treemap echart i have?

How can i stop this onClick event from rerendering the entire treemap echart i have?
I have basically a echarts treemap https://echarts.apache.org/examples/en/editor.html?c=treemap-disk as a functional component in react. I need to be able to apply filters and "grey out" certain tree nodes that dont fit the criteria. This functionality works currently but it rerenders the echart so that the user must restart from the top level and clicktheir way through all the way to the bottom level. How can i avoid the rerendering? This is a similar example i have where clicking the node displays data but also rerenders the chart losing where the node was in the map.
const onChartClick = params => {
if (params.treePathInfo.length === 9) {
setDrawerData(params);
}
};
useEffect(() => {
props.setDrawerData(drawerData);
}, [drawerData]);
const onEvents = {
click: onChartClick,
}; ```
you can try to put your chart on useMemo it works for me :
const [dataLoaded, setdataLoaded] = useState(true);
const onChartClick = params => {
if (params.treePathInfo.length === 9) {
setDrawerData(params);
}
};
useEffect(() => {
props.setDrawerData(drawerData);
setdataLoaded(false)
}, [drawerData]);
const onEvents = {
click: onChartClick,
};
const MemoChart = useMemo(() => <Charts
option={option}
onEvents={onEvents}
/>, [dataLoaded]);

H3 - Show hexagons all over India

I am trying to show the hexagons all over the world, (at least all over India) using H3 on my Leaflet map.
I have tried the below logic but it doesn't work:
Logic:
const boundingBoxIndia = [
[38.11727165830543, 76.37695312500001],
[23.785344805941214, 67.41210937500001],
[6.293458760393985, 77.16796875000001],
[28.51696944040106, 98.525390625],
];
const cellIdsInIndia = h3.polyfill(boundingBoxIndia, 13, true);
const hexagonsInIndia = [];
const hexagonInIndia = cellIdsInIndia?.map((cellId, i) => {
const polygon = h3.h3ToGeoBoundary(cellId, false);
return [polygon];
});
hexagonsInIndia.push(hexagonInIndia);
In render:
<IndiaCells cellGroups={hexagonsInIndia} />
Component
const IndiaCells = (props) => {
if (props.cellGroups?.length) {
return props.cellGroups.map((cells, index) => {
return cells.map(([polygon], groupIndex) => {
return (
<div key={groupIndex}>
<Polygon
positions={polygon}
pathOptions={{...}}
></Polygon>
</div>
);
});
});
} else {
return null;
}
};
I am able to render other hexagons for a smaller sample by the same logic. Also the above code takes a lot of time to load the map but hexagons aren't visible. Looks like size might be an issue here.
Is there any better way to show the H3 hexagon grids all over the map? Something like this:
I think you simply have too many H3 cells for the map to handle. Using your bounding box above, h3.polyfill(boundingBoxIndia, 8, true) yields over 1.5M cells - at resolution 13, you're looking at that number times 7^5, or roughly 25.4 billion cells. I'm guessing that you don't see any cells because the polyfill operation runs out of memory, though I'm somewhat surprised that the page doesn't hang completely.
In general, if you want to render cell boundaries at some fine grain, you need to render only the current viewport (and stop rendering when the expected count gets too high, e.g. when you zoom out). See this h3-viewer project for an example of per-viewport rendering using Leaflet.

taking items from map in flutter

I am tring to use a map to get words from a string and map them to a widget.
I have tried this but my problem is the key for the words doe and sister get the same keys so i end up getting only one of them
String theText = "my name is doe from http.doe.com, my sister is selly. doe and saqil are not sister friends of koiter.";
wordsMap = Map.fromIterable(text.split(' '),
key: (v) => v,
value: (v) => TextSpan(text: v));
so I tried the code below
Map mapMyWord = {};
// var wordsMap;
var splitForSize = text.split(' ').toList();
for(var t = 0;t<= splitForSize.length-1;t++){
mapMyWord[t] = {'$t':TextSpan(text: splitForSize[t])};
}
but In the second code when I tried to access mapMyWord.values.toList() it returns a list of map data again
[{0: TextSpan("my")}, {1: TextSpan("name")}, {2: TextSpan("is")}, {3: TextSpan("doe")}, {4: TextSpan("````http.codeish.com````,")}, ... ,{19: TextSpan("koiter")}]
so my main problem is how to get the values from here.
It returns maps because you're assigning maps with this line :
mapMyWord[t] = {'$t':TextSpan(text: splitForSize[t])};
So in the end you have a Map<Int, Map<String, TextSpan>>.
If you meant to turn the words of that sentence into a list of TextSpan, this would be the way :
var textSpanList = text.split(" ").map((word) => TextSpan(text: word)).toList();
If you want to do it directly in the widget tree, this would do it :
children: <Widget>[
for(var word in text.split(" "))
Text(word),
]
N.B: This last snippet requires a minimum SDK of 2.2.2 in the pubspec.yaml
In your second code, change the assignment part:
Map mapMyWord = {};
// var wordsMap;
var splitForSize = text.split(' ').toList();
for(var t = 0;t<= splitForSize.length-1;t++){
mapMyWord[t] = TextSpan(text: splitForSize[t]);
}
Then, mapMyWord.values.toList() will only return a list of TextSpan's. And if you want to get some specific value from the map:
int index = 1; //some number
print(mapMyWord[index]); //this will return one TextSpan

Draft.js insert image at dropped position

I'm trying to drop image from outside of draft-js editor but it's always inserted at last position of the cursor/selection in editor (or at end if cursor/selection not set).
This is my wrap around draft-js-drag-n-drop-plugin
const droppableBlockDndPlugin = {
...blockDndPlugin,
handleDrop: (
selection,
dataTransfer,
isInternal,
{getEditorState, setEditorState}
) => {
const editorState = getEditorState();
const raw = dataTransfer.data.getData('text');
const data = raw ? raw.split(IMAGE_BLOCK_TYPE_SEPARATOR) : [];
if (data.length > 1 && data[0] === IMAGE_BLOCK_TYPE_PURE) {
const url = data[1];
if (url) {
const newState = imagePlugin.addImage(editorState, url);
setEditorState(newState);
}
}
return blockDndPlugin.handleDrop(selection, dataTransfer, isInternal, {
getEditorState,
setEditorState
});
}
};
Basically I'm just doing extra logic before base handleDrop occurs where I insert image using imagePlugin.addImage. Is there way to drop image to dragged position?
Actually it was quite obvious solution - you should just use passed selection and create new state with it and then add image to that new state:
const newState = imagePlugin.addImage(EditorState.forceSelection(editorState, selection), url);
setEditorState(newState);