Security News
tea.xyz Spam Plagues npm and RubyGems Package Registries
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
@spider-analyzer/timeline
Advanced tools
Readme
React graphical component to display metric over time with a time selection feature.
Live example: https://timeline.oss.spider-analyzer.io
domain
metricsDefinition
prop.metricsDefinition.legend[]
metricsDefinition.colors[]
metricsDefinition.legend[]
, metricsDefinition.colors[]
and histo.items[].metrics[]
metricsDefinition.legend[]
, and displayed left to the chartA cursor allows to select time in the viewed domain.
zoomOutFactor
Limits:
smallestResolution
biggestVisibleDomain
Time domain can be dragged forward or backward by pressing ctrl and dragging the mouse on the chart.
maxDomain
limit is defined, the timeline cannot display dates outside this domainTimeLine is design for integration in time series or operational data reporting and display. It is perfectly suited for integration aside a grid of records to define the time range of records to display.
When integrating the TimeLine in your project, you have to define:
metricsDefinition
domains[0]
loaded by onLoadDefaultDomain
maxDomain
biggestVisibleDomain
smallestResolution
onResetTime
.
onLoadDefaultDomain
and reset the domains.onFormatTimeLegend
onFormatTimeToolTips
onFormatMetricLegend
Default resolution is millisecond, the time may rounded outside TimeLine component to second, minute or so.
onCustomRange
, onLoadDefaultDomain
, onLoadHisto
functions, as shown in demo.smallestResolution
and onFormatTimeToolTips
should be adjusted in consequence.You may also redefine labels displayed: labels
Install using npm or your favorite tool.
npm install --save @spider-analyzer/timeline
Include in your react application.
Warning: Current version requires some props to be Moment.js objects. So you would need Moment in your own application. You can reduce webpack bundle when using webpack, as timeline lib is not using any locale of Moment.js. See: https://github.com/jmblog/how-to-optimize-momentjs-with-webpack.
<TimeLine
className={'timeLine'}
timeSpan = {this.state.timeSpan} //start and stop of selection
histo = {{
items: this.state.items, // table of histo columns: [{time: moment, metrics: [metric1 value, metric2 value...], total: sum of metrics}, ...]
intervalMs: this.state.intervalMs //interval duration of column in ms
}}
showHistoToolTip
quality = {{
items: this.state.quality, //table of quality indicators [{time: moment, quality: float [0,1], tip: string}]
intervalMin: this.state.intervalMin //interval duration of column in Min
}}
qualityScale = {
scaleLinear()
.domain([0,1])
.range(['red','green'])
.clamp(true)
} //color scale (optional)
zoomOutFactor = {1.75} //zoom out factor if never zoomed in
domains = {this.state.domains} //array of zoom levels
maxDomain = {this.state.maxDomain} //max zoom level allowed
metricsDefinition = {metricsDefinition}
biggestVisibleDomain = {moment.duration('P1M')} //maximum visible duration, cannot zoom out further
biggestTimeSpan = {moment.duration('P1D')} //maximum duration that can be selected
smallestResolution = {moment.duration('PT1M')} //max zoom level: 15pixels = duration
labels={{
backwardButtonTip: 'Slide into the past'
}}
tools={{
gotoNow: false
}}
showLegend
fetchWhileSliding
selectBarOnClick
onLoadDefaultDomain = {this.onLoadDefaultDomain} //called on mount to get the default domain
onLoadHisto = {this.onLoadHisto} //called to load items. give the needed interval, computed from props.width, props.domains[0]
onCustomRange = {this.onCustomRange} //called when user has drawn or resized the cursor
onShowMessage = {console.log} //called to display an error message
onUpdateDomains = {this.onUpdateDomains} //called to save domains
onResetTime = {this.onResetTime} //called when user want to reset timeline
onFormatTimeToolTips = {this.onFormatTimeToolTips} //called to display time in tooltips
onFormatTimeLegend = {multiFormat} //called to format x axis legend
onFormatMetricLegend = {formatNumber} //called to format y axis metric legend
/>
TimeLine component is a controlled component.
Main class used in the <div/>
encapsulating the svg graphic.
The width and height of the chart should be defined there. In % or strict dimensions.
When resizing the window, the chart will adapt.
Allows to override any classes used by the component.
To be used by a CSS-in-JS solution, are by listing classes from your own CSS. To find the classes to update... best is to play with developer tools ;)
Allows changing the class prefix for rc-tooltip
Allows to adjust the margin around the graphic area.
The metrics legend, and time legend are rendered inside the margin.
margin: PropTypes.shape({
left: PropTypes.number,
right: PropTypes.number,
top: PropTypes.number,
bottom: PropTypes.number,
})
Allows customising the xAxis (time):
spaceBetweenTicks and spaceBetweenTicks are used to compute the resolution 'interval' of the onLoadHisto function.
xAxis: PropTypes.shape({
arrowPath: PropTypes.string,
spaceBetweenTicks: PropTypes.number.isRequired,
barsBetweenTicks: PropTypes.number.isRequired,
showGrid: PropTypes.bool,
height: PropTypes.number,
})
Allows customising the yAxis (metrics):
yAxis: PropTypes.shape({
path: PropTypes.string,
spaceBetweenTicks: PropTypes.number.isRequired,
showGrid: PropTypes.bool,
})
Defines the start and stop of the selected time window.
timeSpan: PropTypes.shape({
start: PropTypes.instanceOf(moment).isRequired,
stop: PropTypes.instanceOf(moment).isRequired
}).isRequired
Ex:
timeSpan = {
start: moment().subtract(1, 'HOUR'),
stop: moment().add(1, 'HOUR'),
}
Provides the data to display.
/!\ items and intervalMs have to be provided in sync.
When loading new items when processing onLoadHisto, both intervalMs and items must be given back together. That's why they are in same prop. If intervalMs is not consistent with items own duration 'interval', then you'll have an ugly glitch when zooming out and resizing. And wrong information display when zooming in.
So, please do not keep intervalMs in an intermediate state with a closer update loop than the loading request itself.
histo: PropTypes.shape({
items: PropTypes.arrayOf(PropTypes.shape({
time: PropTypes.instanceOf(moment).isRequired, //time of histogram bar
metrics: PropTypes.arrayOf(PropTypes.number).isRequired, //array of values
total: PropTypes.number.isRequired, //total of values of the array
})),
intervalMs: PropTypes.number //interval of each bar
}).isRequired
When true, timeline will display a tooltip when hover the histogram stacked bars.
The tooltip lists the time slot and the different metrics values for the bar.
It may be customized by providing a custom HistoToolTip
component.
showHistoToolTip: PropTypes.bool
React component to replace and customize the histogram tooltips content.
Provided props:
HistoTooltip.propTypes = {
classes: PropTypes.object, // classes you gave in input of TimeLine
item: PropTypes.shape({ // histogram bar
start: PropTypes.instanceOf(moment), // start of the bar
end: PropTypes.instanceOf(moment), // end of the bar
x1: PropTypes.number, // start position in x axis
x2: PropTypes.number, // start position in y axis
metrics: PropTypes.arrayOf(PropTypes.number), // as provided in histo prop
total: PropTypes.number, // total of the metrics bar
}),
metricsDefinition: PropTypes.shape().isRequired, // prop you gave
onFormatTimeToolTips: PropTypes.func.isRequired, // prop you gave
onFormatMetricLegend: PropTypes.func.isRequired, // prop you gave
};
Provides the data to display on the quality line.
quality: PropTypes.shape({
items: PropTypes.arrayOf(PropTypes.shape({
time: PropTypes.instanceOf(moment).isRequired, //time of quality slot
quality: PropTypes.number.isRequired, //quality of the slot
tip: PropTypes.node, //text to display in tooltip - optional
})),
intervalMin: PropTypes.number //duration of each slot (in minutes)
})
Allows to override the color scale for the quality line. Expects a function converting a quality number into a CSS color.
qualityScale: PropTypes.func
Allows to override the default zoom factor (1.25) for zooming out when never zoomed in before.
Should be > 1 ;)
zoomOutFactor: PropTypes.number
Stores/defines the actual zooms levels of the timeline.
domains: PropTypes.arrayOf(PropTypes.shape({
min: PropTypes.instanceOf(moment).isRequired,
max: PropTypes.instanceOf(moment).isRequired
})).isRequired
onUpdateDomains
is called with an update of the domains.onLoadDefaultDomain
that should be used to define the initial domain.Ex:
domains = [{
min: moment().subtract(1, 'WEEK').startOf('DAY'),
max: moment().endOf('DAY')
}]
May/should specify a maximum domain that will set min and max bounds when shifting the TimeLine.
maxDomain: PropTypes.shape({
min: PropTypes.instanceOf(moment).isRequired,
max: PropTypes.instanceOf(moment).isRequired
})
Ex:
maxDomain = {
min: moment().subtract(2, 'MONTHS').startOf('DAY'),
max: moment().add(1, 'WEEK').endOf('DAY')
}
Defines the metrics that will be displayed on the chart: count, legend, formatting
metricsDefinition: PropTypes.shape({
count: PropTypes.number.isRequired,
legends: PropTypes.arrayOf(PropTypes.string).isRequired,
colors: PropTypes.arrayOf(PropTypes.shape({
fill: PropTypes.string.isRequired,
stroke: PropTypes.string.isRequired,
text: PropTypes.string.isRequired,
})).isRequired
}).isRequired
Ex:
metricsDefinition = {
count: 3, //Count of metric in the graphic
legends: ['Info', 'Warn', 'Fail'], //Name of the metrics, in order. Will be displayed left of the chart
colors: [{ //Colors of the metrics, in order: fill of bar, stroke of bar, text in legend
fill: '#9be18c',
stroke: '#5db352',
text: '#5db352'
},
{
fill: '#f6bc62',
stroke: '#e69825',
text: '#e69825'
},{
fill: '#ff5d5a',
stroke: '#f6251e',
text: '#f6251e'
}]
}
Defines the maximum visible duration of a domain, if any. For instance, allows set a maxDomain of 1 year, but limit visible histogram to a window of 1 month. Limits the overloading of the aggregation API.
biggestVisibleDomain: PropTypes.object //expects a Duration created by moment.duration() object
Ex:
biggestVisibleDomain = moment.duration('P1M')
Defines the maximum duration that can be selected, if any.
biggestTimeSpan: PropTypes.object //expects a Duration created by moment.duration() object
Ex:
biggestTimeSpan = moment.duration('P1D')
Defines the smallest zoom resolution to display (for 15 pixels).
smallestResolution: PropTypes.object.isRequired //expects a Duration created by moment.duration() object
Ex:
smallestResolution = moment.duration('PT1M')
Overrides labels to display for ToolTips and onShowMessage calls. Provided for translation.
labels: PropTypes.shape({
forwardButtonTip: PropTypes.string,
backwardButtonTip: PropTypes.string,
resetButtonTip: PropTypes.string,
gotoNowButtonTip: PropTypes.string,
doubleClickMaxZoomMsg: PropTypes.string,
zoomInWithoutChangingSelectionMsg: PropTypes.string,
zoomSelectionResolutionExtended: PropTypes.string,
maxSelectionMsg: PropTypes.string,
scrollMaxZoomMsg: PropTypes.string,
minZoomMsg: PropTypes.string,
maxDomainMsg: PropTypes.string,
minDomainMsg: PropTypes.string,
gotoCursor: PropTypes.string,
zoomInLabel: PropTypes.string,
zoomOutLabel: PropTypes.string,
})
Default:
const defaultLabels = {
forwardButtonTip: 'Slide forward',
backwardButtonTip: 'Slide backward',
resetButtonTip: 'Reset time span',
gotoNowButtonTip: 'Goto Now',
doubleClickMaxZoomMsg: 'Cannot zoom anymore!',
zoomInWithoutChangingSelectionMsg: 'Please change time selection before clicking on zoom ;)',
zoomSelectionResolutionExtended: 'You reached maximum zoom level',
maxSelectionMsg: 'You reached maximum selection',
scrollMaxZoomMsg: 'Cannot zoom anymore!',
minZoomMsg: 'You reached minimum zoom level',
maxDomainMsg: 'You reached maximum visible time',
minDomainMsg: 'You reached minimum visible time',
gotoCursor: 'Goto Cursor',
zoomInLabel: 'Zoom in',
zoomOutLabel: 'Zoom out',
};
Allow deactivating legend display, left to vertical axis
showLegend: PropTypes.bool
Allow deactivating tools. All are present by default.
tools: PropTypes.shape({
slideForward: PropTypes.bool,
slideBackward: PropTypes.bool,
resetTimeline: PropTypes.bool,
gotoNow: PropTypes.bool,
cursor: PropTypes.bool,
zoomIn: PropTypes.bool,
zoomOut: PropTypes.bool,
})
Defines if timeline should try to refresh data when sliding domain. May overload the aggregation API.
fetchWhileSliding: PropTypes.bool
Defines if clicking on a bar of the histogram automatically switch the time selection to this bar.
selectBarOnClick: PropTypes.bool
Called on mount to get the default domain.
domains
prop.[{min: moment, max: moment}]
.Called to load items. Give the needed interval, computed from props.width and props.domains[0].
histo
prop.Called on:
fetchWhileSliding
prop is setParameters:
Called when user has drawn or resized the cursor.
timeSpan
prop.Called to display an error message.
Called to save domains.
domains
prop.Called when user want to reset timeline.
domains
prop. Usually to a new array with only default domain.domains[0]
is expected to be changed (new object) to trigger a new onLoadHisto
call.Called to display time in tooltips.
Ex:
onFormatTimeToolTips = (time) => {
return moment(time).second(0).millisecond(0).format(TIME_FORMAT_TOOLTIP);
};
Called to format the x axis legend. Depending of zoom resolution, the input will be a date rounded to:
millisecond
second
minute
hour
day
month
year
Must return a formatted date as string.
Result should be different for each rounded date.
Example:
import {timeFormat, timeSecond, timeMinute, timeHour, timeDay, timeMonth, timeYear } from 'd3';
const formatMillisecond = timeFormat('.%L'), // .456
formatSecond = timeFormat(':%S'), // :43
formatMinute = timeFormat('%H:%M'), // 13:12
formatHour = timeFormat('%H:00'), // 13:00
formatDay = timeFormat('%b %d'), // Nov 02
formatMonth = timeFormat('%b %d'), // Nov 01
formatYear = timeFormat('%Y %b %d') // 2017 Nov 01
;
const onFormatTimeLegend = (date) => {
return (timeSecond(date) < date ? formatMillisecond
: timeMinute(date) < date ? formatSecond
: timeHour(date) < date ? formatMinute
: timeDay(date) < date ? formatHour
: timeMonth(date) < date ? formatDay
: timeYear(date) < date ? formatMonth
: formatYear)(date);
};
Called to format metric amount value to display on the top of y axis.
Example:
import {formatLocale } from 'd3';
const locale = formatLocale({
decimal: '.',
thousands: ' ',
grouping: [3],
});
const onFormatMetricLegend = (number) => {
return locale.format(`,d`)(number);
};
Three functions are exposed on the mounted component (through React Ref): Other functions are supposed to be private.
This can be used to externalize ZoomIn button behavior in your app and own U/X.
zoomOutFactor
.biggestVisibleDomain
.This can be used to externalize ZoomOut button behavior in your app and own U/X.
This can be used to externalize sliding buttons behavior in your app and own U/X.
You may run the demo in hot reloading mode:
#clone the repo
git clone https://gitlab.com/TincaTibo/timeline.git
cd timeline/test
#make a docker image with a demo app
make image (requires docker and npm)
Then, run the demo in prod mode
# run the demo in prod mode
make demo
Or in dev mode
# run the demo in dev mode (volume mount the dev files for hot reloading)
make start
To access it, go to http://localhost:5000 in your browser
FAQs
React graphical component to display metric over time with a time selection feature.
The npm package @spider-analyzer/timeline receives a total of 41 weekly downloads. As such, @spider-analyzer/timeline popularity was classified as not popular.
We found that @spider-analyzer/timeline demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Tea.xyz, a crypto project aimed at rewarding open source contributions, is once again facing backlash due to an influx of spam packages flooding public package registries.
Security News
As cyber threats become more autonomous, AI-powered defenses are crucial for businesses to stay ahead of attackers who can exploit software vulnerabilities at scale.
Security News
UnitedHealth Group disclosed that the ransomware attack on Change Healthcare compromised protected health information for millions in the U.S., with estimated costs to the company expected to reach $1 billion.