Change Bar hover behaviour, Bar animation

This commit is contained in:
Faris Ansari 2018-02-17 23:23:05 +05:30
parent e55107ee82
commit 390fd2d324
8 changed files with 160 additions and 67 deletions

View File

@ -68,12 +68,16 @@
.gantt .bar-wrapper { .gantt .bar-wrapper {
cursor: pointer; } cursor: pointer; }
.gantt .bar-wrapper:hover .bar { .gantt .bar-wrapper:hover .bar {
stroke-width: 2; } fill: #a9b5c1; }
.gantt .bar-wrapper:hover .bar-progress {
fill: #8a8aff; }
.gantt .bar-wrapper:hover .handle { .gantt .bar-wrapper:hover .handle {
visibility: visible; visibility: visible;
opacity: 1; } opacity: 1; }
.gantt .bar-wrapper.active .bar { .gantt .bar-wrapper.active .bar {
stroke-width: 2; } fill: #a9b5c1; }
.gantt .bar-wrapper.active .bar-progress {
fill: #8a8aff; }
.gantt .lower-text, .gantt .upper-text { .gantt .lower-text, .gantt .upper-text {
font-size: 12px; font-size: 12px;

120
dist/frappe-gantt.js vendored
View File

@ -245,7 +245,64 @@ function createSVG(tag, attrs) {
return elem; return elem;
} }
function animateSVG(svgElement, attr, from, to) {
const animatedSvgElement = getAnimationElement(svgElement, attr, from, to);
if (animatedSvgElement === svgElement) {
// triggered 2nd time programmatically
// trigger artificial click event
const event = document.createEvent('HTMLEvents');
event.initEvent('click', true, true);
event.eventName = 'click';
animatedSvgElement.dispatchEvent(event);
}
}
function getAnimationElement(
svgElement,
attr,
from,
to,
dur = '0.4s',
begin = '0.1s'
) {
const animEl = svgElement.querySelector('animate');
if (animEl) {
$.attr(animEl, {
attributeName: attr,
from,
to,
dur,
begin: 'click + ' + begin // artificial click
});
return svgElement;
}
const animateElement = createSVG('animate', {
attributeName: attr,
from,
to,
dur,
begin,
calcMode: 'spline',
values: from + ';' + to,
keyTimes: '0; 1',
keySplines: cubic_bezier('ease-out')
});
svgElement.appendChild(animateElement);
return svgElement;
}
function cubic_bezier(name) {
return {
ease: '.25 .1 .25 1',
linear: '0 0 1 1',
'ease-in': '.42 0 1 1',
'ease-out': '0 0 .58 1',
'ease-in-out': '.42 0 .58 1'
}[name];
}
$.on = (element, event, selector, callback) => { $.on = (element, event, selector, callback) => {
if (!callback) { if (!callback) {
@ -385,6 +442,8 @@ class Bar {
append_to: this.bar_group append_to: this.bar_group
}); });
animateSVG(this.$bar, 'width', 0, this.width);
if (this.invalid) { if (this.invalid) {
this.$bar.classList.add('bar-invalid'); this.$bar.classList.add('bar-invalid');
} }
@ -402,6 +461,8 @@ class Bar {
class: 'bar-progress', class: 'bar-progress',
append_to: this.bar_group append_to: this.bar_group
}); });
animateSVG(this.$bar_progress, 'width', 0, this.progress_width);
} }
draw_label() { draw_label() {
@ -412,7 +473,8 @@ class Bar {
class: 'bar-label', class: 'bar-label',
append_to: this.bar_group append_to: this.bar_group
}); });
this.update_label_position(); // labels get BBox in the next tick
requestAnimationFrame(() => this.update_label_position());
} }
draw_resize_handles() { draw_resize_handles() {
@ -467,27 +529,35 @@ class Bar {
bind() { bind() {
if (this.invalid) return; if (this.invalid) return;
this.setup_click_event(); this.setup_click_event();
this.show_details();
// this.bind_resize_progress();
} }
show_details() { setup_click_event() {
this.group.onclick = e => { $.on(this.group, 'click', e => {
if (this.action_completed) { if (this.action_completed) {
// just finished a move action, wait for a few seconds // just finished a move action, wait for a few seconds
return; return;
} }
const start_date = date_utils.format(this.task._start, 'MMM D'); if (this.group.classList.contains('active')) {
const end_date = date_utils.format(this.task._end, 'MMM D'); this.gantt.trigger_event('click', [this.task]);
const subtitle = start_date + ' - ' + end_date; }
this.gantt.unselect_all();
this.group.classList.toggle('active');
this.gantt.show_popup({ this.show_popup();
target_element: this.$bar, });
title: this.task.name, }
subtitle: subtitle
}); show_popup() {
}; const start_date = date_utils.format(this.task._start, 'MMM D');
const end_date = date_utils.format(this.task._end, 'MMM D');
const subtitle = start_date + ' - ' + end_date;
this.gantt.show_popup({
target_element: this.$bar,
title: this.task.name,
subtitle: subtitle
});
} }
update_bar_position({ x = null, width = null }) { update_bar_position({ x = null, width = null }) {
@ -517,20 +587,6 @@ class Bar {
// this.update_details_position(); // this.update_details_position();
} }
setup_click_event() {
this.group.onclick = () => {
if (this.action_completed) {
// just finished a move action, wait for a few seconds
return;
}
if (this.group.classList.contains('active')) {
this.gantt.trigger_event('click', [this.task]);
}
this.gantt.unselect_all();
this.group.classList.toggle('active');
};
}
date_changed() { date_changed() {
const { new_start_date, new_end_date } = this.compute_start_end_date(); const { new_start_date, new_end_date } = this.compute_start_end_date();
this.task._start = new_start_date; this.task._start = new_start_date;
@ -662,6 +718,7 @@ class Bar {
update_label_position() { update_label_position() {
const bar = this.$bar, const bar = this.$bar,
label = this.group.querySelector('.bar-label'); label = this.group.querySelector('.bar-label');
if (label.getBBox().width > bar.getWidth()) { if (label.getBBox().width > bar.getWidth()) {
label.classList.add('big'); label.classList.add('big');
label.setAttribute('x', bar.getX() + bar.getWidth() + 5); label.setAttribute('x', bar.getX() + bar.getWidth() + 5);
@ -849,6 +906,7 @@ class Popup {
this.pointer.style.top = this.pointer.style.top =
this.title.clientHeight / 2 - this.title.clientHeight / 2 -
this.pointer.getBoundingClientRect().height + this.pointer.getBoundingClientRect().height +
2 +
'px'; 'px';
} }
@ -1421,7 +1479,7 @@ class Gantt {
bind_grid_click() { bind_grid_click() {
this.layers.grid.onclick = () => { this.layers.grid.onclick = () => {
this.unselect_all(); this.unselect_all();
this.popup && this.popup.hide(); this.hide_popup();
}; };
} }
@ -1661,6 +1719,10 @@ class Gantt {
this.popup.show(options); this.popup.show(options);
} }
hide_popup() {
this.popup && this.popup.hide();
}
trigger_event(event, args) { trigger_event(event, args) {
if (this.options['on_' + event]) { if (this.options['on_' + event]) {
this.options['on_' + event].apply(null, args); this.options['on_' + event].apply(null, args);

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
import date_utils from './date_utils'; import date_utils from './date_utils';
import { createSVG } from './svg_utils'; import { $, createSVG, animateSVG } from './svg_utils';
export default class Bar { export default class Bar {
constructor(gantt, task) { constructor(gantt, task) {
@ -85,6 +85,8 @@ export default class Bar {
append_to: this.bar_group append_to: this.bar_group
}); });
animateSVG(this.$bar, 'width', 0, this.width);
if (this.invalid) { if (this.invalid) {
this.$bar.classList.add('bar-invalid'); this.$bar.classList.add('bar-invalid');
} }
@ -102,6 +104,8 @@ export default class Bar {
class: 'bar-progress', class: 'bar-progress',
append_to: this.bar_group append_to: this.bar_group
}); });
animateSVG(this.$bar_progress, 'width', 0, this.progress_width);
} }
draw_label() { draw_label() {
@ -112,7 +116,8 @@ export default class Bar {
class: 'bar-label', class: 'bar-label',
append_to: this.bar_group append_to: this.bar_group
}); });
this.update_label_position(); // labels get BBox in the next tick
requestAnimationFrame(() => this.update_label_position());
} }
draw_resize_handles() { draw_resize_handles() {
@ -167,27 +172,35 @@ export default class Bar {
bind() { bind() {
if (this.invalid) return; if (this.invalid) return;
this.setup_click_event(); this.setup_click_event();
this.show_details();
// this.bind_resize_progress();
} }
show_details() { setup_click_event() {
this.group.onclick = e => { $.on(this.group, 'click', e => {
if (this.action_completed) { if (this.action_completed) {
// just finished a move action, wait for a few seconds // just finished a move action, wait for a few seconds
return; return;
} }
const start_date = date_utils.format(this.task._start, 'MMM D'); if (this.group.classList.contains('active')) {
const end_date = date_utils.format(this.task._end, 'MMM D'); this.gantt.trigger_event('click', [this.task]);
const subtitle = start_date + ' - ' + end_date; }
this.gantt.unselect_all();
this.group.classList.toggle('active');
this.gantt.show_popup({ this.show_popup();
target_element: this.$bar, });
title: this.task.name, }
subtitle: subtitle
}); show_popup() {
}; const start_date = date_utils.format(this.task._start, 'MMM D');
const end_date = date_utils.format(this.task._end, 'MMM D');
const subtitle = start_date + ' - ' + end_date;
this.gantt.show_popup({
target_element: this.$bar,
title: this.task.name,
subtitle: subtitle
});
} }
update_bar_position({ x = null, width = null }) { update_bar_position({ x = null, width = null }) {
@ -217,20 +230,6 @@ export default class Bar {
// this.update_details_position(); // this.update_details_position();
} }
setup_click_event() {
this.group.onclick = () => {
if (this.action_completed) {
// just finished a move action, wait for a few seconds
return;
}
if (this.group.classList.contains('active')) {
this.gantt.trigger_event('click', [this.task]);
}
this.gantt.unselect_all();
this.group.classList.toggle('active');
};
}
date_changed() { date_changed() {
const { new_start_date, new_end_date } = this.compute_start_end_date(); const { new_start_date, new_end_date } = this.compute_start_end_date();
this.task._start = new_start_date; this.task._start = new_start_date;
@ -362,6 +361,7 @@ export default class Bar {
update_label_position() { update_label_position() {
const bar = this.$bar, const bar = this.$bar,
label = this.group.querySelector('.bar-label'); label = this.group.querySelector('.bar-label');
if (label.getBBox().width > bar.getWidth()) { if (label.getBBox().width > bar.getWidth()) {
label.classList.add('big'); label.classList.add('big');
label.setAttribute('x', bar.getX() + bar.getWidth() + 5); label.setAttribute('x', bar.getX() + bar.getWidth() + 5);

View File

@ -92,7 +92,11 @@ $handle-color: #ddd;
&:hover { &:hover {
.bar { .bar {
stroke-width: 2; fill: darken($bar-color, 5);
}
.bar-progress {
fill: darken($blue, 5);
} }
.handle { .handle {
@ -103,7 +107,11 @@ $handle-color: #ddd;
&.active { &.active {
.bar { .bar {
stroke-width: 2; fill: darken($bar-color, 5);
}
.bar-progress {
fill: darken($blue, 5);
} }
} }
} }

View File

@ -566,7 +566,7 @@ export default class Gantt {
bind_grid_click() { bind_grid_click() {
this.layers.grid.onclick = () => { this.layers.grid.onclick = () => {
this.unselect_all(); this.unselect_all();
this.popup && this.popup.hide(); this.hide_popup();
}; };
} }
@ -806,6 +806,10 @@ export default class Gantt {
this.popup.show(options); this.popup.show(options);
} }
hide_popup() {
this.popup && this.popup.hide();
}
trigger_event(event, args) { trigger_event(event, args) {
if (this.options['on_' + event]) { if (this.options['on_' + event]) {
this.options['on_' + event].apply(null, args); this.options['on_' + event].apply(null, args);

View File

@ -55,6 +55,7 @@ export default class Popup {
this.pointer.style.top = this.pointer.style.top =
this.title.clientHeight / 2 - this.title.clientHeight / 2 -
this.pointer.getBoundingClientRect().height + this.pointer.getBoundingClientRect().height +
2 +
'px'; 'px';
} }

View File

@ -37,8 +37,8 @@ function getAnimationElement(
attr, attr,
from, from,
to, to,
dur = '0.3s', dur = '0.4s',
begin = '0s' begin = '0.1s'
) { ) {
const animEl = svgElement.querySelector('animate'); const animEl = svgElement.querySelector('animate');
if (animEl) { if (animEl) {
@ -57,13 +57,27 @@ function getAnimationElement(
from, from,
to, to,
dur, dur,
begin begin,
calcMode: 'spline',
values: from + ';' + to,
keyTimes: '0; 1',
keySplines: cubic_bezier('ease-out')
}); });
svgElement.appendChild(animateElement); svgElement.appendChild(animateElement);
return svgElement; return svgElement;
} }
function cubic_bezier(name) {
return {
ease: '.25 .1 .25 1',
linear: '0 0 1 1',
'ease-in': '.42 0 1 1',
'ease-out': '0 0 .58 1',
'ease-in-out': '.42 0 .58 1'
}[name];
}
$.on = (element, event, selector, callback) => { $.on = (element, event, selector, callback) => {
if (!callback) { if (!callback) {
callback = selector; callback = selector;