Is there a way to keep only the bottom part in vis.js timeline frame? - vis.js

I built the following frame using vis.js timeline:
But I'd like to keep only the bottom part (highlighted in blue). Is there a way to achieve that?
Respectively code:
export const TimelineGraph = (props) => {
const items = props.items;
const container = useRef(null);
const options = {
showCurrentTime: false
};
useEffect(() => {
const timeline = container.current && new Timeline(container.current, items, options);
}, [container, items]);
return (
<div
ref={container}
className={'container'}
/>
);
};

I think I found a solution. You just need to add min and max options to the options object, like so:
const options = {
showCurrentTime: false,
min: getLowestDate(),
max: getHighestDate(),
};
After that, the upper bar was gone.

Related

How to format TimeTickStrategy

I'm currently using a TimeTickStrategy on the xAxis to show data flowing in real time. However, it's formatting the data using the unix epoch as {hours:minutes:seconds}.
Below is my xAxis code:
xAxis1 = chart.getDefaultAxisX()
.setTickStrategy(AxisTickStrategies.Time, (tickStrategy) => tickStrategy.setTimeOrigin(this.originTime))
.setScrollStrategy(AxisScrollStrategies.progressive)
.setMouseInteractions(false)
.setInterval(60000 * -15, 60000) //xAxis Range(Min,Max) = (origin - 15 minutes, origin + 1 minute)
I'd like to have that formatted in the local time, but I didn't see any options for that when I was reading through the TimeTickStrategy documentation:
https://www.arction.com/lightningchart-js-api-documentation/v3.4.0/classes/timetickstrategy.html
Example (MST):
457050:14:51 --> 11:14:51 AM
Is there a way to do this?
Seems like TimeTickStrategy has no configuration options for formatting.
Maybe you can use DateTimeTickStrategy? It's a bit clumsy but it has quite extensive configuration methods. Here's some kind of an example I whipped up.
/*
* LightningChartJS example showcasing the TimeTickStrategy feature with scrolling data and axis.
*/
// Extract required parts from LightningChartJS.
const {
lightningChart,
AxisScrollStrategies,
AxisTickStrategies,
Themes,
emptyTick,
} = lcjs
// Import data-generators from 'xydata'-library.
const {
createProgressiveTraceGenerator
} = xydata
const chart = lightningChart().ChartXY({
theme: Themes.darkGold,
})
.setTitle('Scrolling TimeTickStrategy example')
.setPadding({ right: 40 })
const axisX = chart
.getDefaultAxisX()
// Enable TimeTickStrategy for X Axis.
.setTickStrategy(AxisTickStrategies.DateTime, ticks => ticks
.setGreatTickStyle(emptyTick)
.setFormattingSecond(
undefined,
{ hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true },
(x) => 'minor'
)
)
// Configure progressive ScrollStrategy.
.setScrollStrategy(AxisScrollStrategies.progressive)
// Set view to 15 seconds
.setInterval(-1 * 15 * 1000, 0)
.setAnimationScroll(false)
const axisY = chart.getDefaultAxisY()
.setAnimationScroll(false)
// Add 3 series for real-time signal monitoring.
const seriesList = new Array(3).fill(0).map((_, iSeries) =>
chart
.addLineSeries({
dataPattern: {
pattern: 'ProgressiveX',
},
})
)
const legend = chart.addLegendBox().add(chart)
// Dispose example UI elements automatically if they take too much space. This is to avoid bad UI on mobile / etc. devices.
.setAutoDispose({
type: 'max-width',
maxWidth: 0.30,
})
// Stream live timestamp data into series.
// Application displays timestamps as offset from when application started (starts at 00:00:00).
const timeOrigin = Date.now()
Promise.all(
seriesList.map((_) =>
createProgressiveTraceGenerator()
.setNumberOfPoints(60 * 1000)
.generate()
.toPromise(),
),
).then((data) => {
let dataAmount = 0
const pushData = () => {
const nDataPoints = 1
seriesList.forEach((series, iSeries) => {
const seriesData = data[iSeries]
const seriesPoints = []
for (let i = 0; i < nDataPoints; i += 1) {
seriesPoints.push({
// TimeTickStrategy interprets values as milliseconds (UNIX timestamp).
// Exactly same as JavaScript Date APIs.
x: Date.now() - timeOrigin,
y: seriesData[(dataAmount + i) % seriesData.length].y,
})
}
series.add(seriesPoints)
})
dataAmount += nDataPoints
requestAnimationFrame(pushData)
}
pushData()
})
<script src="https://unpkg.com/#arction/lcjs#3.4.0/dist/lcjs.iife.js"></script>
<script src="https://unpkg.com/#arction/xydata#1.2.1/dist/xydata.iife.js"></script>

jest test css for positioning

anyone know how to write a jest test for this?
loginBtn.onclick = (()=>{
loginForm.style.marginLeft = "0%";
loginText.style.marginLeft = "0%";
});
i've already tried this but it didnt work
beforeEach(() => {
document.documentElement.innerHTML = html.toString();
});
test('clicking signup moves the styles', () => {
const loginForm = document.querySelector("form.login");
const loginText = document.querySelector(".title-text .login");
expect(loginForm.style.marginLeft).toBeFalsy();
expect(loginText.style.marginLeft).toBeFalsy();
.toBeFalsy() will not be true because '0%' is a string different than 0 which is falsy
You will have to use toEqual('0%') for this situation
expect(loginForm.style.marginLeft).toEqual('0%');
expect(loginText.style.marginLeft).toEqual('0%');

addrow styling in Label

I am adding custom formtable like below
return builder
.addRow(name)
.addRow(price)
Is there anyway to style the row ? I want to display the price with big font and different color.
thank you.
Here is an example of simple custom autoCursor
// Extract required parts from LightningChartJS.
const {
lightningChart,
AutoCursorModes,
UIElementBuilders,
UILayoutBuilders,
UIBackgrounds,
ColorHEX,
SolidFill,
SolidLine,
UIOrigins,
translatePoint,
} = lcjs;
// Import data-generator from 'xydata'-library.
const {
createProgressiveTraceGenerator
} = xydata
// colors of the series
const colors = ["#fc03f0", "#1cb843", "#eeff00", "#0955ff", "#500c3f"];
// Create a XY Chart.
const chart = lightningChart()
.ChartXY({
// theme: Themes.dark
})
// Disable native AutoCursor to create custom
.setAutoCursorMode(AutoCursorModes.disabled)
.setTitle("Custom Cursor using LCJS UI");
// set title for Y axis
chart.getDefaultAxisY().setTitle("Y-axis");
// generate data and creating the series
const series = chart.addLineSeries().setStrokeStyle(
new SolidLine({
fillStyle: new SolidFill({ color: ColorHEX(colors[0]) }),
thickness: 2,
})
);
createProgressiveTraceGenerator()
.setNumberOfPoints(200)
.generate()
.toPromise()
.then((data) => {
return series.add(data);
});
// Create UI elements for custom cursor.
const resultTable = chart
.addUIElement(
UILayoutBuilders.Column.setBackground(UIBackgrounds.Rectangle),
{
x: chart.getDefaultAxisX(),
y: chart.getDefaultAxisY(),
}
)
.setMouseInteractions(false)
.setOrigin(UIOrigins.LeftBottom)
.setMargin(2)
.setBackground((background) =>
background.setStrokeStyle(
new SolidLine({
thickness: 1,
fillStyle: new SolidFill({ color: ColorHEX("#c9bab9") }),
})
)
);
const rowX = resultTable
.addElement(UILayoutBuilders.Row)
.addElement(UIElementBuilders.TextBox)
.setTextFont((font) => font.setSize(15))
.setTextFillStyle(new SolidFill({ color: ColorHEX(colors[1]) }));
const rowY = resultTable
.addElement(UILayoutBuilders.Row)
.addElement(UIElementBuilders.TextBox)
.setTextFont((font) => font.setSize(15))
.setTextFillStyle(new SolidFill({ color: ColorHEX(colors[2]) }));
// Hide custom cursor components initially.
resultTable.dispose();
// Implement custom cursor logic with events.
chart.onSeriesBackgroundMouseMove((_, event) => {
const mouseLocationClient = { x: event.clientX, y: event.clientY };
// Translate mouse location to LCJS coordinate system for solving data points from series, and translating to Axes.
const mouseLocationEngine = chart.engine.clientLocation2Engine(
mouseLocationClient.x,
mouseLocationClient.y
);
// Translate mouse location to Axis.
const mouseLocationAxis = translatePoint(
mouseLocationEngine,
chart.engine.scale,
series.scale
);
// Solve nearest data point to the mouse on each series.
const nearestDataPoints = series.solveNearestFromScreen(mouseLocationEngine)
if (nearestDataPoints) {
// Set custom cursor location.
resultTable.setPosition({
x: nearestDataPoints.location.x,
y: nearestDataPoints.location.y,
});
// set Origin of resultTable
if ( nearestDataPoints.location.x > chart.getDefaultAxisX().getInterval().end / 1.5 ) {
if (nearestDataPoints.location.y >chart.getDefaultAxisY().getInterval().end / 1.5) {
resultTable.setOrigin(UIOrigins.RightTop);
} else {
resultTable.setOrigin(UIOrigins.RightBottom);
}
} else if ( nearestDataPoints.location.y > chart.getDefaultAxisY().getInterval().end / 1.5) {
resultTable.setOrigin(UIOrigins.LeftTop);
} else {
resultTable.setOrigin(UIOrigins.LeftBottom);
}
// Format result table text.
rowX.setText(`X: ${nearestDataPoints.location.x.toFixed(1)}`);
rowY.setText(`Y: ${nearestDataPoints.location.y.toFixed(1)}`)
// Display cursor.
resultTable.restore();
} else {
// Hide cursor.
resultTable.dispose();
}
});
chart.onSeriesBackgroundMouseLeave((_, e) => {
resultTable.dispose();
});
<script src="https://unpkg.com/#arction/xydata#1.4.0/dist/xydata.iife.js"></script>
<script src="https://unpkg.com/#arction/lcjs#3.0.0/dist/lcjs.iife.js"></script>
There is no existing built-in method for customizing each row/column of result table apart from the text content.
This is definitely a feature that we are eventually including in the library, as soon as it becomes a priority or a customer requests it.
Right now, as a community user, it can be done by creating a custom cursor. Unfortunately there aren't many examples on this subject.
The general idea is solving the nearest data point from mouse location with ChartXY.solveNearest (or calculating by some custom method), and showing the custom cursor using UI elements and custom ticks if desired.
The ResultTable can be created by combining Column and Row layouts to get a grid, and then adding TextBox elements, whose font/color you can style individually.
EDIT: The official examples for custom cursors have been released.
You can find them there https://www.arction.com/lightningchart-js-interactive-examples/search.html?t=cursor
There is one example with LCJS UI elements and another with dynamic HTML & CSS (same approach could be used with some external UI framework).

How to addOne item at the beginning of collection in ngrx/entity

I started using ngrx/entity package, where I can manage store by adapter. There is addOne method I'd like to use, but it adds item to the end of collection. I wanna add one at the beginning. Could you please help me with that? How to add item at the beginning with EntityAdapter.
How I create entity adapter:
export const adapter: EntityAdapter<AssetTreeNode> = createEntityAdapter({
selectId: (model: AssetTreeNode) => model.Id
});
Reducer looks like that:
export function reducer(state: AssetListState = initialState, action: AssetListAction) {
switch (action.type) {
(...)
case ASSET_LIST_ADD_ITEM:
let assetToAdd: AssetTreeNode = Object.assign({} as AssetTreeNode,
action.payload.asset,
{ Id: action.payload.createdAssetId });
return adapter.addOne(assetToAdd, state); <--- I wanna add here at the end.
(...)
default:
return state;
}
}
There is no proper way provided by #ngrx/entity team. One of the answer mentions to use sort-comparator. But i believe using sort-comparator is not the right way to go. Suppose there is two click actions and in one action we need to append item below and in other action on top. here we will run into the same problem again.
I had run into the same issue and my solution to the problem is to reconstruct the list when we want the item on top of the list.
To add at the top of entity list
const { selectAll } = myAdapter.getSelectors();
...
...
on(MyActions.addItem, (state, { item }) =>{
return myAdapter.setAll([item ,...selectAll(state)], { ...state})
}),
To add at the bottom of entity list
on(MyActions.addItem, (state, { item}) =>{
return myAdapter.addOne(item, state)
}),
The only way to change this behavior would be to use the sortComparer when you create the adapter - docs.
export const adapter: EntityAdapter<User> = createEntityAdapter<User>({
sortComparer: (a: User, b: User) => a.name.localeCompare(b.name),
});
Maybe you could place the item at the begining and replace the list
on(addAsset, (state, { payload }) => {
const currentList = Object.values(state.entities);
const newList = [payload, ...currentList];
return adapter.setAll(newList, state);
});

Firebase: Update item in list binding using AngularFire2

According to the angularfire2 documentation the following can be done when you wan't to update a item in a list :
const items = af.database.list('/items');
// to get a key, check the Example app below
items.update('key-of-some-data', { size: newSize });
But is is possible to update an item in the list, without having to specify key:values for the object like this?
items.update('key-of-some-data', item);
In angularfire this is possible to do like this:
<li ng-repeat="item in list">
<input type="text" ng-model="item.title" ng-change="list.$save(item)" />
</li>
Thanks for taking your time to read this question :)
The implementation of update looks like this:
update(item: FirebaseOperation, value: Object): firebase.Promise<void> {
return this._checkOperationCases(item, {
stringCase: () => this.$ref.ref.child(<string>item).update(value),
firebaseCase: () => (<firebase.database.Reference>item).update(value),
snapshotCase: () => (<firebase.database.DataSnapshot>item).ref.update(value),
unwrappedSnapshotCase: () => this.$ref.ref.child((<AFUnwrappedDataSnapshot>item).$key).update(value)
});
}
So it's possible to call update in the following ways:
Using a string key and a value:
const items = af.database.list('/items');
items.update('key-of-some-data', { size: newSize });
Using a Firebase ref and a value:
const items = af.database.list('/items');
const ref = items.$ref.ref;
items.update(ref.child('key-of-some-data'), { size: newSize });
Using a Firebase snapshot and a value:
const items = af.database.list('/items', { preserveSnapshot: true });
items.subscribe(list => {
const snapshot = list[0];
items.update(snapshot, { size: newSize });
});
Using an unwrapped list item and a value:
const items = af.database.list('/items');
items.subscribe(list => {
const item = list[0];
items.update(item, { size: newSize });
});
(The snippets above that call subscribe are only to illustrate that the snapshot and unwrapped items are the list observable's emitted values. Using subscribe like this to perform an update makes no sense.)
AngularFire2 is currently undergoing some refactoring and rearranging in preparation for a release candidate. If you have a use case for which none of the above options is suitable, now is the time to speak up. The discussion is here. However, for something this specific, you should create a new issue.

Resources