Equipment Schedule browsing/scrolling

I’m trying to use the equipment schedule, and it’s a very handy tool to display orders.

However, I find it hard to navigate around in that view.
Binding the start and end times to a time range selector works, however, that component requires very precise mouse control (hovering the right pixels to enlarge or shink the range).
Especially zooming in is very hard: requires you to grab that pixel on both sides multiple times.

So I would like to add some keyboard / scroll events to the schedule component: scroll to pan sideways, ctrl+scroll to zoom in and out, arrows to pan, +/- to zoom, …

Since it’s a component they should use a lot, it should be ergonomic to use.

But apparently, it’s not possible to define keyboard events on the component. Only click/drag events are supported, but get an animation like it’s drawing on the component (so to create new orders) instead of panning.

Is there a way to add such support, or will I have to add my own clumsy buttons to pan and zoom? Has anyone done this before?

1 Like

I was going to try using the code and ideas in this thread to do what you are describing. Haven’t had time to fiddle with it yet though. If you figure something out, let me know :slightly_smiling_face:

Thanks for the hint,

I transformed the linked code in something that works for the equipment schedule.

Here is the code that can be set as a “Custom Method” on the schedule component. You can call it from a button (to re-add the listener while testing) or from the “componentRunning” property change to load it on startup in production.

This behaviour should be default though IMHO …

def setScrollInteractionListener(self):
	import math
	from java.awt.event import MouseWheelEvent
	from java.awt.event import MouseWheelListener
	
	# assign self to schedule variable to avoid name collision
	shedule = self
	
	class scheduleMouseWheelListener(MouseWheelListener):
		def mouseWheelMoved(self, event):
			# https://docs.oracle.com/javase/tutorial/uiswing/events/mousewheellistener.html
			# https://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html
			
			# define the timeShift as 10% of the view, in the direction of the scroll action
			timeShift = int(math.ceil(event.getWheelRotation() * system.date.minutesBetween(shedule.startDate, shedule.endDate) / 10))
			
			if event.isControlDown():
				# Zooming: move the startDate against the direction of the scroll wheel, the endDate with the scroll wheel
				shedule.startDate = system.date.addMinutes(shedule.startDate, -1 * timeShift)
				shedule.endDate = system.date.addMinutes(shedule.endDate, timeShift)
			elif event.isShiftDown():
				# Fast scrolling: scroll 70% of the screen per click
				shedule.startDate = system.date.addMinutes(shedule.startDate, 7 * timeShift)
				shedule.endDate = system.date.addMinutes(shedule.endDate, 7 * timeShift)
			else:
				# Regular scrolling: move both timestamps with the same amount (10% in the direction of the scroll) 
				shedule.startDate = system.date.addMinutes(shedule.startDate, timeShift)
				shedule.endDate = system.date.addMinutes(shedule.endDate, timeShift)
			return

	for i in shedule.mouseWheelListeners:
		# print "Remove mouse wheel listener:", i.__class__.__name__
		shedule.removeMouseWheelListener(i)
	shedule.addMouseWheelListener(scheduleMouseWheelListener())
2 Likes

I’ve added another improvement. The scroll-to-zoom now takes the mouse position into account, and zooms around that mouse position.

This works more like users expect from other scroll-to-zoom apps like pictures and maps.

def setScrollInteractionListener(self):
	import math
	from java.awt.event import MouseWheelEvent
	from java.awt.event import MouseWheelListener
	

	HEADER_WIDTH = 70 # width of the title of the line, depends on your setup
	# assign self to schedule variable to avoid name collision
	schedule = self
	
	class scheduleMouseWheelListener(MouseWheelListener):
		def mouseWheelMoved(self, event):
			# https://docs.oracle.com/javase/tutorial/uiswing/events/mousewheellistener.html
			# https://docs.oracle.com/javase/tutorial/uiswing/events/mouselistener.html
			
			# define the timeShift as 10% of the view, in the direction of the scroll action
			timeShift = int(math.ceil(event.getWheelRotation() * system.date.minutesBetween(schedule.startDate, schedule.endDate) / 10))
			
			if event.isControlDown():
				# Zooming: move the startDate against the direction of the scroll wheel, the endDate with the scroll wheel
				# The zoom point depends on the mouse position (what fraction is before and after the mouse)
				fraction = 1.0 * (event.getX() - HEADER_WIDTH) / (schedule.width - HEADER_WIDTH)
				shiftStart = int(math.ceil(timeShift * fraction))
				shiftEnd = int(math.ceil(timeShift * (1 - fraction)))
				
				schedule.startDate = system.date.addMinutes(schedule.startDate, -1 * shiftStart)
				schedule.endDate = system.date.addMinutes(schedule.endDate, shiftEnd)
			elif event.isShiftDown():
				# Fast scrolling: scroll 70% of the screen per click
				schedule.startDate = system.date.addMinutes(schedule.startDate, 7 * timeShift)
				schedule.endDate = system.date.addMinutes(schedule.endDate, 7 * timeShift)
			else:
				# Regular scrolling: move both timestamps with the same amount (10% in the direction of the scroll) 
				schedule.startDate = system.date.addMinutes(schedule.startDate, timeShift)
				schedule.endDate = system.date.addMinutes(schedule.endDate, timeShift)
			return

	for i in schedule.mouseWheelListeners:
		# print "Remove mouse wheel listener:", i.__class__.__name__
		schedule.removeMouseWheelListener(i)
	schedule.addMouseWheelListener(scheduleMouseWheelListener())
6 Likes

Cool, thanks for sharing your solution @Sanderd17! I might see if I can adapt this to the date range picker control instead of the equipment schedule component. We use the picker in conjunction with both equipment schedule components and easy charts, so a common zoom function between them would be nice.

Very cool, Sander! Thanks for sharing

1 Like

Thanks for sharing this. It's elegant and intuitive to use. I implemented it and immediately ran into what looks like a rendering bug. This is what I should have seen:


This is what I saw instead:

The contents of the Equipment Schedule bounding box (in a popup window) are being pulled from multiple places on the Ignition Vision client desktop. If I drag the popup window by the title bar, the contents redraw correctly. Anyone seen this kind of behaviour before? Any suggestions on how to fix?
EDIT: The rendering corruption also happens when the Scheduled Events SQL binding refreshes every 5 minutes.

1 Like

Mate, i don't have words to thank you for this! Thank you very much for sharing this, you saved our lives here at the company, lol. It's really a cool and elegant solution.