Our pure JavaScript Scheduler component


Post by Luffy »

sergey.maltsev wrote: Tue Oct 08, 2019 10:53 am
Thank you for reporting this bug. I've created a ticket to fix it.
https://app.assembla.com/spaces/bryntum/tickets/9355-cannot-read-property---39-targethidden--39--on-async-tooltip-display/details
Hi,

Any Update on this ticket?
This is bit urgent.

Thank you.

Post by Maxim Gorkovsky »

Hello.
Now news on the ticket.

While it looks difficult to change event tip behavior, you can implement your own tip using two events: eventmouseover and eventmouseout

Basic idea is as follows:
1. diable default tip, if it doesn't work like you expect
2. implement own scheduler feature which would listen to events above to show/hide tip
class MyTip extends InstancePlugin {
    static get pluginConfig() {
        return {
            chain : ['render']
        };
    }
    
    construct(client, config) {
        super.construct(client, config);
        
        client.on({
            eventmouseover : this.onEventMouseOver,
            eventmouseout  : this.onEventMouseOut,
            thisObj        : this
        });
    }
    
    render() {
        let client = this.client;
        
        this.tip = new Tooltip({
            forSelector    : '.b-sch-event',
            scrollAction   : 'realign',
            forElement     : client.timeAxisSubGridElement,
            showOnHover    : true,
            hoverDelay     : 0,
            hideDelay      : 100,
            anchorToTarget : true,
            allowOver      : true,
            html           : 'Loading'
        });
    }
    
    onEventMouseOver({ eventRecord }) {
        this.activeRecord = eventRecord;
        
        this.tip.show();
        this.tip.html = 'Loading';
        
        setTimeout(() => {
            if (this.tip.isVisible && this.activeRecord === eventRecord) {
                this.tip.html = 'Loaded';
            }
        }, 2000);
    }
    
    onEventMouseOut() {
        this.activeRecord = null;
    }
}

GridFeatureManager.registerFeature(MyTip, true, 'Scheduler');

new Scheduler({
  features : { 
    eventTooltip : false
  }
})

Post by Luffy »

Hello Maxim,

This work great. Thanks. I was able to display the tooltip using my own tip as you suggested. (even though this didnt work viewtopic.php?f=51&t=12455&p=65603&hilit=Async#p65603)

But there is a little problem.
Tootltip goes beyond the event when the event is too long.
left-right.png
left-right.png (81.98 KiB) Viewed 2065 times
is there anyway to get this to the left most end if the event is too long.
like this.
well worked left-right.png
well worked left-right.png (68.52 KiB) Viewed 2065 times

Post by Luffy »

any update on this please.

Post by Luffy »

To over come this issue i made
anchorToTarget: false
.

But when i do that cannot identify which events owns the tooltip.
clearly-identify-which-event-owns-the-tooltip.gif
clearly-identify-which-event-owns-the-tooltip.gif (1.33 MiB) Viewed 2047 times
In that case, is there a anyway to make the event keep highlighted or selected until the tooltip is close.

or any suggestion to clearly identify which event owns the tooltip.


All of these troubles are because of the tooltip goes beyond the event when the event is too long.
tooltip goes off.png
tooltip goes off.png (51.5 KiB) Viewed 2047 times
this is my code.
class RmsEventTooltip extends InstancePlugin {
  client: any;
  tip: any;
  activeRecord: any;
  static get pluginConfig() {
    return {
      chain: ['render']
    };
  }

  construct(client, config) {
    super.construct(client, config);

    client.on({
      eventmouseover: this.onEventMouseOver,
      eventmouseout: this.onEventMouseOut,
      thisObj: this
    });
  }

  render() {
    const client = this.client;

    this.tip = new Tooltip({
      forSelector: '.b-sch-event',
      scrollAction: 'hide', // hide the widget when scroll
      forElement: client.timeAxisSubGridElement,
      showOnHover: true,
      hoverDelay: 0,
      hideDelay: 100,
      anchorToTarget: false,
      // floating: true, // hide tooltip when the dom scrolls
      // positioned: true,
      // anchor: true,
      // trackMouse: true,
      // scrollAction: realign,
      allowOver: true,
      // align: 'l-r',
      style: { fontSize: '0.85rem' }
    });
  }

  onEventMouseOver({ eventRecord }) {
    this.activeRecord = eventRecord;
    this.tip.show();
    this.tip.html = 'Loading';
    makeEventTootip(eventRecord).then(response => {
      this.tip.html = response;
    });
  }

  onEventMouseOut() {
    this.activeRecord = null;
  }
}

GridFeatureManager.registerFeature(RmsEventTooltip, true, 'Scheduler');

Post by Luffy »

Found a way to apply a style and remove that style when the tooltip is hiding.
happy case.gif
happy case.gif (714.13 KiB) Viewed 2046 times
But as you can see from the below gif, it will not trigger the HIDE event if you move the cursor across the tooltip and then goes to an new event.
sad case.gif
sad case.gif (776.09 KiB) Viewed 2046 times
my code is,
class RmsEventTooltip extends InstancePlugin {
  client: any;
  tip: any;
  activeRecord: any;
  static get pluginConfig() {
    return {
      chain: ['render']
    };
  }

  construct(client, config) {
    super.construct(client, config);

    client.on({
      eventmouseover: this.onEventMouseOver,
      eventmouseout: this.onEventMouseOut,
      thisObj: this
    });
  }

  render() {
    const client = this.client;

    this.tip = new Tooltip({
      forSelector: '.b-sch-event',
      scrollAction: 'hide', // hide the widget when scroll
      forElement: client.timeAxisSubGridElement,
      showOnHover: true,
      hoverDelay: 0,
      hideDelay: 100,
      anchorToTarget: false,
      // floating: true, // hide tooltip when the dom scrolls
      // positioned: true,
      // anchor: true,
      // trackMouse: true,
      // scrollAction: realign,
      allowOver: true,
      // align: 'l-r',
      style: { fontSize: '0.85rem' },
      mouseOffsetX: 2,
      mouseOffsetY: 2,
      listeners: {
        hide: this.removeEventSelectedStyle.bind(this)
        // destroy : this.removeEventSelectedStyle.bind(this) // <<<<<<<<this event does not work for some reason
      }
    });
  }

  // Remove the applied styles from the active event, when the tooltip hide
  removeEventSelectedStyle() {
    console.log('removeEventSelected');
    const element = this.client.getElementFromEventRecord(this.activeRecord);
    element.classList.remove('b-sch-event-selected');
    this.activeRecord = null;
  }

  onEventMouseOver({ eventRecord }) {
    this.activeRecord = eventRecord;
    this.tip.show();
    this.tip.html = 'Loading';
    makeEventTootip(eventRecord).then(response => {
      this.tip.html = response;
    });

    // Make the active record highlighted until the tooltip is open
    const element = this.client.getElementFromEventRecord(this.activeRecord);
    element.classList.add('b-sch-event-selected');
  }

  onEventMouseOut() {
    // this.activeRecord = null;
  }
}

GridFeatureManager.registerFeature(RmsEventTooltip, true, 'Scheduler');
anyhow these are the methods i have tried. But no luck in any of these.
if i can show the arrow tip anchored to the related event, everything will be fine.

Post by pmiklashevich »

if i can show the arrow tip anchored to the related event, everything will be fine.
You want anchor to be shown but in you code I see "anchor: true" commented out. Why? Did I miss something?

Pavlo Miklashevych
Sr. Frontend Developer


Post by Luffy »

Yes. I commented it because that makes tooltip appears form somewhere else when my event is too long.
That is the reason for all of these troubles.
if ancor true.png
if ancor true.png (62.98 KiB) Viewed 2031 times

code :
  render() {
    const client = this.client;

    this.tip = new Tooltip({
      forSelector: '.b-sch-event',
      scrollAction: 'hide', // hide the widget when scroll
      forElement: client.timeAxisSubGridElement,
      showOnHover: true,
      hoverDelay: 0,
      hideDelay: 100,
      // anchorToTarget: false,
      floating: true, // hide tooltip when the dom scrolls
      // positioned: true,
      anchor: true,
      // trackMouse: true,
      // scrollAction: realign,
      allowOver: true,
      // align: 'l-r',
      style: { fontSize: '0.85rem' },
      // mouseOffsetX: 2,
      // mouseOffsetY: 2,
      listeners: {
        paint: this.removeEventSelectedStyle.bind(this)
        // destroy : this.removeEventSelectedStyle.bind(this) // <<<<<<<<this event does not work for some reason
      }
    });
  }

Post by pmiklashevich »

There is private 'clippedBy' config which restricts area of the target element:
new Tooltip({
    clippedBy    : [scheduler.timeAxisSubGridElement, scheduler.bodyContainer],
    ....
It should do the trick. Please try it out and let us know how it works for you. We will discuss the possibility of making it public.
https://app.assembla.com/spaces/bryntum/tickets/9444-make---39-clippedby--39--config-public-for-tooltips/details

By the way, why don't you use EventTooltip feature if you're showing a tooltip for the events?

Pavlo Miklashevych
Sr. Frontend Developer


Post by pmiklashevich »

Another option is to extend TooltipBase and implement the logic you need. TooltipBase already uses the "clippedBy" config. That would be the proper way to achieve your goal.

Please also keep in mind, the extra capability Tooltip has over Popup is the various ways it can be pointed at a target and be sensitive to mouseovers and mouseouts and timings. If you don't need that extra things, you can just listen to mouseover and show a Popup.

Cheers!

Pavlo Miklashevych
Sr. Frontend Developer


Post Reply