Hi,
I want to make a web page and display a count down for example 5 minutes. It will count from 05:00.00 to 00:00.00 in 10ms interval. There will be a start button to start the timer. Timer will be shown on page as format 04:45.23.
After reaching 0, I want to display something (text in div or span).
How is it possible?
Hey @kahlenberg There is a pull request in the queue for a new dcc.Timer
component that will make this super easy to do. You can track the progress and see a preview here:
plotly:dev
← AnnMarieW:timer
opened 01:41PM - 03 May 21 UTC
## dcc.Timer()
The new Timer component is a response to the discussion in [#8… 57](https://github.com/plotly/dash-core-components/issues/857).
`dcc.Timer` is based on the `dcc.Interval` component. It has all the functionality of `dcc.Interval` plus these new features:
- Operate the timer in either `countdown` or `stopwatch` (count up) modes.
- Specify custom messages to display at certain times.
- Automatically convert milliseconds into human readable times. For example, 1337000000ms can be display as:
'15d 11h 23m 20s' See other available formats in the `timer_format` prop.
- Specify certain times to trigger a callback. This makes it easy to start or stop jobs at a specified elapse time.
- Improve load and performance times because updates can happen clientside. This makes it unnecessary to fire a callback
frequently (ie every interval) just to update a countdown/stopwatch message.
#### Component Properties
|Prop name|Type & Default value|Description|Example values|
|----|----|----|----|
| id| string; optional|id of component used to identify dash components in callbacks| |
|interval| number; default 1000| This component will increment the counter `n_intervals` every `interval` milliseconds| |
|disabled |boolean; optional| If True, the n_interval counter and the timer no longer updates. This pauses the timer.| |
|n_intervals| number; default 0| Number of times the interval has passed (read-only)| |
|max_intervals| number; default -1| Number of times the interval will be fired. If -1, then the interval has no limit and if 0 then the interval stops running.||
|timer| number; default 0| When in countdown mode, the timer will count down to zero from the starting `duration` and will show the number of milliseconds remaining. When in stopwatch mode, the timer will count up from zero and show the number of milliseconds elapsed. (read only) | |
|mode| 'stopwatch' or 'countdown'; default 'countdown'| The timer will count down to zero in `countdown` mode and count up from zero in `stopwatch` mode| |
|duration| number; default -1| Sets the number of milliseconds the timer will run. If -1 the timer will not be limited by the duration and if 0 then the timer stops running and may be reset.||
|reset| boolean; default True| This will start the timer at the beginning with the given prop settings.| |
|fire_times| list; optional| A list of the time(s) in milliseconds at which to fire a callback. This can be used to start a task at a given time rather than using the timer. Since the timer is typically set at a small interval like one second, using `fire_times` can reduce the number of times a callback is fired and can increase app performance. The time(s) must be a multiple of the interval.| |
|at_fire_time| number| This is updated when the timer reaches one of the times in the `fire_times` list. Using `at_fire_time` in a callback will trigger the callback at the time(s) in `fire_times` (Read only)| |
|rerun|boolean; default False| When True, the timer repeats once the timer has run for the number of milliseconds set in the `duration`.| |
|messages|dict; optional| Timer messages to be displayed by the component rather than showing the timer. It is a dictionary in the form of: { integer: string} where integer is the time in milliseconds of when the `string` message is to be displayed. Note: `timer_format` will override `messages`.| {10000 : "updating in 10 seconds"} will display the message "updating in 10 seconds" once the timer equals 10000.|
|timer_format|string; optional. One of:| If a timer is displayed, it will override timer `messages`. This formats the timer (milliseconds) into human readable formats.| |
| | 'none'; default| No timer will be displayed. Timer `messages` will be shown.
| | 'display'| Display timer in default format. For example, 1337000000 milliseconds will display as: '15d 11h 23m 20s'|'15d 11h 23m 20s'|
| | 'compact'| Shows a compact timer display. It will only show the first unit| 1h 10m → 1h|
| | 'verbose'| Verbose will display full-length units.|5h 1m 45s → 5 hours 1 minute 45 seconds|
| | 'colonNotation'| Use this when you want to display time without the time units, similar to a digital watch. It will always show at least minutes: 1s → 0:01|5h 1m 45s → 5:01:45|
### Demo
Run `timer_demo_py` to see eight examples using `dcc.Timer`. Some may be good candidates for the docs. Here is a preview:
#### Countdown and Stopwatch timers with messages updated clientside - no callbacks required!
![Peek 2021-05-03 06-31](https://user-images.githubusercontent.com/72614349/116882776-ad60fe80-abd9-11eb-9a3e-987dc3c8bf66.gif)
#### Space shuttle app:
This app uses the `dcc.Timer` component to launch the space shuttle. :rocket:
- The `messages` property is used to define the messages that are displayed at certain times during the launch.
- The `fire_times` property specifies the time to trigger a callback to start the launch.
The timer runs for 51 seconds, but it only fires the callback once (at liftoff) All the other messages are handled
clientside by the component.
![Peek 2021-05-03 06-39](https://user-images.githubusercontent.com/72614349/116883437-750df000-abda-11eb-9225-3198b866259f.gif)
Ok, thank you but I need this functionality now
So, I implemented my own rudimentary timer callback with desired functionality:
time_interval_s = 120
time_interval_ms = time_interval_s * 1000
...
@app.callback(
Output("timer_display", "children"),
Input("interval-component", "n_intervals"),
)
def update_output(n):
#calculate remaining time in ms
remaining = time_interval_ms - (n * 100)
minute = (remaining // 60000)
second = (remaining % 60000) // 1000
milisecond = (remaining % 1000) // 10
return u'{:02d}:{:02d}.{:02d}'.format(minute, second, milisecond)
In case someone is looking for a complete working solution over this topic, I have combined the pseudo code provided by @kahlenberg above with working solution by @AnnMarieW from https://community.plotly.com/t/using-dcc-interval-for-continuous-update/41071/10 into the following codes:
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
from dash.exceptions import PreventUpdate
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
[
# "start value",
dcc.Input(id="total", type="number", value=120 * 1000),
# "countdown value", " #can be hidden - or use dcc.Store instead
# dcc.Input(id="countdown", type="number", value=0, disabled=True),
html.Div(id="page-content"),
dcc.Interval(id="interval", n_intervals=0, interval=3000),
]
)
@app.callback(
Output("page-content", "children"),
Input("total", "value"),
Input("interval", "n_intervals"),
)
def display_page(value, n):
if not value:
raise PreventUpdate
if not value:
raise PreventUpdate
ctx = dash.callback_context
callback_input_id = ctx.triggered[0]["prop_id"].split(".")[0]
if callback_input_id == "total":
remaining = value
else:
#calculate remaining time in ms
remaining = value - (n * 100)
minute = (remaining // 60000)
second = (remaining % 60000) // 1000
milisecond = (remaining % 1000) // 10
return u'{:02d}:{:02d}.{:02d}'.format(minute, second, milisecond)
if __name__ == "__main__":
app.run_server(debug=True)
If you would like to see how @kahlenberg pseudo code is functioning.