05-20-2010 05:15 PM
My goal is to create a WaveForm graph with the following criteria.
With the code below, I can double-click to draw cursor at the nearest point and draw a box to zoom in. However, I can't figure out how to zoom out.
What am I doing wrong?
(Measurement Studio 8.5 & Visual Studio 2008)
Imports NationalInstruments
Imports NationalInstruments.UI
Imports System.Drawing
Partial Public Class PlotData
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then 'generate initial random waveform
myGraph.PlotY(GenerateData(1000))
End If
End Sub
Protected Sub myGraph_PlotAreaClick(ByVal sender As Object, ByVal e As NationalInstruments.UI.ClickEventArgs) Handles myGraph.PlotAreaClick
Dim plotX As Double, plotY As Double
InverseMap(myGraph, e.X, e.Y, plotX, plotY)
myGraph.Cursors(0).MoveCursor(plotX, plotY)
'Show click and plot coordinates
cursor_lbl.Text = "X: " & e.X & " Y: " & e.Y & " pX: " & plotX & " pY: " & plotY
End Sub
Private Shared Function GenerateData(ByVal dataLength As Integer) As Double()
Dim data(dataLength) As Double
Dim rnd As New Random()
For i As Integer = 0 To dataLength - 1
data(i) = rnd.NextDouble() * Math.Sin((i / 3.15))
Next
Return data
End Function
Private Shared Sub InverseMap(ByVal graph As NationalInstruments.UI.WebForms.WaveformGraph, ByVal xClick As Integer, ByVal yClick As Integer, ByRef xPlot As Double, ByRef yPlot As Double)
Dim xMin As Double, xMax As Double
Dim yMin As Double, yMax As Double
Dim plotLeft As Double, plotRight As Double
Dim plotTop As Double, plotBottom As Double
xMin = graph.XAxes(0).Range.Minimum
xMax = graph.XAxes(0).Range.Maximum
yMin = graph.YAxes(0).Range.Minimum
yMax = graph.YAxes(0).Range.Maximum
With graph.PlotAreaBounds
plotLeft = .Left
plotRight = .Right
plotTop = .Top
plotBottom = .Bottom
End With
xPlot = ((xMax - xMin) * ((xClick - plotLeft) / (plotRight - plotLeft))) + xMin
yPlot = ((yMax - yMin) * ((plotBottom - yClick) / (plotBottom - plotTop))) + yMin
End Sub
End Class
<ni:WaveformGraph runat="server" ID="myGraph" Width="1000px" Height="500px"
InteractionMode="ZoomX, ZoomY, PlotAreaClick">
<XAxes><ni:XAxis Mode="Fixed" Range="400, 600"/></XAxes>
<YAxes><ni:YAxis/></YAxes>
<Cursors><ni:XYCursor Plot="Plots[0]" /></Cursors>
<Plots><ni:WaveformPlot /></Plots>
</ni:WaveformGraph>
Solved! Go to Solution.
05-21-2010 09:31 AM - edited 05-21-2010 09:33 AM
Hi Steven,
The solution I can think of is to use a special key (say Control key) along with a mouse click to zoom out. This will need quite a bit of work on your part.
The plot are click event does not provide info about if there was a key press. In order to do this, you will need to manually pass some information from client side to the server side that you had pressed the control key while you clicked. This can be done using a HTML hidden field.
How to pass the control key pressed info from client to server?
1) Add a hidden field (say with id and name attributes set to 'ControlKeyPressed') inside the form that is rendered by default in the .aspx file.
2) At the end of the form, Register the key down and key up events on the document.
3) In the javascript event handlers, when the control key is pressed, set the hidden field's value as 'Y', in all other cases, the hidden field's value will be set to 'N'.
The .aspx code would look something like,
<form id="form1" runat="server">
<!-- IMPORTANT: The hidden field that you would need to pass data to server -->
<input type ="hidden" id="ControlKeyPressed" name="ControlKeyPressed" value="" />
<div>
<ni:WaveformGraph ID="WaveformGraph1" runat="server"
InteractionMode="ZoomX, ZoomY, PlotAreaClick"
onplotareaclick="WaveformGraph1_PlotAreaClick">
<XAxes>
<ni:XAxis>
</ni:XAxis>
</XAxes>
<Plots>
<ni:WaveformPlot XAxis="XAxes[0]" YAxis="YAxes[0]" />
</Plots>
<YAxes>
<ni:YAxis>
</ni:YAxis>
</YAxes>
</ni:WaveformGraph>
</div>
</form>
<!-- Javascript -->
<script type="text/javascript">
function myKeyDownHandler(e) {
if (!e) e = event;
var x = document.getElementById("ControlKeyPressed");
if (e.keyCode == 17) { // check code for contro key.// If key pressed is control, then set the hidden fields value to 'Y'.
x.value = "Y";
}
else {
x.value = "N";
}
}
function myKeyUpHandler(e) {
if (!e) e = event;
var x = document.getElementById("ControlKeyPressed");
if (e.keyCode == 17) {// Here the control is is released, so change back the hidden field's value to 'N'.
x.value = "N";
}
}
function init() {// Attach the events.
if (document.attachEvent) {
document.attachEvent("onkeydown", myKeyDownHandler);
document.attachEvent("onkeypress", myKeyDownHandler);
document.attachEvent("onkeyup", myKeyUpHandler);
}
}
// IMPORTANT: Dont forget to call the init() function once when the document is loaded.
init();
</script>
Now, when there is a PlotAreaClick event fired on the server (here server meaning the C#/VB code), the server maintains the parameters that the client had sent. You can access parameters as follows,
string str = Context.Request.Params["ControlKeyPressed"] as string;
Now, your PlotAreaClick event handler would look something like,
protected void WaveformGraph1_PlotAreaClick(object sender, ClickEventArgs e)
{
if (IsPlotAreaClick())
{
//--------------------------------------------------------------------------------------
// Important Note:
// You will have to maintain a stack to remember the ranges of x/y axes before you set the new ranges.
// Keep the stack in a session variable or an application varaible or make the stack a static variable.
// First, Push the current x/y ranges to the stack.
//--------------------------------------------------------------------------------------
//Then, perform the tasks that you intend to do.
//Set the calculated new range to x/y axes.
WaveformGraph1.XAxes[0].Range = new Range(0, 1); // This is your calculated new range.
WaveformGraph1.YAxes[0].Range = new Range(0, 1); // This is your calculated new range.
}
else
{
//Pop the item from stack and assign the range to x/y axes.
WaveformGraph1.XAxes[0].Range = new Range(0, 10); // here you should use the value popped from stack.
WaveformGraph1.YAxes[0].Range = new Range(0, 10); // here you should use the value popped from stack.
}
}
private bool IsPlotAreaClick()
{
string str = Context.Request.Params["ControlKeyPressed"] as string;// If the parameter value is 'Y' then that means the action was a zoom back out, not a plot area click.
if (str == "Y")
return false;
else return true;
}
Hope this helps.
05-21-2010 10:11 AM
Wow. In the meantime, I just added a form button which calls myGraph.ResetZoomPan(). For simplicity, I'll probably just stick with that.
Also, do you happen to know why a double-click (instead of a single click) is required to trigger the PlotAreaClick event?