yotamberk / timeline-plus Goto Github PK
View Code? Open in Web Editor NEWTimeline - chronological visualization of your data
License: MIT License
Timeline - chronological visualization of your data
License: MIT License
According to ISO-8601, the week starts with Monday, not Sunday like in the US or UK.
An option on whether to start the week on Monday or Sunday would be good.
Hi,
After upgrading from vis.js to timeline-plus,
I have a little problem because of the change in core.js, in line 220:
if (this.options.zoomKey && event[this.options.zoomKey]) return;
in vis.js the same line is : (line 206)
if (!this.options.zoomKey || event[this.options.zoomKey]) return;
This change broke the option to scroll in groups panel and zooming in center panel as default, without using zoomKey, when verticalScroll is set to true.
So what is the best solution to prefer zooming on scrolling in center panel without using a zoomKey?
I thought of adding an option and if so the onMouseWheel function will break if this option set to true.
First, thank a lot for you have done so far on vis.js and about timeline-plus, it works well (FYI;)
By cons and a priori it's not possible to do as described in title, in any case for now as far as know anyway...
So, I have done a test for find a solution...
It works fine on Chrome but unfortunately not on Firefox?
I've been working this for a while without understanding what I'm doing wrong...
Any idea about that?
Do you happen to know if we can use the @types/vis library, somehow, on your fork or if there's one planned for yours since it actually keeps the timeline up to date? I'm definitely interested in trying yours over the non-updated vis, but I cannot, easily, if there's no types for it.
Thanks!
I am looking at moving a project from vis.js-timelines to timeline-plus since vis seems pretty neglected. As a test I took my existing project and just swapped out the library and the timeline constructor. Since the project worked fine on vis I was expecting a smooth transition. However, when I went to load the page nothing appeared. When I checked the console I now had the warning Something is wrong with the Timeline scale. Limited drawing of grid lines to 1000 lines.
I'm not sure if this is a bug or if I am missing something in my conversion. For reference I am using the minified file from https://github.com/yotamberk/timeline-plus/blob/master/dist/timeline.min.js that I downloaded today (9-12-2018)
Tooltip is cut off if it is large and out of the time line view area. It is easily produced if only one item in the timeline and tooltip is high. Any work around instead of modifying the lib?
First of all I like the new feature of getting an alert if the user drops and item over another item in the timeline. I am looking for a way to use the normal item behaviour together with onDropObjectOnItem.
I want the user to get an alarm if an item is dropped over another item, but if not I want the item to be created. Is this possible somehow? Thankyou
I love the timeline you have designed and it works well within my application. I have it contained within its own user web control and all works perfectly if i use it outside of an update panel.
I can't however seem to get it to work from within an update panel.
I assumed it was because of the javascript block so i registered the javascript on pageload
` Try
Dim csName As String = "Timeline"
Dim SM As ScriptManager = ScriptManager.GetCurrent(Me.Page)
Dim JS As String = genrequiredjavascript()
SM.RegisterClientScriptBlock(Me.Page, Me.Page.[GetType](), csName, JS, False)
Catch ex As Exception
b.passerror(ex)
End Try
Protected Function genjavaarrays(ByRef idt As DataTable, ByRef gdt As DataTable)
Dim output As String = ""
Dim GSB As New StringBuilder
GSB.Append("var groups = new vis.DataSet([" & Environment.NewLine)
If gdt.Rows.Count > 0 Then
For i = 0 To gdt.Rows.Count - 1
Dim _Row As DataRow = gdt.Rows(i)
'GSB.Append("{id: " & i & ", content: '" & Trim(_Row("alarm_desc")) & "', value: " & _Row("Alarm_id") & "}," & Environment.NewLine)
GSB.Append("{id: " & _Row("Alarm_id") & ", content: '" & Trim(_Row("alarm_desc")) & "', value: " & _Row("Alarm_id") & "}," & Environment.NewLine)
Next
End If
GSB.Append(" ]);")
GSB.Append(Environment.NewLine)
output = output & GSB.ToString
GSB = Nothing
Dim SB As New StringBuilder
SB.Append("var items = new vis.DataSet([" & Environment.NewLine)
If idt.Rows.Count > 0 Then
For i = 0 To idt.Rows.Count - 1
Dim _Row As DataRow = idt.Rows(i)
SB.Append("{id: " & i & ", group: " & _Row("Alarm_ID") & ", content: '', start: '" & b.formatDateTimeforSQL(_Row("Alarm_Date_Time")) & "', type: 'point', ruid: '" & _Row("RU_ID") & "'}, " & Environment.NewLine)
Next
End If
SB.Append(" ]);")
SB.Append(Environment.NewLine)
output = output & SB.ToString
SB = Nothing
Return output
End Function
Private Function genrequiredjavascript() As String
Dim js As New StringBuilder
js.Append("<script type = ""text/javascript""")
js.Append(Environment.NewLine)
js.Append("// DOM element where the Timeline will be attached
var container = document.getElementById('DrawTimeline');")
js.Append(Environment.NewLine)
'<%= _GroupArrayList %>
'<%= _ArrayList %>
Dim dttb As DataTable = itemsDT
Dim Gdttb As DataTable = GroupDT
js.Append(genjavaarrays(dttb, Gdttb))
js.Append("
// Configuration for the Timeline
var options = {
dataAttributes 'all',
tooltip: { followMouse: true },
stack: false,
orientation: { axis 'top' },
width:'100%'
};")
js.Append("
// Create a Timeline
var timeline = New vis.Timeline(container);
timeline.setOptions(options);
timeline.setGroups(groups);
timeline.setItems(items);
timeline.on('click', function (properties) {
logEvent('click', properties);
});")
js.Append("
Function logEvent(event, properties) {
var Log = document.getElementById('Details');
// document.getElementById('lbldetails').innertext = 'liam';
Console.log(properties);
var alm = properties.item;
var grp = properties.group;
Console.log(alm)
var grpitem = groups.get(grp);
var Almitem = items.get(alm);
Console.log(Almitem)
//check i have a value for the instance And Not just a point on the timeline
If (Almitem.ruid!== undefined) Then {
$(""#lblALM"").text('Alarm Type: ' + grpitem.content);
$(""#lblRUID"").text('RUID: ' + Almitem.ruid);
$(""#lblDateTime"").text('Date Time: ' + properties.time);
}
}
Function move(percentage) {
var Range = timeline.getWindow();
var Interval = Range.end - Range.start;
timeline.setWindow({
start: Range.start.valueOf() - interval * percentage,
End : Range.end.valueOf() - interval * percentage
});
}
document.getElementById('zoomIn').onclick = function () { timeline.zoomIn(0.2); };
document.getElementById('zoomOut').onclick = function () { timeline.zoomOut(0.2); };
document.getElementById('moveLeft').onclick = function () { move(0.2); };
document.getElementById('moveRight').onclick = function () { move(-0.2); };
Return js.ToString
End Function`
i just don't get the timeline to appear
Any help would be greatly appreciated
Liam
I have set an ‚onDrop‘ Event on the timeline div. Unfortunately it does not execute.
sorry it was a stupid question. not related to timeline.plus
Is it possible to implement this timeline using Vue.js? How is it done?
When you click an item of the timeline that overlaps with other items of the same group, the click event only returns one item (the one on top of the stack). Is there a way to fetch all (overlapping) items that are underneath the click event? I could not find an option in the documentation to change this behaviour.
If we put option as below,
orientation: {
axis: 'top',
item: 'top'
},
initially the items in the same group arranged correctly from top to bottom, however if you scroll the timeline horizontally to some point where all rows are empty, and move back, the items are then arranged from bottom to top, after that it will keep constantly with such wrong order.
I guess it is a bug and could it be fixed or if there is any work around?
This will allow people to add jsbins with timeline-plus
+ allow people to use the project without extra actions (npm, git clone, etc.)
I have checked that this issue is interesting: almende/vis#4074
(I tried producing this image using the examples of this project but failed to reach them because of #64. So I used the example from vis.js instead, I hope that's ok.)
It seems like the background color is slightly offset for some reason. This is taken from the Background areas example
My first thought was that the areas were defined using a time that wasn't midnight, but looking at the code that doesn't seem to be correct. My best guess is that my timezone is playing a role here. I'm at UTC+2, which seems to sort of match the visual offset.
27000 items, 500 rendered,
calc(100%-px)
=> 18 seconds to paint, there are several paint/reflow events that take 1 second.
no calc(..)
Note: I'm still using vis.js timeline as I upgraded from CHAP timeline
to vis.js
, then realized this is the next fork.
WA:
vis.timeline.components.items.RangeItem.prototype._getDomComponentsSizes = function() {
// determine from css whether this box has overflow
this.overflow = false;//window.getComputedStyle(this.dom.frame).overflow !== 'hidden';
This avoids calc(100%-...px)
in rangeitem CSS, and it results in much nicer paints.
Note: I do understand it changes item rendering, however I like "WA" rendering even better.
Note: there might be better ways to workaround that, however I'm not an expert in CSS.
Copy of: almende/vis#3347
The last group is taller than the others.
It also can be seen on this demo : https://yotamberk.github.io/timeline-plus/examples/groups/groupsEditable.html
The height of each group is 41px except the last one which is 56px.
Browser: Firefox 63
Timeline-Plus: 2.2.2
React: 16.4.2
Browsers: Chrome 69.0.3497.100, Chrome-Dev 71.0.3573.0
Global align
option works as intended, but item specific align
has no effect. This bug is supposed to be fixed with 1df3237. There's an open issue for this bug in the vis repo.
const nodeContent = `
<div>
<div>
${data.name}
</div>
<div style="font-size: 0.85em; font-style: italic">
${quantity}
</div>
</div>
`;
const { id } = data;
const node = {
id,
content: nodeContent,
align: 'right', // <- this has no effect
title: nodeContent,
start,
};
I noticed that a lot of measurement and subsequent layout recalculation is taking place in the animation frame. A lot of measured values can be cached, and perf can be improved by batching reads and writes.
For eg., the line 5563:
label.style.width = width + 'px'; // set width to prevent overflow
takes a whole 6ms (on a Ryzen 7). I'm combining this with a canvas, and its framerates end up being killed every time the timeline is moved.
Just started an issue to list ideas here.
Hi @yotamberk and thanks for having forked this Timeline module from Vis ! 😄
I want to improve timeline-plus
by adding the ability to "snap" non-timeline-item to the timeline when dragging.
In other words, I want to :
dragEnter
in the timelineI found in the code a beggining of implementation https://github.com/yotamberk/timeline-plus/blob/master/lib/timeline/Core.js#L302 (I think).
Can you give me hints to develop this feature ? (and make a PR to improve the lib of course 😄 )
Added a issue to the vis.js repository (almende/vis#4136), however have not had a response yet.
Thought I'd reach out here to see if anyone had thoughts on how this can be achieved.
Thanks.
timeline-plus/lib/timeline/Timeline.js
Lines 559 to 562 in 06ec120
In my case the stacktrace is as follows:
Core.redraw
-> Emitter.emit
(event=changed) -> me.fit({animation:false});
-> Timeline.fit
-> Timeline.getItemRange
set the groupHeightMode to fixed,
when navigate the timeline,the item.top will be changed and then the group height will be changed.
any solution? thx very much.
i can't run timeline in jsfiddle.
so i remake the problem in https://jshare.com.cn/temp/FptwxQ
pay attention to the "two group".
I guess, maybe sth wrong with the _calculateHeight code, because the item.top change frequently and then the group height changed. I'm not sure.
key: '_calculateHeight',
value: function _calculateHeight(margin) {
// recalculate the height of the group
var height = void 0;
var items = void 0;
if (this.heightMode === 'fixed') {
items = util.toArray(this.items);
} else {
// default or 'auto'
items = this.visibleItems;
}
if (items.length > 0) {
var min = items[0].top;
var max = items[0].top + items[0].height;
util.forEach(items, function (item) {
min = Math.min(min, item.top);
max = Math.max(max, item.top + item.height);
});
if (min > margin.axis) {
// there is an empty gap between the lowest item and the axis
var offset = min - margin.axis;
max -= offset;
util.forEach(items, function (item) {
item.top -= offset;
});
}
height = max + margin.item.vertical / 2;
} else {
height = 0;
}
height = Math.max(height, this.props.label.height);
return height;
}
specially
if (min > margin.axis) {
// there is an empty gap between the lowest item and the axis
var offset = min - margin.axis;
max -= offset;
util.forEach(items, function (item) {
item.top -= offset;
});
Hi,
After upgrading from vis.js version 4.17 to timeline-plus we got really bad perfomance. We have about 450 groups and 3000 items in them. I started to investigate what had changed and managed to pin it down to that something had changed between vis 4.17 and 4.18. So after a diff of these two versions i noticed that the following code had been removed from updateItemsInRange
in Group.js
if (!this.isVisible && this.groupId != "__background__") {
for (var i = 0; i < oldVisibleItems.length; i++) {
var item = oldVisibleItems[i];
if (item.displayed) item.hide();
}
return visibleItems;
}
If i put this code back the perfomance is back to normal but im not sure that this does not affect something else.
I also noticed that without the code we get alot of style recalculations and layouts.
Would it be possible to put this code back in timeline-plus or does this affect something else?
Currently Group. _updateItemsInRange
computes the set of visible items, however there's no way to customize the set of "actually visible" items there.
https://github.com/yotamberk/timeline-plus/blob/master/lib/timeline/component/Group.js#L851
It would be nice if that could be customized.
Possible use cases:
Hi all,
I am using this timeline that works smarter than the old project and this improves our page.
But i have a question: for some operation, I need to update the timeline only for some groups, but operation setItems refreshes all items.
Is there a possibility to remove items, add items and then refresh the user interface only for them?
Under certain circumstances, the timeline does not appear until after the user resizes the window.
(Duplicate of this issue by request of @yotamberk.)
This issue reproduces in both of the following browsers:
Safari Version 11.1.2 (12605.3.8.1)
Version 68.0.3440.106 (Official Build) (64-bit)
timeline
I took a look at the source, and it seems that the behavior to set the timeline's root DOM node as hidden is was introduced in #3530, in response to feature request #3529.
Specifically, this line seems to hide the root DOM node if no options are provided, or if there's no value provided for the RTL option. It doesn't seem to me that the component's visibility is appropriately changed back after guessing RTL. (I see this assignment on line 185, but it's also guarded by some conditional logic, and it seems that it's not being triggered in my use case.)
I don't completely understand the context of the change, so I can't provide a fix. (My gut says the change is prevent the timeline from flashing in the "wrong" direction, but I'm not sure.) A workaround for me was to add rtl: false
to my options payload. (This prevents the root DOM node from being hidden in the first place.)
I noticed that the !options
clause on line 67 is probably redundant. The line above that one calls util.deepExtend
. I glanced quickly at util.deepExtend
and it seems that it always returns something (except for when it throws) and so !options
, will always be false
on the following line. Empty objects are truthy, and, as I understand it, line 67 is guaranteed to have options set.
Also, if options
is indeed undefined
and !options
is true
, then line 74 may result in a runtime error.
This issue seems to possibly be tangentially related to this issue (and another one, which I haven't been able to find) where setting ranges is a workaround for the missing rtl
option.
I don't have a minimum reproduction sample right now, happy to provide if necessary.
Hi,
the have checked that the following issue almende/vis#3994 is also present in timeline-plus.
In my project I have managed the problem by comparing the "start" and the "end" when an item is modified: If the "end" is before than the "start" then the item returns to previous state.
I'm trying the groupsEditable.html
example, and I'm seeing several glitches regarding the drag-to-reorder functionality.
I'm using the versions of timeline that's on unpkg, and have verified the behaviour above on both Chrome (69) and Firefox (62).
Let me know if I should add a couple of illustrations to show this better.
Hi!!
I have checked that the performance of time-plus in Google chrome is awesome.
However, in Firefox, the Zoom with the mousewheel does not work and the displacement of the timeline when is dragged is a bit weird.
The subgroups are falling off the group when zooming or panning, at certain levels.
The below link has more details:
The jsfiddle uses the vis.js libraries, because I did not figure how to upload the timeline-plus files and could
not find links to use.
Thanks
incorporate examples in an iframe
I'm facing a problem when I have 3 or more levels of nested groups. If I'm trying to collapse first level then third level is not collapsed and placed at the top of the timeline.
As a quick fix I did small change in the logic to collapse all subgroups at _onGroupClick:
var getAllNestedGroups = function(groupId){
var curGroup = groupsData.get(groupId);
if(!curGroup.nestedGroups) {
return;
}
var subgroups = curGroup.nestedGroups;
curGroup.nestedGroups.forEach(function (g){
var sbgrps = getAllNestedGroups(g);
if(sbgrps){
subgroups = subgroups.concat(sbgrps);
}
});
return subgroups;
}
var nestedGroups = groupsData.get(getAllNestedGroups(group.groupId)).map(function (nestedGroup) {
nestedGroup.visible = nestingGroup.showNested;
return nestedGroup;
});
The core problem with the vertical scrollbar in Timeline from #3145 (scrollbar doesn't work without groups) and #3954, #3066 (how to place the scrollbar on the right) is that scrolling the main content via a scrollbar is done by the vis-label-set div from ItemSet. When groups are enabled, this div has a non-zero width and height that matches the content area, and scrolling the center content area is synchronized and everything works pretty well.
However, whenever there are no groups, that div has 0 width and is not scrollable. Moreover, this scrollbar ends up on the left for ltr and right for rtl, which is backwards. Three ideas come to mind to fix this:
Most Compatible. When there are no groups, reverse the attachment of the labelSet from ItemSet and force an explict width of say 1px, in addition to some general bug fixes I made in this branch in my fork that hasn't been fully adapted to support groups. The problem with this is that groups can be removed or added later, and that would mean swapping attachment of the nodes, which is a concern of the Timeline Core code not ItemSet, so this needs to be decoupled (it should anyways). Moreover swapping attachment dynamically isn't done yet, but not the worst thing to do.
Add a dedicated vertical scroll area. Add another vis-panel that would sit to the right or left of the center panel depending on options.rtl and have it function as the scroll area. This would cause some behavioral changes, namely it would mean that the scrollbar for groups would be on the left of the content, and break two-wheel scrolling and other native scrolling functionality. It would be easier for users to style and move themselves if they wish though.
Cleanest and most natural solution, but breaking changes. Set the center content area to have overflow-y: auto when verticalScroll is enabled (and likely the overflow-x: auto when horizontalScroll is enabled) and syncronize the two scroll areas when groups are available. This is the most natural, as two finger scorlling, mousewheel, etc will all work with the center area more naturally, Chrome will auto-hide scrollbars too, and probably fix things like #3353, #3864. A variant on this is have verticalScroll take a string options of auto and scroll to force those specific modes, with boolean true meaning overflow-y: scroll.
Thoughts? I suggest no 3, but can see no 1 if there are issues with 3 I'm not seeing.
As soon as I add bootstrap to my webpage. I can´t use fixed height for groups anymore.
I have added a jsfiddle.
This way you can add a custom button like the delete button. Just add your css
`Item.prototype._repaintDeleteButton = function (anchor) {
if (this.selected && this.options.editable.remove && !this.dom.deleteButton) {
// create and show button
var me = this;
var deleteButton = document.createElement('div');
deleteButton.className = 'delete';
deleteButton.title = 'Delete this item';
var controlButton = document.createElement('div');
controlButton.className = 'controlbutton';
controlButton.title = 'Test Event';
Hammer(deleteButton, {
preventDefault: true
}).on('tap', function (event) {
me.parent.removeFromDataSet(me);
event.stopPropagation();
});
Hammer(controlButton, {
preventDefault: true
}).on('tap', function (event) {
console.log("test");
});
anchor.appendChild(deleteButton);
this.dom.deleteButton = deleteButton;
anchor.appendChild(controlButton);
this.dom.controlButton = controlButton;
}
else if (!this.selected && this.dom.deleteButton) {
// remove button
if (this.dom.deleteButton.parentNode) {
this.dom.deleteButton.parentNode.removeChild(this.dom.deleteButton);
}
this.dom.deleteButton = null;
if (this.dom.controlButton.parentNode) {
this.dom.controlButton.parentNode.removeChild(this.dom.controlButton);
}
this.dom.controlButton = null;
}
};`
Is there a way to have the "zoom on mousewheel" handler of the central timeline element also work while the mouse hovers over the time axis (or axes, if 'both' is set)?
Would it make sense to attach the 'scroll' listener from https://github.com/yotamberk/timeline-plus/blob/master/lib/timeline/Core.js#L268 to this.dom.bottom
and this.dom.top
as well?
While looking at the code I saw that there's ~20 places mentioning deprecated things that should be removed at some point.
I just thought I should mention that considering this is a fork, it kind of makes sense to do those edits now. Less baggage into the new project, so to speak.
https://en.wikipedia.org/wiki/Interval_scheduling#Greedy_polynomial_solution
Current stack.stack is O(N^2)
: https://github.com/yotamberk/timeline-plus/blob/master/lib/timeline/Stack.js#L57-L70
It looks like the following O(N log N)
algorithm should produce sane outputs:
I went to https://yotamberk.github.io/examples and clicked examples and then an example - and get a new set of navigation links. From there I clicked examples and then an example - and get a new set of navigation links. From there I clicked examples and then an example - and get a new set of navigation links.
I think you're getting the idea. :)
Version: 2.1.8
Browser: Internet Explorer 11
Problem: basicUsage.html shows a blank browser window
JS error message: Object doesn't support property or method 'includes'
Workaround:
if(Array.prototype.includes == undefined) {
Array.prototype.includes = function(item) {
return this.indexOf(item) > -1? true : false;
}
}
Best regards
Daniel
Hi!,
I am trying to pass my project from vis to timeline-plus, and I have checked that if you create a timeline like in many examples:
var timeline = new timeline.Timeline(container);
In most cases you can get the following error:
(Firefox) -> "TypeError: timeline is undefined"
(Chrome) -> "Uncaught TypeError: Cannot read property 'DataSet' of undefined at HTMLDocument."
The solution is not to create a timeline with var name "timeline". For instance:
var myTimeline = new timeline.Timeline(container);
I hope this would be helpful.
In vis there was a PR almende/vis#3818 to fix almende/vis#3734 which hasn't made it into this repo.
Is there an easy way to bring it in or should I re-create the commit and make a new PR? Github won't let the original PR target this repo since it isn't listed as a fork of vis.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.