// o---------------------------------------------------------------------------------o // | This file is part of the RGraph package - you can learn more at: | // | | // | https://www.rgraph.net/license.html | // | | // | RGraph is dual-licensed under the Open Source GPL license. That means that it's | // | free to use and there are no restrictions on what you can use RGraph for! | // | If the GPL license does not suit you however, then there's an inexpensive | // | commercial license option available. See the URL above for more details. | // o---------------------------------------------------------------------------------o // // Initialise the various objects // RGraph = window.RGraph || {isrgraph:true,isRGraph: true,rgraph:true}; // Module pattern (function (win, doc, undefined) { var ua = navigator.userAgent; // // This is the window click event listener. It redraws all canvas tags on the page. // RGraph.installWindowMousedownListener = function (obj) { if (!RGraph.window_mousedown_event_listener) { RGraph.window_mousedown_event_listener = function (e) { // // For firefox add the window.event object // if (navigator.userAgent.indexOf('Firefox') >= 0) win.event = e; var tooltip = RGraph.Registry.get('tooltip'); if ( RGraph.hideTooltip && tooltip && tooltip.__object__.get('tooltipsEffect') !== 'slide' ) { RGraph.clear(RGraph.Registry.get('tooltip').__canvas__); RGraph.redraw(); RGraph.hideTooltip(); } }; win.addEventListener('mousedown', RGraph.window_mousedown_event_listener, false); } }; // // This is the window click event listener. It redraws all canvas tags on the page. // RGraph.installWindowMouseupListener = function (obj) { if (!RGraph.window_mouseup_event_listener) { RGraph.window_mouseup_event_listener = function (e) { // // For firefox add the window.event object // if (navigator.userAgent.indexOf('Firefox') >= 0) win.event = e; // // Stop any annotating that may be going on // if (RGraph.annotating_window_onmouseup) { RGraph.annotating_window_onmouseup(e); return; } // // End adjusting // if (RGraph.Registry.get('adjusting') || RGraph.Registry.get('adjusting.gantt')) { var obj = RGraph.Registry.get('adjusting'); // If it's a line chart update the data_arr variable if (obj && obj.type === 'line') { obj.data_arr = RGraph.arrayLinearize(obj.data); } RGraph.fireCustomEvent(RGraph.Registry.get('adjusting'), 'onadjustend'); } RGraph.Registry.set('adjusting', null); RGraph.Registry.set('adjusting.shape', null); RGraph.Registry.set('adjusting.gantt', null); // ============================================== // Finally, redraw the chart // ============================================== var tags = document.getElementsByTagName('canvas'); for (var i=0; i<tags.length; ++i) { if (tags[i].__object__ && tags[i].__object__.isRGraph) { if (!tags[i].__object__.get('annotatable')) { if (!tags[i].__rgraph_trace_cover__ && !noredraw) { RGraph.clear(tags[i]); } else { var noredraw = true; } } } } if (!noredraw) { RGraph.redraw(); } }; win.addEventListener('mouseup', RGraph.window_mouseup_event_listener, false); } }; // // This is the canvas mouseup event listener. It installs the // mouseup event for the canvas. The mouseup event then checks // the relevant object. // // @param object obj The chart object // RGraph.installCanvasMouseupListener = function (obj) { if (!obj.canvas.rgraph_mouseup_event_listener) { obj.canvas.rgraph_mouseup_event_listener = function (e) { // // For firefox add the window.event object // if (navigator.userAgent.indexOf('Firefox') >= 0) window.event = e; // ************************************************************************* // Tooltips // ************************************************************************* // This causes things at the edge of the chart area - eg line chart hotspots - not to fire because the // cursor is out of the chart area var objects = RGraph.ObjectRegistry.getObjectsByXY(e); //var objects = RGraph.ObjectRegistry.getObjectsByCanvasID(e.target.id); if (objects) { for (var i=0,len=objects.length; i<len; i+=1) { var obj = objects[i], id = objects[i].id; // ========================================================================= // The drawing API text object supports the link configuration property // ======================================================================== var link = obj.get('link'); if (obj.type == 'drawing.text' && typeof link === 'string') { var link_target = obj.get('linkTarget'); var link_options = obj.get('linkOptions'); window.open(link, link_target ? link_target : null, link_options); } // ======================================================================== // Tooltips // ======================================================================== if (!RGraph.isNullish(obj) && RGraph.tooltip) { var shape = obj.getShape(e); if (shape && shape.tooltip) { var text = shape.tooltip; if (text) { var type = shape.object.type; RGraph.clear(obj.canvas); RGraph.redraw(); RGraph.Registry.set('tooltip.shape', shape); // Note that tooltips are positioned at the pointer // now; and thats done within the .tooltip() function RGraph.tooltip( obj, text, 0, 0, shape.sequentialIndex, e ); obj.highlight(shape); // Add the shape that triggered the tooltip if (RGraph.Registry.get('tooltip')) { RGraph.Registry.get('tooltip').__shape__ = shape; RGraph.evaluateCursor(e); } e.cancelBubble = true; e.stopPropagation(); return false; } } } // ========================================================================= // Adjusting // ======================================================================== if (RGraph.Registry.get('adjusting') || RGraph.Registry.get('adjusting.gantt')) { //var obj = RGraph.Registry.get('adjusting'); // If it's a line chart update the data_arr variable if (obj && obj.type === 'line') { obj.data_arr = RGraph.arrayLinearize(obj.data); } RGraph.fireCustomEvent(RGraph.Registry.get('adjusting'), 'onadjustend'); } RGraph.Registry.set('adjusting', null); RGraph.Registry.set('adjusting.shape', null); RGraph.Registry.set('adjusting.gantt', null); // // If the mouse pointer is over a "front" chart this prevents charts behind it // from firing their events. // if (shape || (obj.overChartArea && obj.overChartArea(e)) ) { break; } } } }; obj.canvas.addEventListener('mouseup', obj.canvas.rgraph_mouseup_event_listener, false); } }; // // This is the canvas mousemove event listener. // // @param object obj The chart object // RGraph.installCanvasMousemoveListener = function (obj) { if (!obj.canvas.rgraph_mousemove_event_listener) { obj.canvas.rgraph_mousemove_event_listener = function (e) { // // For firefox add the window.event object // if (navigator.userAgent.indexOf('Firefox') >= 0) window.event = e; // // Go through all the objects and check them to see if anything needs doing // var objects = RGraph.OR.getObjectsByXY(e); // Necessary to track which objects have had the mouseover // triggered on them var uids = []; if (objects && objects.length > 0) { for (var i=0,len=objects.length; i<len; i+=1) { var obj = objects[i]; var id = obj.id; // Record the uid uids[obj.uid] = true; /////////////////////////////////////////////////// // This bit facilitates the dataset highlighting // /////////////////////////////////////////////////// if (obj && obj.properties.highlightDataset && obj.properties.highlightDatasetEvent === 'mousemove') { var [x, y] = RGraph.getMouseXY(e); var shape = obj.over(x, y); var excludedNumber = RGraph.isNumber(obj.properties.highlightDatasetExclude) && shape && obj.properties.highlightDatasetExclude === shape.dataset; var excludedArray = RGraph.isArray(obj.properties.highlightDatasetExclude) && shape && obj.properties.highlightDatasetExclude.includes(shape.dataset); if (shape && !excludedNumber && !excludedArray) { // Store the index that's highlighted on the canvas if // it's different to what's previously been stored. if (shape.dataset !== obj.canvas.rgraph_highlightDataset_dataset) { RGraph.redrawCanvas(obj.canvas); obj.canvas.rgraph_highlightDataset_dataset = shape.dataset; obj.highlightDataset({ dataset: shape.dataset, fill: obj.properties.highlightDatasetFill, stroke: obj.properties.highlightDatasetStroke, linewidth: obj.properties.highlightDatasetLinewidth, linedash: obj.properties.highlightDatasetDashArray, dotted: obj.properties.highlightDatasetDotted, dashed: obj.properties.highlightDatasetDashed }); // Call the callback if specified if (RGraph.isFunction (obj.properties.highlightDatasetCallback)) { obj.properties.highlightDatasetCallback({ dataset: shape.dataset, object: obj }); } } } else { obj.canvas.rgraph_highlightDataset_dataset = null; RGraph.redraw(); } } if (!obj.getShape) { continue; } var shape = obj.getShape(e); // If the object has changed (based on the UID) then // fire the prior objects mouseout event if (RGraph.last_mouseover_uid && RGraph.last_mouseover_uid !== obj.uid) { RGraph.fireCustomEvent(RGraph.last_mouseover_object, 'onmouseout'); RGraph.last_mouseover_object.__mouseover_shape_index__ = null; RGraph.last_mouseover_object.__mouseover_shape__ = null; RGraph.last_mouseover_object = null; RGraph.last_mouseover_uid = null; } // Fire the onmouseout event if necessary if ( (!shape && typeof obj.__mouseover_shape_index__ === 'number') || (shape && typeof obj.__mouseover_shape_index__ === 'number' && shape.index !== obj.__mouseover_shape_index__) ) { RGraph.fireCustomEvent(obj, 'onmouseout'); } // // If the mouse is over a key element add the details // of it to the Registry // if (obj.coords && obj.coords.key && obj.coords.key.length) { var mouseXY = RGraph.getMouseXY(e); for (var i=0,overkey=false; i<obj.coords.key.length; ++i) { if ( mouseXY[0] >= obj.coords.key[i][0] && mouseXY[0] <= (obj.coords.key[i][0] + obj.coords.key[i][2]) && mouseXY[1] >= obj.coords.key[i][1] && mouseXY[1] <= (obj.coords.key[i][1] + obj.coords.key[i][3]) ) { RGraph.Registry.set('key-element', obj.coords.key[i]); overkey = true; } if (!overkey) { RGraph.Registry.set('key-element', null); } } } // ================================================================================================ // // This facilitates the onmousemove facility // ================================================================================================ // var func = null; if (!func && typeof obj.onmousemove == 'function') { var func = obj.onmousemove; } // // // if (shape) { var index = shape.sequentialIndex; if (typeof obj['$' + index] === 'object' && typeof obj['$' + index].onmousemove == 'function') { var func2 = obj['$' + index].onmousemove; } } // // This bit saves the current pointer style if there isn't one already saved // if (shape && (typeof func == 'function' || typeof func2 == 'function' || typeof obj.get('link') === 'string')) { if (obj.get('eventsMousemoveRevertto') == null) { obj.set('eventsMousemoveRevertto', e.target.style.cursor); } if (typeof func == 'function') RGraph.custom_events_mousemove_pointer = func(e, shape); if (typeof func2 == 'function') RGraph.custom_events_mousemove_pointer = RGraph.custom_events_mousemove_pointer || func2(e, shape); // Go through the RGraph.events array looking for more // event listeners if ( typeof RGraph.events === 'object' && typeof RGraph.events[obj.uid] === 'object') { for (i in RGraph.events[obj.uid]) { if ( typeof i === 'string' && typeof RGraph.events[obj.uid][i] === 'object' && RGraph.events[obj.uid][i][1] === 'onmousemove' && typeof RGraph.events[obj.uid][i][2] === 'function') { (RGraph.events[obj.uid][i][2])(obj); } } } //return; } else if (typeof obj.get('eventsMousemoveRevertto') == 'string') { RGraph.cursor.push('default'); obj.set('eventsMousemoveRevertto', null); } // ====================================================== // This bit of code facilitates the onmouseover event // ====================================================== var func = null; if (!func && typeof obj.onmouseover === 'function') { func = obj.onmouseover; } // Allow for individually index functions to be specified if (shape) { var index = shape.sequentialIndex; if (typeof obj['$' + index] == 'object' && typeof obj['$' + index].onmouseover == 'function') { var func2 = obj['$' + index].onmouseover; } } else { obj.__mouseover_shape_index__ = null; RGraph.__mouseover_objects__ = []; RGraph.last_mouseover_uid = null; RGraph.last_mouseover_object = null; } if (typeof RGraph.__mouseover_objects__ === 'undefined') { RGraph.__mouseover_objects__ = []; RGraph.last_mouseover_uid = null; RGraph.last_mouseover_object = null; } if (shape) { if ((obj.__mouseover_shape_index__ === shape.index) === false) { obj.__mouseover_shape__ = shape; obj.__mouseover_shape_index__ = shape.index; RGraph.last_mouseover_uid = obj.uid; RGraph.last_mouseover_object = obj; RGraph.__mouseover_objects__.push(obj); if (func) func(e, shape); if (func2) func2(e, shape); // Go through the RGraph.events array looking for more // event listeners if ( typeof RGraph.events === 'object' && typeof RGraph.events[obj.uid] === 'object') { for (i in RGraph.events[obj.uid]) { if ( typeof i === 'string' && typeof RGraph.events[obj.uid][i] === 'object' && RGraph.events[obj.uid][i][1] === 'onmouseover' && typeof RGraph.events[obj.uid][i][2] === 'function') { (RGraph.events[obj.uid][i][2])(obj); } } } } } else { obj.__mouseover_shape_index__ = null; RGraph.__mouseover_objects__ = []; RGraph.last_mouseover_uid = null; RGraph.last_mouseover_object = null; } // ================================================================================================ // // Tooltips // ================================================================================================ // var current_tooltip = RGraph.Registry.get('tooltip'); var tooltips = obj.get('tooltips'); var tooltips_event = obj.get('tooltipsEvent'); if ( shape && (tooltips && tooltips[shape.index] || shape.tooltip) && tooltips_event.indexOf('mousemove') !== -1 && ( !current_tooltip // Is there a tooltip being shown? || obj.uid != current_tooltip.__object__.uid // Same object? || (current_tooltip.__index__ != shape.sequentialIndex) // Same datapiece index? [UPDATE ON 29/10/2019 TO TRY AND MATCH THE sequentialIndex] || (typeof shape.dataset === 'number' && shape.dataset != current_tooltip.__shape__.dataset) // Different dataset index ) ) { RGraph.clear(obj.canvas); RGraph.hideTooltip(); RGraph.redraw(); obj.canvas.rgraph_mouseup_event_listener(e); return; } // ================================================================================================ // // Adjusting // ================================================================================================ // if (obj && obj.get('adjustable')) { obj.adjusting_mousemove(e); } // // This facilitates breaking out of the loop when a shape has been found - // ie the cursor is over a shape an upper chart // if (shape || (obj.overChartArea && obj.overChartArea(e) )) { break; } } // // For all objects that are NOT mouseover'ed, reset the // mouseover flag back to null // var objects = RGraph.OR.getObjectsByCanvasID(e.target.id); for (var i=0; i<objects.length; ++i) { if (!uids[objects[i].uid]) { objects[i].__mouseover_shape_index__ = null; } } } else { // Reset the mouseover flag on all of this canvas tags objects var objects = RGraph.OR.getObjectsByCanvasID(e.target.id); for (var i=0; i<objects.length; i++) { if (typeof objects[i].__mouseover_shape_index__ === 'number') { RGraph.fireCustomEvent(objects[i], 'onmouseout'); } objects[i].__mouseover_shape_index__ = null; } RGraph.__mouseover_objects__ = []; RGraph.last_mouseover_uid = null; RGraph.last_mouseover_object = null; } // ================================================================================================ // // Crosshairs // ================================================================================================ // if (e.target && e.target.__object__ && e.target.__object__.get('crosshairs')) { RGraph.drawCrosshairs(e, e.target.__object__); } // ================================================================================================ // // Interactive key No LONGER REQUIRED // ================================================================================================ // //if (typeof InteractiveKey_line_mousemove == 'function') InteractiveKey_line_mousemove(e); //if (typeof InteractiveKey_pie_mousemove == 'function') InteractiveKey_pie_mousemove(e); // ================================================================================================ // // Annotating // ================================================================================================ // if (e.target.__object__ && e.target.__object__.get('annotatable') && RGraph.annotating_canvas_onmousemove) { RGraph.annotating_canvas_onmousemove(e); } // // Determine the pointer // RGraph.evaluateCursor(e); }; obj.canvas.addEventListener('mousemove', obj.canvas.rgraph_mousemove_event_listener, false); } }; // // This is the canvas mousedown event listener. // // @param object obj The chart object // RGraph.installCanvasMousedownListener = function (obj) { if (!obj.canvas.rgraph_mousedown_event_listener) { obj.canvas.rgraph_mousedown_event_listener = function (e) { // // For firefox add the window.event object // if (navigator.userAgent.indexOf('Firefox') >= 0) window.event = e; // // Annotating // if (e.target.__object__ && e.target.__object__.get('annotatable') && RGraph.annotating_canvas_onmousedown) { RGraph.annotating_canvas_onmousedown(e); return; } var obj = RGraph.ObjectRegistry.getObjectByXY(e); if (obj) { var id = obj.id; // // Handle adjusting for all object types // if (obj && obj.isRGraph && obj.get('adjustable')) { // // Check the cursor is in the correct area // var obj = RGraph.OR.getObjectByXY(e); if (obj && obj.isRGraph) { // If applicable, get the appropriate shape and store it in the registry switch (obj.type) { case 'bar': var shape = obj.getShapeByX(e); break; case 'gantt': var shape = obj.getShape(e); if (shape) { var data = typeof obj.data[shape.dataset] === 'object' && obj.data[shape.dataset][shape.index] && obj.data[shape.dataset][shape.index].start ? obj.data[shape.dataset][shape.index] : obj.data[shape.dataset]; var mouseXY = RGraph.getMouseXY(e); RGraph.Registry.set('adjusting.gantt', { dataset: shape.dataset, index: shape.index, object: obj, mousex: mouseXY[0], mousey: mouseXY[1], event: data, event_start: data.start, event_duration: data.duration, mode: (mouseXY[0] > (shape.x + shape.width - 5) ? 'resize' : 'move'), shape: shape }); } break; case 'line': var shape = obj.getShape(e); break; case 'scatter': var shape = obj.getShape(e); break; case 'hbar': var shape = obj.getShapeByY(e); break; case 'activity': var shape = obj.getShape(e); break; default: var shape = null; } // Facilitate one click adjusting on the lline chart if (obj.type === 'line' && obj.properties.adjustableXonly) { var shape = obj.getShapeByX(e); } // // Added 30/9/2016 // Now check the index in the adjustingOnly property // If that property is an object and the appropriate index is // truthy then allow adjusting, otherwise don't. // if ( RGraph.isNullish(obj.properties.adjustableOnly) || typeof obj.properties.adjustableOnly === 'undefined' || ( RGraph.isArray(obj.properties.adjustableOnly) && obj.isAdjustable && obj.isAdjustable(shape) ) ) { RGraph.Registry.set('adjusting.shape', shape); // Fire the onadjustbegin event RGraph.fireCustomEvent(obj, 'onadjustbegin'); RGraph.Registry.set('adjusting', obj); // Liberally redraw the canvas RGraph.clear(obj.canvas); RGraph.redraw(); // Call the mousemove event listener so that the canvas // is adjusted even though the mouse isn't moved obj.canvas.rgraph_mousemove_event_listener(e); } } } if (obj.properties.tooltipsEffect !== 'slide') { RGraph.clear(obj.canvas); RGraph.redraw(); } } }; obj.canvas.addEventListener('mousedown', obj.canvas.rgraph_mousedown_event_listener, false); } }; // // This is the canvas click event listener. Used by the pseudo event listener // // @param object obj The chart object // RGraph.installCanvasClickListener = function (obj) { if (!obj.canvas.rgraph_click_event_listener) { obj.canvas.rgraph_click_event_listener = function (e) { // // For firefox add the window.event object // if (navigator.userAgent.indexOf('Firefox') >= 0) window.event = e; var objects = RGraph.ObjectRegistry.getObjectsByXY(e); for (var i=0,len=objects.length; i<len; i+=1) { var obj = objects[i]; var id = obj.id; var shape = obj.getShape(e); /////////////////////////////////////////////////// // This bit facilitates the dataset highlighting // /////////////////////////////////////////////////// if (obj && obj.properties.highlightDataset && obj.properties.highlightDatasetEvent === 'click') { var [x, y] = RGraph.getMouseXY(e); var shape = obj.over(x, y); var excludedNumber = RGraph.isNumber(obj.properties.highlightDatasetExclude) && shape && obj.properties.highlightDatasetExclude === shape.dataset; var excludedArray = RGraph.isArray(obj.properties.highlightDatasetExclude) && shape && obj.properties.highlightDatasetExclude.includes(shape.dataset); if (shape && !excludedNumber && !excludedArray) { obj.highlightDataset({ dataset: shape.dataset, fill: obj.properties.highlightDatasetFill, stroke: obj.properties.highlightDatasetStroke, linewidth: obj.properties.highlightDatasetLinewidth, linedash: obj.properties.highlightDatasetDashArray, dotted: obj.properties.highlightDatasetDotted, dashed: obj.properties.highlightDatasetDashed }); // Call the callback if specified if (RGraph.isFunction (obj.properties.highlightDatasetCallback)) { obj.properties.highlightDatasetCallback({ dataset: shape.dataset, object: obj }); } } } // // This bit saves the current pointer style // if there isn't one already saved // var func = null; if (!func && typeof obj.onclick == 'function') { func = obj.onclick; } if (shape && typeof func == 'function') { func(e, shape); // Go through the RGraph.events array looking for more // event listeners if ( typeof RGraph.events === 'object' && typeof RGraph.events[obj.uid] === 'object') { for (i in RGraph.events[obj.uid]) { if ( typeof i === 'string' && typeof RGraph.events[obj.uid][i] === 'object' && RGraph.events[obj.uid][i][1] === 'onclick' && typeof RGraph.events[obj.uid][i][2] === 'function') { (RGraph.events[obj.uid][i][2])(obj); } } } // // If objects are layered on top of each other this return // stops objects underneath from firing once the "top" // objects user event has fired // return; } // // Handle the key click event // var key = RGraph.Registry.get('key-element'); if (key) { RGraph.fireCustomEvent(obj, 'onkeyclick'); } // // The property takes priority over this. // if (shape) { var index = shape.sequentialIndex; if (typeof index == 'number' && obj['$' + index]) { var func = obj['$' + index].onclick; if (typeof func == 'function') { func(e, shape); // // If objects are layered on top of each other this return // stops objects underneath from firing once the "top" // objects user event has fired // return; } } } // // This facilitates breaking out of the loop when a shape has been found - // ie the cursor is over a shape an upper chart // if (shape || (obj.overChartArea && obj.overChartArea(e)) ) { break; } } }; obj.canvas.addEventListener('click', obj.canvas.rgraph_click_event_listener, false); } }; // // This function evaluates the various cursor settings and if there's one for pointer, changes it to that // RGraph.evaluateCursor = function (e) { if (e.rgraph_evaluateCursor === false) { return; } var obj = null; var mouseXY = RGraph.getMouseXY(e); var mouseX = mouseXY[0]; var mouseY = mouseXY[1]; var canvas = e.target; // // Tooltips cause the mouse pointer to change // var objects = RGraph.OR.getObjectsByCanvasID(canvas.id); for (var i=0,len=objects.length; i<len; i+=1) { if ((objects[i].getShape && objects[i].getShape(e)) || (objects[i].overChartArea && objects[i].overChartArea(e))) { var obj = objects[i]; var id = obj.id; } } if (!RGraph.isNullish(obj)) { if (obj.getShape && obj.getShape(e)) { var shape = obj.getShape(e); if ( (!obj.isMarimekko && obj.get('tooltips')) || (obj.isMarimekko && obj.get('marimekkoTooltips')) ) { var text = RGraph.parseTooltipText( obj.isMarimekko ? obj.get('marimekkoTooltips') : obj.get('tooltips'), shape.sequentialIndex ); if (!text && shape.object.type == 'scatter' && shape.index) { text = RGraph.parseTooltipText(obj.get('tooltips'), shape.index); } // // This essentially makes front charts "hide" the back charts // if (text) { var pointer = true; } } } // // Now go through the key coords and see if it's over that. // if (!RGraph.isNullish(obj) && obj.get('keyInteractive')) { for (var j=0; j<obj.coords.key.length; ++j) { if (mouseX > obj.coords.key[j][0] && mouseX < (obj.coords.key[j][0] + obj.coords.key[j][2]) && mouseY > obj.coords.key[j][1] && mouseY < (obj.coords.key[j][1] + obj.coords.key[j][3])) { var pointer = true; } } } } // // It can be specified in the user mousemove event - remember it can now // be specified in THREE ways // if (RGraph.custom_events_mousemove_pointer) { var pointer = true; RGraph.custom_events_mousemove_pointer = false; } // // // // var index = shape.object.type == 'scatter' ? shape.index_adjusted : shape.index; // // if (!RGraph.isNullish(obj['$' + index]) && typeof obj['$' + index].onmousemove == 'function') { // var str = (obj['$' + index].onmousemove).toString(); // if (str.match(/pointer/) && str.match(/cursor/) && str.match(/style/)) { // var pointer = true; // } // } // } // // // Is the chart resizable? Go through all the objects again // var objects = RGraph.OR.objects.byCanvasID; for (var i=0,len=objects.length; i<len; i+=1) { if (objects[i] && objects[i][1].get('resizable')) { var resizable = true; } } if (resizable && mouseX > (e.target.width - 32) && mouseY > (e.target.height - 16)) { pointer = true; } if (pointer) { e.target.style.cursor = 'pointer'; } else if (e.target.style.cursor == 'pointer') { e.target.style.cursor = 'default'; } else { e.target.style.cursor = null; } // ========================================================================= // Resize cursor - check mouseis in bottom left corner and if it is change it // ========================================================================= if (resizable && mouseX >= (e.target.width - 15) && mouseY >= (e.target.height - 15)) { e.target.style.cursor = 'move'; } else if (e.target.style.cursor === 'move') { e.target.style.cursor = 'default'; } // ========================================================================= // Line chart dataset highlighting // ========================================================================= var objects = RGraph.OR.getObjectsByXY(e); for (let i=0; i<objects.length; ++i) { if (objects[i] && objects[i].type && objects[i].type === 'line' && objects[i].properties.highlightDataset) { var [x, y] = RGraph.getMouseXY(e); var shape = objects[i].over(x, y); var excludedNumber = RGraph.isNumber(objects[i].properties.highlightDatasetExclude) && shape && objects[i].properties.highlightDatasetExclude === shape.dataset; var excludedArray = RGraph.isArray(objects[i].properties.highlightDatasetExclude) && shape && objects[i].properties.highlightDatasetExclude.includes(shape.dataset); if (shape && !excludedNumber && !excludedArray) { e.target.style.cursor = 'pointer'; } } if (objects[i].getShape(e)) { break; } } // ========================================================================= // Interactive key // ========================================================================= if (typeof mouse_over_key == 'boolean' && mouse_over_key) { e.target.style.cursor = 'pointer'; } // ========================================================================= // Gantt chart adjusting // ========================================================================= //if (obj && obj.type == 'gantt' && obj.get('adjustable')) { // if (obj.getShape && obj.getShape(e)) { // e.target.style.cursor = 'ew-resize'; // } else { // e.target.style.cursor = 'default'; // } //} else if (!obj || !obj.type) { // e.target.style.cursor = cursor; //} // ========================================================================= // Line chart adjusting // ========================================================================= if (obj && obj.type == 'line' && obj.get('adjustable')) { if (obj.getShape) { var shape = obj.getShape(e); if (shape && obj.isAdjustable(shape)) { e.target.style.cursor = 'ns-resize'; } } else { e.target.style.cursor = 'default'; } } // ========================================================================= // Scatter chart adjusting // ========================================================================= if (obj && obj.type == 'scatter' && obj.get('adjustable')) { if (obj.getShape) { var shape = obj.getShape(e); if (shape && obj.isAdjustable(shape)) { e.target.style.cursor = 'move'; } } else { e.target.style.cursor = 'default'; } } // ========================================================================= // Annotatable // ========================================================================= if (e.target.__object__ && e.target.__object__.get('annotatable')) { e.target.style.cursor = 'crosshair'; } // ========================================================================= // Drawing API link // ========================================================================= if (obj && obj.type === 'drawing.text' && shape && typeof obj.get('link') === 'string') { e.target.style.cursor = 'pointer'; } }; // // This function handles the tooltip text being a string, function // // @param mixed tooltip This could be a string or a function. If it's a function it's called and // the return value is used as the tooltip text // @param numbr idx The index of the tooltip. // RGraph.parseTooltipText = function (tooltips, idx) { // No tooltips if (!tooltips) { return null; } // Get the tooltip text if (typeof tooltips == 'function') { var text = tooltips(idx); // A single tooltip. Now with template support } else if (typeof tooltips == 'string') { var text = tooltips; } else if (typeof tooltips === 'object' && typeof tooltips[idx] == 'function') { var text = tooltips[idx](idx); } else if (typeof tooltips === 'object' && (RGraph.isNullish(tooltips[idx]) || typeof tooltips[idx] === 'undefined') ) { return null; } else if (typeof tooltips[idx] == 'string' && tooltips[idx]) { var text = tooltips[idx]; } else { var text = ''; } if (typeof text === 'undefined') { text = ''; } else if (typeof text === 'null') { text = ''; } // Conditional in case the tooltip file isn't included return RGraph.getTooltipTextFromDIV ? RGraph.getTooltipTextFromDIV(text) : text; }; // // Draw crosshairs if enabled // // @param object obj The graph object (from which we can get the context and canvas as required) // RGraph.drawCrosshairs = function (e, obj) { var width = obj.canvas.width, height = obj.canvas.height, mouseXY = RGraph.getMouseXY(e), x = mouseXY[0], y = mouseXY[1], marginLeft = obj.marginLeft, marginRight = obj.marginRight, marginTop = obj.marginTop, marginBottom = obj.marginBottom, prop = obj.properties, properties = obj.properties; // // The event listener for the crosshairs // var crosshairsSnapToScale = function (e) { var obj = e.target.__object__; if (obj.properties.crosshairs && obj.properties.crosshairsSnapToScale) { if (obj.type === 'scatter') { var value = obj.getYValue(e); } else { var value = obj.getValue(e); } var scale = obj.scale2.values; scale.unshift(obj.scale2.min); var dist = []; scale.map((v, k, arr) => { dist.push({ index: k, distance: Math.abs(value - v) }); }); dist.sort(function (a, b) { return a.distance - b.distance; }); // Reset the value variable value = obj.scale2.values[dist[0].index]; // Determine the linedash setting if (properties.crosshairsDotted) { var linedash = '[1,3]'; } else if (properties.crosshairsDashed) { var linedash = '[5,5]'; } else { var linedash = '[1,1]'; } // Start drawing on a "fresh" canvas RGraph.redraw(); // Draw a vertical line for the HBar if (obj.type === 'hbar') { // Draw the vertical line if (obj.properties.crosshairsVline) { obj.path( 'b ld % lw % m % % l % % s %', linedash, obj.properties.crosshairsLinewidth, obj.getXCoord(value), obj.marginTop, obj.getXCoord(value), obj.canvas.height - obj.marginBottom, obj.properties.crosshairsColor ); } // Draw the horizontal line if (obj.properties.crosshairsHline) { var [mouseX, mouseY] = RGraph.getMouseXY(e); obj.path( 'b ld % lw % m % % l % % s %', linedash, obj.properties.crosshairsLinewidth, obj.properties.marginLeft, mouseY, obj.canvas.width - obj.properties.marginRight, mouseY, obj.properties.crosshairsColor ); } // Draw a horizontal line for bar/line/scatter/waterfall charts } else { if (obj.properties.crosshairsHline) { obj.path( 'b ld % lw % m % % l % % s %', linedash, obj.properties.crosshairsLinewidth, obj.marginLeft, obj.getYCoord(value), obj.canvas.width - obj.marginRight, obj.getYCoord(value), obj.properties.crosshairsColor ); } // Draw a vertical line if (obj.properties.crosshairsVline) { var [mouseX, mouseY] = RGraph.getMouseXY(e); obj.path( 'b ld % lw % m % % l % % s %', linedash, obj.properties.crosshairsLinewidth, mouseX, obj.properties.marginTop, mouseX, obj.canvas.height - obj.properties.marginBottom, obj.properties.crosshairsColor ); } } } }; RGraph.redrawCanvas(obj.canvas); if ( x >= marginLeft && y >= marginTop && x <= (width - marginRight) && y <= (height - marginBottom) ) { var linewidth = properties.crosshairsLinewidth ? properties.crosshairsLinewidth : 1; obj.context.lineWidth = linewidth ? linewidth : 1; obj.path( 'b ss %', properties.crosshairsColor ); // // The crosshairsSnap option // if (properties.crosshairsSnap && !properties.crosshairsSnapToScale) { // Linear search for the closest point var point = null; var dist = null; var len = null; if (obj.type == 'line') { for (var i=0; i<obj.coords.length; ++i) { var length = RGraph.getHypLength(obj.coords[i][0], obj.coords[i][1], x, y); // Check the mouse X coordinate if (typeof dist != 'number' || length < dist) { var point = i; var dist = length; } } x = obj.coords[point][0]; y = obj.coords[point][1]; // Get the dataset for (var dataset=0; dataset<obj.coords2.length; ++dataset) { for (var point=0; point<obj.coords2[dataset].length; ++point) { if (obj.coords2[dataset][point][0] == x && obj.coords2[dataset][point][1] == y) { obj.canvas.__crosshairs_snap_dataset__ = dataset; obj.canvas.__crosshairs_snap_point__ = point; } } } } else { for (var i=0; i<obj.coords.length; ++i) { for (var j=0; j<obj.coords[i].length; ++j) { // Check the mouse X coordinate var len = RGraph.getHypLength(obj.coords[i][j][0], obj.coords[i][j][1], x, y); if (typeof dist != 'number' || len < dist) { var dataset = i; var point = j; var dist = len; } } } obj.canvas.__crosshairs_snap_dataset__ = dataset; obj.canvas.__crosshairs_snap_point__ = point; x = obj.coords[dataset][point][0]; y = obj.coords[dataset][point][1]; } } else if (!properties.crosshairsSnap && properties.crosshairsSnapToScale) { crosshairsSnapToScale(e); } if (!properties.crosshairsSnapToScale) { // Determine the linedash setting if (properties.crosshairsDotted) { obj.context.setLineDash([1,3]); } else if (properties.crosshairsDashed) { obj.context.setLineDash([5,5]); } else { obj.context.setLineDash([1,1]); } // Draw a vertical line if (properties.crosshairsVline) { obj.context.moveTo(Math.round(x), Math.round(marginTop)); obj.context.lineTo(Math.round(x), Math.round(height - marginBottom)); } // Draw a horizontal line if (properties.crosshairsHline) { obj.context.moveTo(Math.round(marginLeft), Math.round(y)); obj.context.lineTo(Math.round(width - marginRight), Math.round(y)); } } obj.context.stroke(); // // Need to show the coords? // if (obj.type == 'scatter' && properties.crosshairsCoords) { var xCoord = (((x - marginLeft) / (width - marginLeft - marginRight)) * (properties.xaxisScaleMax - properties.xaxisScaleMin)) + properties.xaxisScaleMin; xCoord = xCoord.toFixed(properties.yaxisScaleDecimals); var yCoord = obj.max - (((y - properties.marginTop) / (height - marginTop - marginBottom)) * (obj.max - obj.scale2.min)); if (obj.type == 'scatter' && obj.properties.xaxisPosition === 'center') { yCoord = (yCoord - (obj.max / 2)) * 2; } yCoord = yCoord.toFixed(properties.yaxisScaleDecimals); var div = RGraph.Registry.get('coordinates.coords.div'); var mouseXY = RGraph.getMouseXY(e); var canvasXY = RGraph.getCanvasXY(obj.canvas); if (!div) { var div = document.createElement('DIV'); div.__object__ = obj; div.style.position = 'absolute'; div.style.backgroundColor = 'white'; div.style.border = '1px solid gray'; div.style.fontFamily = 'Arial, Verdana, sans-serif'; div.style.fontSize = '10pt' div.style.padding = '2px'; div.style.opacity = 1; div.style.WebkitBorderRadius = '3px'; div.style.borderRadius = '3px'; div.style.MozBorderRadius = '3px'; div.style.lineHeight = RGraph.ISIE ? 'normal' : 'initial'; document.body.appendChild(div); RGraph.Registry.set('coordinates.coords.div', div); } // Convert the X/Y pixel coords to correspond to the scale div.style.opacity = 1; div.style.display = 'inline'; if (!properties.crosshairsCoordsFixed) { div.style.left = Math.max(2, (e.pageX - div.offsetWidth - 3)) + 'px'; div.style.top = Math.max(2, (e.pageY - div.offsetHeight - 3)) + 'px'; } else { div.style.left = canvasXY[0] + marginLeft + 3 + 'px'; div.style.top = canvasXY[1] + marginTop + 3 + 'px'; } // Use the formatter functions if defined. This allows the user to format them as they wish if (typeof properties.crosshairsCoordsFormatterX === 'function') { xCoord = (properties.crosshairsCoordsFormatterX)({object: obj, value: parseInt(xCoord)}); } if (typeof properties.crosshairsCoordsFormatterY === 'function') { yCoord = (properties.crosshairsCoordsFormatterY)({object: obj, value: parseInt(yCoord)}); } div.innerHTML = '<span id="rgraph_crosshairsCoordsLabelsX">' + properties.crosshairsCoordsLabelsX + ':</span> ' + xCoord + '<br><span id="rgraph_crosshairsCoordsLabelsY">' + properties.crosshairsCoordsLabelsY + ':</span> ' + yCoord; // Change the color of the labels - don't use // inline styles because of CSP security errors document.getElementById('rgraph_crosshairsCoordsLabelsX').style.color = '#666'; document.getElementById('rgraph_crosshairsCoordsLabelsY').style.color = '#666'; obj.canvas.addEventListener('mouseout', RGraph.hideCrosshairCoords, false); obj.canvas.__crosshairs_labels__ = div; obj.canvas.__crosshairs_x__ = xCoord; obj.canvas.__crosshairs_y__ = yCoord; } else if (properties.crosshairsCoords) { alert('[RGRAPH] Showing crosshair coordinates is only supported on the Scatter chart'); } // // Fire the oncrosshairs custom event // RGraph.fireCustomEvent(obj, 'oncrosshairs'); } else { RGraph.hideCrosshairCoords(); } }; // // Adds a mousemove event listener that highlights a segment based on th // mousemove event. Used in the Rose and the RScatter charts // //@param int segments The number of segments to allow // RGraph.allowSegmentHighlight = function (opt) { var obj = opt.object, count = opt.count, fill = opt.fill, stroke = opt.stroke if (!RGraph.segmentHighlightFunction) { RGraph.segmentHighlightFunction = function (e) { var mouseXY = RGraph.getMouseXY(e); var angle = RGraph.getAngleByXY(obj.centerx, obj.centery, mouseXY[0], mouseXY[1]); angle += RGraph.HALFPI; if (angle > RGraph.TWOPI) { angle -= RGraph.TWOPI; } RGraph.redraw(); var start = 0; var end = 0; var a = (Math.PI * 2) / count; // // Radius // var r = obj.radius; (function () { for (i=0; i<count; i+=1) { if (angle < (a * (i + 1))) { start = i * a; end = (i + 1) * a; return; } } })(); start -= RGraph.HALFPI; end -= RGraph.HALFPI; obj.path( 'b m % % a % % % % % false c s % f %', obj.centerx, obj.centery, obj.centerx,obj.centery,r,start,end, stroke, fill ); }; obj.canvas.addEventListener( 'mousemove', RGraph.segmentHighlightFunction, false ); } } // End module pattern })(window, document);