Ejemplo n.º 1
0
 def _tooltip_handler(self, e):
     ev = create_pointer_event(self.node, e)
     x, y = ev.pos
     # Get tooltip object - if text is None it means no tooltip
     ob = self._tooltips.pick(x, y)
     if ob is not None and not ob.text:
         ob = None
     # Handle touch events - show tt during a touch, but only after a delay
     delay = 400
     if e.type == "touchstart":
         delay = 200
     elif e.type == "touchend" or e.type == "touchcancel" or e.type == "touchmove":
         ob = None
     # Update our tooltip div
     if ob is not None:
         if e.type == "mousedown":  # down -> hide while we're over it
             self._tooltipdiv.style.display = "none"
         elif self._mouse_tracking:  # dont show tooltips while dragging
             pass
         elif self._tooltipdiv.rect != ob.rect:  # note: deep comparison
             # Prepare for showing tooltip, then show after a delay
             self._tooltipdiv.rect = ob.rect
             self._tooltipdiv.innerText = ob.text
             self._tooltipdiv.style.display = "block"
             self._tooltipdiv.style.transition = "none"
             self._tooltipdiv.style.opacity = 0
             if ob.positioning == "mouse":
                 self._tooltipdiv.ypos = y - 20
             elif ob.positioning == "below":
                 self._tooltipdiv.ypos = ob.rect[3]
             else:  # ob.positioning == "ob"
                 self._tooltipdiv.ypos = ob.rect[1]
             self._tooltipdiv.style.top = self._tooltipdiv.ypos + "px"
             if x < self.w - 200:
                 if ob.positioning == "below":
                     self._tooltipdiv.xpos = ob.rect[0] - 10
                 else:
                     self._tooltipdiv.xpos = ob.rect[2]
                 self._tooltipdiv.style.left = self._tooltipdiv.xpos + "px"
                 self._tooltipdiv.style.right = None
             else:
                 if ob.positioning == "below":
                     self._tooltipdiv.xpos = self.w - ob.rect[2] - 10
                 else:
                     self._tooltipdiv.xpos = self.w - ob.rect[0]
                 self._tooltipdiv.style.left = None
                 self._tooltipdiv.style.right = self._tooltipdiv.xpos + "px"
             window.setTimeout(self._tooltip_show, delay)
     elif self._tooltipdiv.rect is not None:
         # Hide tooltip, really un-display the div after a delay
         self._tooltipdiv.style.opacity = 0
         if self._tooltipdiv.style.left:
             self._tooltipdiv.style.left = self._tooltipdiv.rect[2] + "px"
         else:
             self._tooltipdiv.style.right = self.w - self._tooltipdiv.rect[
                 0] + "px"
         self._tooltipdiv.rect = None
         window.setTimeout(self._tooltip_hide, 300)
Ejemplo n.º 2
0
 def on_ws_message(evt):
     msg = evt.data or evt  # bsdf-encoded command
     if self._pending_commands is None:
         # Direct mode
         self._receive_raw_command(msg)
     else:
         # Indirect mode, to give browser draw-time during loading
         if len(self._pending_commands) == 0:
             window.setTimeout(self._process_commands, 0)
         self._pending_commands.push(msg)
Ejemplo n.º 3
0
 def update(self, asap=True):
     """Schedule an update."""
     # The extra setTimeout is to make sure that there is time for the
     # browser to process events (like scrolling).
     if not self._pending_draw:
         self._pending_draw = True
         if asap:
             window.requestAnimationFrame(self._draw)
         else:
             window.setTimeout(window.requestAnimationFrame, 10, self._draw)
Ejemplo n.º 4
0
 def _draw_tick(self):
     """Function that calls update() to schedule a draw() on a regular interval.
     Where regular is really regular, so that second-ticks don't "jump".
     This functon must *not* be called more than once.
     """
     now = window.Date().getTime()
     res = 1000  # 1 FPS
     etime = int(now / res) * res + res
     window.setTimeout(self._draw_tick, etime - now)
     self.update()
Ejemplo n.º 5
0
 def on_ws_message(evt):
     msg = evt.data  # bsdf-encoded command
     if not msg:
         pass  # ? drop glitchy message :/
     elif self._pending_commands is None:
         # Direct mode
         self._receive_raw_command(msg)
     else:
         # Indirect mode, to give browser draw-time during loading
         if len(self._pending_commands) == 0:
             window.setTimeout(self._process_commands, 0)
         self._pending_commands.push(msg)
Ejemplo n.º 6
0
 def _process_commands(self):
     """ A less direct way to process commands, which gives the
     browser time to draw about every other JS asset. This is a
     tradeoff between a smooth spinner and fast load time.
     """
     while self._pending_commands is not None and len(self._pending_commands) > 0:
         msg = self._pending_commands.pop(0)
         try:
             command = self._receive_raw_command(msg)
         except Exception as err:
             window.setTimeout(self._process_commands, 0)
             raise err
         if command[0] == 'DEFINE':
             self._asset_count += 1
             if (self._asset_count % 3) == 0:
                 if len(self._pending_commands):
                     window.setTimeout(self._process_commands, 0)
                 break
Ejemplo n.º 7
0
 def _set_state(self, state, timeout=0):
     """Set the state, now or somewhat later."""
     window.clearTimeout(self._state_timeout)
     self._state_timeout = None
     if timeout > 0:
         self._state_timeout = window.setTimeout(self._set_state,
                                                 timeout * 1000, state)
     else:
         self.state = state
Ejemplo n.º 8
0
 def _process_commands(self):
     """ A less direct way to process commands, which gives the
     browser time to draw about every other JS asset. This is a
     tradeoff between a smooth spinner and fast load time.
     """
     while self._pending_commands is not None and len(self._pending_commands) > 0:
         msg = self._pending_commands.pop(0)
         try:
             command = self._receive_raw_command(msg)
         except Exception as err:
             window.setTimeout(self._process_commands, 0)
             raise err
         if command[0] == 'DEFINE':
             self._asset_count += 1
             if (self._asset_count % 3) == 0:
                 if len(self._pending_commands):
                     window.setTimeout(self._process_commands, 0)
                 break
Ejemplo n.º 9
0
    def _init_events(self):

        # Disable context menu so we can handle RMB clicks
        # Firefox is particularly stuborn with Shift+RMB, and RMB dbl click
        for ev_name in ("contextmenu", "click", "dblclick"):
            window.document.addEventListener(ev_name,
                                             self._prevent_default_event, 0)

        # Keep track of wheel event directed at the canvas
        self.node.addEventListener("wheel", self._on_js_wheel_event, 0)

        # If the canvas uses the wheel event for something, you'd want to
        # disable browser-scroll when the mouse is over the canvas. But
        # when you scroll down a page and the cursor comes over the canvas
        # because of that, we don't want the canvas to capture too eagerly.
        # This code only captures if there has not been scrolled elsewhere
        # for about half a second.
        if not window._wheel_timestamp:
            window._wheel_timestamp = 0, ""
            window.document.addEventListener("wheel", self._on_js_wheel_global,
                                             0)

        # Keep track of mouse events
        self.node.addEventListener("mousedown", self._on_js_mouse_event, 0)
        window.document.addEventListener("mouseup", self._on_js_mouse_event, 0)
        window.document.addEventListener("mousemove", self._on_js_mouse_event,
                                         0)

        window.document.addEventListener("mousemove", self._tooltip_handler, 0)
        self.node.addEventListener("mousedown", self._tooltip_handler, 0)
        self.node.addEventListener("touchstart", self._tooltip_handler, 0)
        self.node.addEventListener("touchmove", self._tooltip_handler, 0)
        self.node.addEventListener("touchend", self._tooltip_handler, 0)
        self.node.addEventListener("touchcancel", self._tooltip_handler, 0)

        # Keep track of touch events
        self.node.addEventListener("touchstart", self._on_js_touch_event, 0)
        self.node.addEventListener("touchend", self._on_js_touch_event, 0)
        self.node.addEventListener("touchcancel", self._on_js_touch_event, 0)
        self.node.addEventListener("touchmove", self._on_js_touch_event, 0)

        # Keep track of window size
        window.addEventListener("resize", self._on_js_resize_event, False)
        window.setTimeout(self._on_js_resize_event, 10)
Ejemplo n.º 10
0
 def _receive_command(self, command):
     """ Process a command send from the server.
     """
     cmd = command[0]
     if cmd == 'PING':
         # Used for roundtrip stuff, do at least one iter loop here ...
         window.setTimeout(self.send_command, 10, 'PONG', command[1])
     elif cmd == 'INIT_DONE':
         window.flexx.spin(None)
         while len(self._pending_commands):
             self._receive_raw_command(self._pending_commands.pop(0))
         self._pending_commands = None
         # print('init took', time() - self._init_time)
     elif cmd == 'PRINT':
         (window.console.ori_log or window.console.log)(command[1])
     elif cmd == 'EXEC':
         eval(command[1])
     elif cmd == 'EVAL':
         x = None
         if len(command) == 2:
             x = eval(command[1])
         elif len(command) == 3:
             x = eval('this.instances.' + command[1] + '.' + command[2])
         console.log(str(x))  # print (and thus also sends back result)
     elif cmd == 'EVALANDRETURN':
         try:
             x = eval(command[1])
         except Exception as err:
             x = str(err)
         eval_id = command[2]  # to identify the result in Python
         self.send_command("EVALRESULT", x, eval_id)
     elif cmd == 'INVOKE':
         id, name, args = command[1:]
         ob = self.instances.get(id, None)
         if ob is None:
             console.warn('Cannot invoke %s.%s; '
                          'session does not know it (anymore).' %
                          (id, name))
         elif ob._disposed is True:
             pass  # deleted, but other end might not be aware when command was send
         else:
             ob[name](*args)
     elif cmd == 'INSTANTIATE':
         self.instantiate_component(
             *command[1:])  # module, cname, id, args, kwargs
     elif cmd == 'DISPOSE':
         id = command[1]
         c = self.instances.get(id, None)
         if c is not None and c._disposed is False:  # else: no need to warn
             c._dispose()
         self.send_command('DISPOSE_ACK', command[1])
         self.instances.pop(id, None)  # Drop local reference now
     elif cmd == 'DISPOSE_ACK':
         self.instances.pop(command[1], None)  # Drop reference
     elif cmd == 'DEFINE':
         #and command[1] == 'JS' or command[1] == 'DEFINE-JS-EVAL '):
         kind, name, code = command[1:]
         window.flexx.spin()
         address = window.location.protocol + '//' + self.ws_url.split(
             '/')[2]
         code += '\n//# sourceURL=%s/flexx/assets/shared/%s\n' % (address,
                                                                  name)
         if kind == 'JS-EVAL':
             eval(code)
         elif kind == 'JS':
             # With this method, sourceURL does not work on Firefox,
             # but eval might not work for assets that don't "use strict"
             # (e.g. Bokeh). Note, btw, that creating links to assets does
             # not work because these won't be loaded on time.
             el = window.document.createElement("script")
             el.id = name
             el.innerHTML = code
             window.flexx.asset_node.appendChild(el)
         elif kind == 'CSS':
             el = window.document.createElement("style")
             el.type = "text/css"
             el.id = name
             el.innerHTML = code
             window.flexx.asset_node.appendChild(el)
         else:
             window.console.error('Dont know how to DEFINE ' + name +
                                  ' with "' + kind + '".')
     elif cmd == 'OPEN':
         window.win1 = window.open(command[1], 'new', 'chrome')
     else:
         window.console.error('Invalid command: "' + cmd + '"')
     return command
Ejemplo n.º 11
0
def on_resize():
    window.setTimeout(_on_resize, 1)
Ejemplo n.º 12
0
 def sync_soon(self, timeout=10):
     """Invoke a sync action. Cancel the pending sync action."""
     self.sync_time = dt.now(), dt.now() + timeout
     window.clearTimeout(self._sync_timeout)
     self._sync_timeout = window.setTimeout(self._sync_callback,
                                            timeout * 1000)
Ejemplo n.º 13
0
 def _receive_pong(self, count):
     while len(self._ping_calls) > 0 and self._ping_calls[0][0] <= count:
         _, callback, args = self._ping_calls.pop(0)
         window.setTimeout(callback, 0, *args)
Ejemplo n.º 14
0
 def call_after_roundtrip(self, callback, *args):
     ping_to_schedule_at = self._ping_counter + 1
     if len(self._ping_calls) == 0 or self._ping_calls[-1][0] < ping_to_schedule_at:
         window.setTimeout(self._send_ping, 0)
     self._ping_calls.push((ping_to_schedule_at, callback, args))
Ejemplo n.º 15
0
 def _receive_command(self, command):
     """ Process a command send from the server.
     """
     cmd = command[0]
     if cmd == 'PING':
         # Used for roundtrip stuff, do at least one iter loop here ...
         window.setTimeout(self.send_command, 10, 'PONG', command[1])
     elif cmd == 'INIT_DONE':
         window.flexx.spin(None)
         while len(self._pending_commands):
             self._receive_raw_command(self._pending_commands.pop(0))
         self._pending_commands = None
         # print('init took', time() - self._init_time)
     elif cmd == 'PRINT':
         (window.console.ori_log or window.console.log)(command[1])
     elif cmd == 'EXEC':
         eval(command[1])
     elif cmd == 'EVAL':
         x = None
         if len(command) == 2:
             x = eval(command[1])
         elif len(command) == 3:
             x = eval('this.instances.' + command[1] + '.' + command[2])
         console.log(str(x))  # print (and thus also sends back result)
     elif cmd == 'EVALANDRETURN':
         try:
             x = eval(command[1])
         except Exception as err:
             x = str(err)
         eval_id = command[2]  # to identify the result in Python
         self.send_command("EVALRESULT", x, eval_id)
     elif cmd == 'INVOKE':
         id, name, args = command[1:]
         ob = self.instances.get(id, None)
         if ob is None:
             console.warn('Cannot invoke %s.%s; '
                          'session does not know it (anymore).' % (id, name))
         elif ob._disposed is True:
             pass  # deleted, but other end might not be aware when command was send
         else:
             ob[name](*args)
     elif cmd == 'INSTANTIATE':
         self.instantiate_component(*command[1:])  # module, cname, id, args, kwargs
     elif cmd == 'DISPOSE':
         id = command[1]
         c = self.instances.get(id, None)
         if c is not None and c._disposed is False:  # else: no need to warn
             c._dispose()
         self.send_command('DISPOSE_ACK', command[1])
         self.instances.pop(id, None)  # Drop local reference now
     elif cmd == 'DISPOSE_ACK':
         self.instances.pop(command[1], None)  # Drop reference
     elif cmd == 'DEFINE':
         #and command[1] == 'JS' or command[1] == 'DEFINE-JS-EVAL '):
         kind, name, code = command[1:]
         window.flexx.spin()
         address = window.location.protocol + '//' + self.ws_url.split('/')[2]
         code += '\n//# sourceURL=%s/flexx/assets/shared/%s\n' % (address, name)
         if kind == 'JS-EVAL':
             eval(code)
         elif kind == 'JS':
             # With this method, sourceURL does not work on Firefox,
             # but eval might not work for assets that don't "use strict"
             # (e.g. Bokeh). Note, btw, that creating links to assets does
             # not work because these won't be loaded on time.
             el = window.document.createElement("script")
             el.id = name
             el.innerHTML = code
             window.flexx.asset_node.appendChild(el)
         elif kind == 'CSS':
             el = window.document.createElement("style")
             el.type = "text/css"
             el.id = name
             el.innerHTML = code
             window.flexx.asset_node.appendChild(el)
         else:
             window.console.error('Dont know how to DEFINE ' +
                                  name + ' with "' + kind + '".')
     elif cmd == 'OPEN':
         window.win1 = window.open(command[1], 'new', 'chrome')
     else:
         window.console.error('Invalid command: "' + cmd + '"')
     return command
Ejemplo n.º 16
0
 def call_after_roundtrip(self, callback, *args):
     ping_to_schedule_at = self._ping_counter + 1
     if len(self._ping_calls
            ) == 0 or self._ping_calls[-1][0] < ping_to_schedule_at:
         window.setTimeout(self._send_ping, 0)
     self._ping_calls.push((ping_to_schedule_at, callback, args))
Ejemplo n.º 17
0
 def _receive_pong(self, count):
     while len(self._ping_calls) > 0 and self._ping_calls[0][0] <= count:
         _, callback, args = self._ping_calls.pop(0)
         window.setTimeout(callback, 0, *args)
Ejemplo n.º 18
0
 def init(self):
     self.node.id = self.id
     window.setTimeout(self.load_viz, 500)