I am using Microsoft Chart control in my project and I want to enable zooming feature in Chart Control by using Mouse Wheel, how can I achieve this?
but user don't have to click on chart, It should be like if mouse position is on my Chart than from that point onward by mouse wheel rolling it can zoom in / out
You'll want to use the MouseWheel event.
First make both axes of your chart zoomable:
chart1.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
chart1.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
And assign the event:
chart1.MouseWheel += chart1_MouseWheel;
Then in the event handler:
private void chart1_MouseWheel(object sender, MouseEventArgs e)
{
var chart = (Chart)sender;
var xAxis = chart.ChartAreas[0].AxisX;
var yAxis = chart.ChartAreas[0].AxisY;
try
{
if (e.Delta < 0) // Scrolled down.
{
xAxis.ScaleView.ZoomReset();
yAxis.ScaleView.ZoomReset();
}
else if (e.Delta > 0) // Scrolled up.
{
var xMin = xAxis.ScaleView.ViewMinimum;
var xMax = xAxis.ScaleView.ViewMaximum;
var yMin = yAxis.ScaleView.ViewMinimum;
var yMax = yAxis.ScaleView.ViewMaximum;
var posXStart = xAxis.PixelPositionToValue(e.Location.X) - (xMax - xMin) / 4;
var posXFinish = xAxis.PixelPositionToValue(e.Location.X) + (xMax - xMin) / 4;
var posYStart = yAxis.PixelPositionToValue(e.Location.Y) - (yMax - yMin) / 4;
var posYFinish = yAxis.PixelPositionToValue(e.Location.Y) + (yMax - yMin) / 4;
xAxis.ScaleView.Zoom(posXStart, posXFinish);
yAxis.ScaleView.Zoom(posYStart, posYFinish);
}
}
catch { }
}
The e.Delta property tells you how many wheel "scrolls" you've done, and can be useful.
Scrolling out at all will zoom out the whole way.
There's probably a cleaner way of doing this, but there it is.
Hope this helps!
I modificated code from above and added a reverse zooming using Stack.
private class ZoomFrame
{
public double XStart { get; set; }
public double XFinish { get; set; }
public double YStart { get; set; }
public double YFinish { get; set; }
}
private readonly Stack<ZoomFrame> _zoomFrames = new Stack<ZoomFrame>();
private void chart1_MouseWheel(object sender, MouseEventArgs e)
{
var chart = (Chart)sender;
var xAxis = chart.ChartAreas[0].AxisX;
var yAxis = chart.ChartAreas[0].AxisY;
try
{
if (e.Delta < 0)
{
if (0 < _zoomFrames.Count)
{
var frame = _zoomFrames.Pop();
if (_zoomFrames.Count == 0)
{
xAxis.ScaleView.ZoomReset();
yAxis.ScaleView.ZoomReset();
}
else
{
xAxis.ScaleView.Zoom(frame.XStart, frame.XFinish);
yAxis.ScaleView.Zoom(frame.YStart, frame.YFinish);
}
}
}
else if (e.Delta > 0)
{
var xMin = xAxis.ScaleView.ViewMinimum;
var xMax = xAxis.ScaleView.ViewMaximum;
var yMin = yAxis.ScaleView.ViewMinimum;
var yMax = yAxis.ScaleView.ViewMaximum;
_zoomFrames.Push(new ZoomFrame { XStart = xMin, XFinish = xMax, YStart = yMin, YFinish = yMax });
var posXStart = xAxis.PixelPositionToValue(e.Location.X) - (xMax - xMin) / 4;
var posXFinish = xAxis.PixelPositionToValue(e.Location.X) + (xMax - xMin) / 4;
var posYStart = yAxis.PixelPositionToValue(e.Location.Y) - (yMax - yMin) / 4;
var posYFinish = yAxis.PixelPositionToValue(e.Location.Y) + (yMax - yMin) / 4;
xAxis.ScaleView.Zoom(posXStart, posXFinish);
yAxis.ScaleView.Zoom(posYStart, posYFinish);
}
}
catch { }
}
Hope this helps!
I modificated code from above and added a reverse zooming. So when you rotate a mouse wheel back the chart zoom out. Also i don't recommend use 2^n as divider of the interval because it cause lag.
numberOfZoom - counter of Zooming
private void Chart1_MouseWheel(object sender, MouseEventArgs e)
{
var chart = (Chart)sender;
var xAxis = chart.ChartAreas[0].AxisX;
var yAxis = chart.ChartAreas[0].AxisY;
var xMin = xAxis.ScaleView.ViewMinimum;
var xMax = xAxis.ScaleView.ViewMaximum;
var yMin = yAxis.ScaleView.ViewMinimum;
var yMax = yAxis.ScaleView.ViewMaximum;
int IntervalX = 3;
int IntervalY = 3;
try
{
if (e.Delta < 0 && numberOfZoom > 0) // Scrolled down.
{
var posXStart = xAxis.PixelPositionToValue(e.Location.X) - IntervalX *2/ Math.Pow(2, numberOfZoom);
var posXFinish = xAxis.PixelPositionToValue(e.Location.X) + IntervalX *2/ Math.Pow(2, numberOfZoom);
var posYStart = yAxis.PixelPositionToValue(e.Location.Y) - IntervalY*2 / Math.Pow(2, numberOfZoom);
var posYFinish = yAxis.PixelPositionToValue(e.Location.Y) + IntervalY*2 / Math.Pow(2, numberOfZoom);
if (posXStart < 0) posXStart = 0;
if (posYStart < 0) posYStart = 0;
if (posYFinish > yAxis.Maximum) posYFinish = yAxis.Maximum;
if (posXFinish > xAxis.Maximum) posYFinish = xAxis.Maximum;
xAxis.ScaleView.Zoom(posXStart, posXFinish);
yAxis.ScaleView.Zoom(posYStart, posYFinish);
numberOfZoom--;
}else if (e.Delta < 0 && numberOfZoom == 0) //Last scrolled dowm
{
yAxis.ScaleView.ZoomReset();
xAxis.ScaleView.ZoomReset();
}
else if (e.Delta > 0) // Scrolled up.
{
var posXStart = xAxis.PixelPositionToValue(e.Location.X) - IntervalX / Math.Pow(2, numberOfZoom);
var posXFinish = xAxis.PixelPositionToValue(e.Location.X) + IntervalX / Math.Pow(2, numberOfZoom);
var posYStart = yAxis.PixelPositionToValue(e.Location.Y) - IntervalY / Math.Pow(2, numberOfZoom);
var posYFinish = yAxis.PixelPositionToValue(e.Location.Y) + IntervalY / Math.Pow(2, numberOfZoom);
xAxis.ScaleView.Zoom(posXStart, posXFinish);
yAxis.ScaleView.Zoom(posYStart, posYFinish);
numberOfZoom++;
}
if (numberOfZoom < 0) numberOfZoom = 0;
}
catch { }
}
Waaaay late to the party, but I had this challenge myself today.
I am sure the following can be improved, still, but it's what I came up with.
I tested this with .net 4.5.2 and 4.6, so I am not sure if it works with older frameworks.
I've combined a couple of answers from way in the past and made the following:
using System;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
namespace ExampleApp
{
public partial class Form1 : Form
{
private const float CZoomScale = 4f;
private int FZoomLevel = 0;
public Form1()
{
InitializeComponent();
chart1.MouseWheel += Chart1_MouseWheel;
}
private void Chart1_MouseEnter(object sender, EventArgs e)
{
if (!chart1.Focused)
chart1.Focus();
}
private void Chart1_MouseLeave(object sender, EventArgs e)
{
if (chart1.Focused)
chart1.Parent.Focus();
}
private void Chart1_MouseWheel(object sender, MouseEventArgs e)
{
try {
Axis xAxis = chart1.ChartAreas[0].AxisX;
double xMin = xAxis.ScaleView.ViewMinimum;
double xMax = xAxis.ScaleView.ViewMaximum;
double xPixelPos = xAxis.PixelPositionToValue(e.Location.X);
if (e.Delta < 0 && FZoomLevel > 0) {
// Scrolled down, meaning zoom out
if (--FZoomLevel <= 0) {
FZoomLevel = 0;
xAxis.ScaleView.ZoomReset();
} else {
double xStartPos = Math.Max(xPixelPos - (xPixelPos - xMin) * CZoomScale, 0);
double xEndPos = Math.Min(xStartPos + (xMax - xMin) * CZoomScale, xAxis.Maximum);
xAxis.ScaleView.Zoom(xStartPos, xEndPos);
}
} else if (e.Delta > 0) {
// Scrolled up, meaning zoom in
double xStartPos = Math.Max(xPixelPos - (xPixelPos - xMin) / CZoomScale, 0);
double xEndPos = Math.Min(xStartPos + (xMax - xMin) / CZoomScale, xAxis.Maximum);
xAxis.ScaleView.Zoom(xStartPos, xEndPos);
FZoomLevel++;
}
} catch { }
}
}
}
Related
I want to move the zoomed image with gyroscope. As you can see in below code I can do this thing by hand and I got a good result. I have to write something inside "Gyroscope_ReadingChanged" to convert gyroscope data to the Content.TranslationX and Content.TranslationY. Any help would be appreciated.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:video="clr-namespace:UbSports.Controls"
xmlns:local="clr-namespace:UbSports.Controls"
x:Class="UbSports.Pages.TestPage">
<local:PinchToZoomContainer VerticalOptions="FillAndExpand">
<local:PinchToZoomContainer.Content>
<Image x:Name="image" Source="waterfront.jpg" />
</local:PinchToZoomContainer.Content>
</local:PinchToZoomContainer>
</ContentPage>
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestPage: ContentPage
{
public TestPage()
{
InitializeComponent();
}
}
public class PinchToZoomContainer : ContentView
{
public PinchToZoomContainer()
{
Gyroscope.ReadingChanged += Gyroscope_ReadingChanged;
try
{
Gyroscope.Start(SensorSpeed.UI);
}
catch (FeatureNotSupportedException fnsEx)
{
}
catch (Exception ex)
{
}
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(panGesture);
var pinchGesture = new PinchGestureRecognizer();
pinchGesture.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add(pinchGesture);
}
void Gyroscope_ReadingChanged(object sender, GyroscopeChangedEventArgs e)
{
var data = e.Reading;
if (data.AngularVelocity.X == 0 && data.AngularVelocity.Y == 0) return;
// do something
}
void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Started:
startX = e.TotalX;
startY = e.TotalY;
Content.AnchorX = 0;
Content.AnchorY = 0;
break;
case GestureStatus.Running:
var maxTranslationX = Content.Scale * Content.Width - Content.Width;
Content.TranslationX = Math.Min(0, Math.Max(-maxTranslationX, xOffset + e.TotalX - startX));
var maxTranslationY = Content.Scale * Content.Height - Content.Height;
Content.TranslationY = Math.Min(0, Math.Max(-maxTranslationY, yOffset + e.TotalY - startY));
break;
case GestureStatus.Completed:
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
break;
}
}
void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started)
{
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
}
if (e.Status == GestureStatus.Running)
{
currentScale += (e.Scale - 1) * startScale;
currentScale = Math.Max(1, currentScale);
double renderedX = Content.X + xOffset;
double deltaX = renderedX / Width;
double deltaWidth = Width / (Content.Width * startScale);
double originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
double renderedY = Content.Y + yOffset;
double deltaY = renderedY / Height;
double deltaHeight = Height / (Content.Height * startScale);
double originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
double targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
double targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);
Content.TranslationX = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
Content.TranslationY = targetY.Clamp(-Content.Height * (currentScale - 1), 0);
Content.Scale = currentScale;
}
if (e.Status == GestureStatus.Completed)
{
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
}
}
}
This question already has answers here:
All possible array initialization syntaxes
(19 answers)
Closed 2 years ago.
Is there a way to declare a array that contains float variables and that has a fixed size of an int?
int balls = 5;
float array posX[balls];
private float posY[] = 0;
basically, I want to create an array so that each ball can have its own XY coords without creating a handful of new variables. I am getting errors saying that I have bad array declaration (line 3) and that posX and Balls does not exist in the current context (line 2). The code above is some of my trial and error. I'm making a xamarin forms app so maybe that has something to do with it? My full code is this:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using SkiaSharp;
using SkiaSharp.Views.Forms;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.CompilerServices;
using System.Linq.Expressions;
using Xamarin.Forms.Internals;
namespace Ball_Bounce
{
public partial class MainPage : ContentPage
{
int balls = 5;
float array posX[balls];
private float posY[] = 0;
float dx = 5;
float dy = 5;
int ballD = 100;
bool gravity = false;
float time = 1f / 60;
float mass = 10;
float g = -9.8f;
float forceOnWalls = 0;
int bounces = 0;
SKPaint blackFillPaint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.Black
};
SKPaint Ball = new SKPaint
{
Color = SKColors.Black,
};
public MainPage()
{
InitializeComponent();
Device.StartTimer(TimeSpan.FromSeconds(1f / 60), () =>
{
CanvasView.InvalidateSurface();
return true;
});
}
private void CanvasView_PaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
SKSurface surface = e.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear(SKColors.SteelBlue);
float width = e.Info.Width;
float height = e.Info.Height;
canvas.Translate(width / 2, height / 2);
posX += dx;
posY += dy;
if (gravity == false)
{
bounces = 0;
if (posX >= width / 2 - ballD|| posX <= -width / 2 + ballD)
{
dx = -dx;
}
else if (posY >= height / 2 - ballD|| posY <= -height / 2 + ballD)
{
dy = -dy;
}
}
else if (gravity == true)
{
if (bounces >= 8)
{
dy = 0;
posY = height / 2 - ballD;
}
dy = Gravity(dy, time);
if (posX >= width / 2 - ballD || posX <= -width / 2 + ballD)
{
dx = -dx;
}
else if (posY >= height / 2 - ballD || posY <= -height / 2 + ballD)
{
dy = -dy+dy/5;
bounces += 1;
}
//forceOnWalls = mass * Math.Abs(dy);
//if (posY < height / 2 + 11*ballD/10)
//{
// dy = Gravity(dy, time);
// if (posX >= width / 2 - ballD || posX <= -width / 2 + ballD)
// {
// dx = -dx;
// }
// else if (posY > (height / 2) - (ballD + 10))
// {
// dy = -dy + 2f; //slows bouncing
// }
}
//else if (posY >= height / 2 - 9 * ballD / 10 && posY <= height / 2 - 2 * ballD && (forceOnWalls < 1 && forceOnWalls > 0))
//{
// if (posX >= width / 2 - ballD || posX <= -width / 2 + ballD)
// {
// dx = -dx;
// }
// posY = height / 2 - ballD;
// dy = 0;
canvas.DrawCircle(posX, posY, ballD, blackFillPaint);
}
void OnToggled(object sender, ToggledEventArgs e)
{
if (gravity == true)
{
dy = -5;
gravity = false;
}
else
{
gravity = true;
}
}
void OnSpeedValueChanged(object sender, ValueChangedEventArgs args)
{
double value = args.NewValue;
float valueF = Convert.ToSingle(value);
float signX = Math.Sign(dx);
float signY = Math.Sign(dy);
dx = valueF * signX;
dy = valueF * signY;
}
void OnGravityValueChanged(object sender, ValueChangedEventArgs args) //slider that controls
{
double value = args.NewValue;
float valueF = Convert.ToSingle(value);
g = valueF;
}
public static float Gravity(float vOld, float time) //calculates the dy changes
{
float g = 15f;
float vNew = vOld + g * time;
return vNew;
}
}
}
this is a fixed size (10) float array
float[] array = new float[10];
To prevent your errors, do your assignments inside the constructor
namespace Ball_Bounce
{
public partial class MainPage : ContentPage
{
int balls;
float[] array;
private float posY;
....
public MainPage()
{
balls = 5;
array = new float[balls];
posY = 0;
}
I have a problem. I created an image within a AbsoluteLayout with a panGestureRecognizer, but when I use that to move the image in the app, it jumps back and forth. Very annoying. Here is the code I am using
private void AddImageToPreview(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
var image = (Image)e.NewItems[e.NewItems.Count - 1];
PanGestureRecognizer panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += PanUpdated;
image.GestureRecognizers.Add(panGesture);
MyLayout.Children.Add(image);
}
}
void PanUpdated(object sender, PanUpdatedEventArgs args)
{
Image image = (Image)sender;
if (args.StatusType.Equals(GestureStatus.Running))
{
x = args.TotalX;
y = args.TotalY;
image.TranslateTo(x, y, 1);
}
}
Can someone help me improve this, so this drag/drop system works smooth and fast!
I have a control purely made in Xamarin.Forms that you can use for the above mentioned usage:
using System;
using Xamarin.Forms;
using FFImageLoading.Forms;
public class ZoomImage : CachedImage
{
private const double MIN_SCALE = 1;
private const double MAX_SCALE = 4;
private const double OVERSHOOT = 0.15;
private double StartScale, LastScale;
private double StartX, StartY;
public ZoomImage()
{
var pinch = new PinchGestureRecognizer();
pinch.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add(pinch);
var pan = new PanGestureRecognizer();
pan.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(pan);
var tap = new TapGestureRecognizer { NumberOfTapsRequired = 2 };
tap.Tapped += OnTapped;
GestureRecognizers.Add(tap);
Scale = MIN_SCALE;
TranslationX = TranslationY = 0;
AnchorX = AnchorY = 0;
}
protected override SizeRequest OnMeasure(double widthConstraint, double heightConstraint)
{
Scale = MIN_SCALE;
TranslationX = TranslationY = 0;
AnchorX = AnchorY = 0;
return base.OnMeasure(widthConstraint, heightConstraint);
}
private void OnTapped(object sender, EventArgs e)
{
if (Scale > MIN_SCALE)
{
this.ScaleTo(MIN_SCALE, 250, Easing.CubicInOut);
this.TranslateTo(0, 0, 250, Easing.CubicInOut);
}
else
{
AnchorX = AnchorY = 0.5; //TODO tapped position
this.ScaleTo(MAX_SCALE, 250, Easing.CubicInOut);
}
}
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Started:
StartX = (1 - AnchorX) * Width;
StartY = (1 - AnchorY) * Height;
break;
case GestureStatus.Running:
AnchorX = Clamp(1 - (StartX + e.TotalX) / Width, 0, 1);
AnchorY = Clamp(1 - (StartY + e.TotalY) / Height, 0, 1);
break;
}
}
private void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
switch (e.Status)
{
case GestureStatus.Started:
LastScale = e.Scale;
StartScale = Scale;
AnchorX = e.ScaleOrigin.X;
AnchorY = e.ScaleOrigin.Y;
break;
case GestureStatus.Running:
if (e.Scale < 0 || Math.Abs(LastScale - e.Scale) > (LastScale * 1.3) - LastScale)
{ return; }
LastScale = e.Scale;
var current = Scale + (e.Scale - 1) * StartScale;
Scale = Clamp(current, MIN_SCALE * (1 - OVERSHOOT), MAX_SCALE * (1 + OVERSHOOT));
break;
case GestureStatus.Completed:
if (Scale > MAX_SCALE)
this.ScaleTo(MAX_SCALE, 250, Easing.SpringOut);
else if (Scale < MIN_SCALE)
this.ScaleTo(MIN_SCALE, 250, Easing.SpringOut);
break;
}
}
private T Clamp<T>(T value, T minimum, T maximum) where T: IComparable
{
if (value.CompareTo(minimum) < 0)
return minimum;
else if (value.CompareTo(maximum) > 0)
return maximum;
else
return value;
}
}
What this does:
Pinch zoom, Pan and Swipe movements together with double tap centre zoom and un-zoom
Note: I have used FFimageLoading's CachedImage because I needed to cache the data in case you do not intend this replace CachedImage with Xamarin.Forms.Image
I have list XY points are including 16000 points, I deployed it to 2 chart type waveform chart and arc graph. I used the class name is VerticalLineAnnotation to design the vertical line on waveform chart and add series chart type line on arc graph to reflect any the last X point of the veritcal line on arc graph. When move the vertical line to left-right, it work very well but when I leave mouse out the line, the charts (waveforma and arc graph) are redraw and take to long time. How can I prevent it (redraw event) or speed up?.
This is source code
ChartArea CA;
Series S1;
VerticalLineAnnotation VA;
double degree = 0;
int test = 0;
Dictionary<int, PointXY> xyMap = new Dictionary<int, PointXY>();
private void DrawGraph(DataTable dtExcel)
{
Series series1 = new Series("Series2");
series1.ChartArea = "ChartArea1";
series1.ChartType = SeriesChartType.Spline;
series1.Color = Color.White;
chart1.ChartAreas["ChartArea1"].AxisY.Minimum = 1000;
chart1.ChartAreas["ChartArea1"].AxisY.Maximum = 4500;
chart1.ChartAreas["ChartArea1"].AxisY.Interval = 500;
chart1.ChartAreas["ChartArea1"].AxisX.Minimum = 0;
chart1.ChartAreas["ChartArea1"].AxisX.Maximum = 16000;
chart1.ChartAreas["ChartArea1"].AxisX.Interval = 1000;
Series series2 = new Series("Series2");
series2.ChartArea = "ChartArea1";
series2.ChartType = SeriesChartType.Spline;
series2.Color = Color.White;
chart2.ChartAreas["ChartArea1"].AxisY.Minimum = -100;
chart2.ChartAreas["ChartArea1"].AxisY.Maximum = 100;
chart2.ChartAreas["ChartArea1"].AxisY.Interval = 10;
chart2.ChartAreas["ChartArea1"].AxisX.Minimum = -100;
chart2.ChartAreas["ChartArea1"].AxisX.Maximum = 100;
chart2.ChartAreas["ChartArea1"].AxisX.Interval = 10;
foreach (DataRow item in dtExcel.Rows)
{
series1.Points.AddXY(int.Parse(item[0].ToString()), item[1].ToString());
CaculatePointXY(item, series2);
}
chart1.Series.Add(series1);
chart1.ChartAreas["ChartArea1"].AxisX.MajorGrid.LineColor = Color.Green;
chart1.ChartAreas["ChartArea1"].AxisY.MajorGrid.LineColor = Color.Green;
chart1.ChartAreas["ChartArea1"].AxisX.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont;
chart2.Series.Add(series2);
chart2.ChartAreas["ChartArea1"].AxisX.MajorGrid.LineColor = Color.Green;
chart2.ChartAreas["ChartArea1"].AxisY.MajorGrid.LineColor = Color.Green;
chart2.ChartAreas["ChartArea1"].AxisX.LabelAutoFitStyle = LabelAutoFitStyles.DecreaseFont;
//Draw vertical line
CA = chart1.ChartAreas["ChartArea1"];
VA = new VerticalLineAnnotation();
VA.AxisX = CA.AxisX;
VA.AllowMoving = true;
VA.IsInfinitive = true;
VA.ClipToChartArea = CA.Name;
VA.Name = "myLine";
VA.LineColor = Color.Red;
VA.LineWidth = 2; // use your numbers!
VA.X = 8000;
chart1.Annotations.Add(VA);
chart2.Series.Add("Line");
chart2.Series["Line"].Points.Add(new DataPoint(0, 0));
chart2.Series["Line"].Color = Color.Red;
chart2.Series["Line"].BorderWidth = 2;
chart2.Series["Line"].Points.Add(new DataPoint(0, 100));
chart2.Series["Line"].ChartType = SeriesChartType.Line;
}
private void CaculatePointXY(DataRow item, Series series2)
{
double distance = (int.Parse(item[1].ToString()) - 819) * 0.0030525;
distance += 95;
double x = distance * Math.Cos((degree * Math.PI / 180));
double y = distance * Math.Sin((degree * Math.PI / 180));
series2.Points.AddXY(x, y);
xyMap.Add(int.Parse(item[0].ToString()), new PointXY()
{
X = x,
Y = y
});
degree += 0.0225;
}
private void chart1_Customize(object sender, EventArgs e)
{
foreach (var label in chart1.ChartAreas[0].AxisY.CustomLabels)
{
label.Text = ((int)double.Parse(label.Text) / 100).ToString();
}
foreach (var label in chart1.ChartAreas[0].AxisX.CustomLabels)
{
label.Text = ((int)double.Parse(label.Text) / 100).ToString();
}
}
private void chart1_MouseDoubleClick(object sender, MouseEventArgs e)
{
var xVal = chart1.ChartAreas[0].AxisX.PixelPositionToValue(e.X);
var yVal = chart1.ChartAreas[0].AxisY.PixelPositionToValue(e.Y);
ZoomWaveFormGraph(xVal, yVal);
}
private void ZoomWaveFormGraph(double xVal, double yVal)
{
ZoomArcGraph((int)xVal);
var YMin = Math.Round(yVal - 1000, 0);
var YMax = Math.Round(yVal + 1000, 0);
chart1.ChartAreas["ChartArea1"].AxisY.Minimum = YMin;
chart1.ChartAreas["ChartArea1"].AxisY.Maximum = YMax;
chart1.ChartAreas["ChartArea1"].AxisY.Interval = 100;
var XMin = Math.Round(xVal - 1000, 0);
var XMax = Math.Round(xVal + 1000, 0);
chart1.ChartAreas["ChartArea1"].AxisX.Minimum = XMin;
chart1.ChartAreas["ChartArea1"].AxisX.Maximum = XMax;
chart1.ChartAreas["ChartArea1"].AxisX.Interval = 200;
}
private void ZoomArcGraph(double xVal)
{
int a = (int)xVal;
var b = xyMap[a];
chart2.ChartAreas["ChartArea1"].AxisY.Minimum = Math.Round(b.Y - 20, 0);
chart2.ChartAreas["ChartArea1"].AxisY.Maximum = Math.Round(b.Y + 20, 0);
chart2.ChartAreas["ChartArea1"].AxisY.Interval = 2;
chart2.ChartAreas["ChartArea1"].AxisX.Minimum = Math.Round(b.X - 20, 0);
chart2.ChartAreas["ChartArea1"].AxisX.Maximum = Math.Round(b.X + 20, 0);
chart2.ChartAreas["ChartArea1"].AxisX.Interval = 2;
}
private double RadianToDegree(double angle)
{
return angle * (180.0 / Math.PI);
}
private void chart1_AnnotationPositionChanging(object sender, AnnotationPositionChangingEventArgs e)
{
test = (int)Math.Round(e.NewLocationX, 0);
Console.WriteLine("X : " + e.NewLocationX.ToString());
}
private void chart1_AnnotationPositionChanged(object sender, EventArgs e)
{
var a = xyMap[test];
chart2.Series["Line"].Points.ElementAt(1).SetValueXY(a.X, a.Y);
chart2.Refresh();
}
Into Copystransform, if I removed 2 in the end of line then I will could zoom in and out but could not drag while that have zoom in.
what else I did not remove then can't zoom and can't drag. It just zoom when the picture is small else if the picture is full screen then did not that.
Link:http://blogs.msdn.com/b/wsdevsol/archive/2014/06/10/constraining-manipulations.aspx
double mincale = 0.5;
//double maxscale = 10.0;
CompositeTransform savedtransform = new CompositeTransform();
private void Image_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
// FrameworkElement elemt = sender as FrameworkElement;
Image elemt = sender as Image;
CompositeTransform transform = elemt.RenderTransform as CompositeTransform;
//
copytransform(transform,savedtransform);
//apply
transform.ScaleX *= e.Delta.Scale;
transform.ScaleY *= e.Delta.Scale;
transform.TranslateX += e.Delta.Translation.X;
transform.TranslateY += e.Delta.Translation.Y;
if (transform.ScaleX < mincale) transform.ScaleX = mincale;
if (transform.ScaleY < mincale) transform.ScaleY = mincale;
// if (transform.ScaleX > maxscale) transform.ScaleX = maxscale;
// if (transform.ScaleY > maxscale) transform.ScaleY = maxscale;
if(elemt!=null)
{
if(!intersetElemnets(elemt,this.content,true))
{
copytransform(savedtransform, transform);
}
}
/*
double scalewidth = Zoomimages.ActualWidth * ct.ScaleX;
double scleheight = Zoomimages.ActualHeight * ct.ScaleY;
double xdiff = Math.Max(0, (scalewidth - this.content.ActualWidth) / 2);
double ydiff = Math.Max(0, (scleheight - this.content.ActualHeight) / 2);
if (Math.Abs(ct.TranslateX) > xdiff)
ct.TranslateX = xdiff * Math.Sign(e.Delta.Translation.X);
if (Math.Abs(ct.TranslateY) > ydiff)
ct.TranslateY = ydiff * Math.Sign(e.Delta.Translation.Y);
* */
}
private bool intersetElemnets(FrameworkElement inner, FrameworkElement outer,bool contains)
{
GeneralTransform testTransform = inner.TransformToVisual(outer);
//
Rect boundsinner = new Rect(0,0,inner.ActualWidth,inner.ActualHeight);
Rect bboxouter = new Rect(0, 0, outer.ActualWidth, outer.ActualHeight);
Rect bboxinner = testTransform.TransformBounds(boundsinner);
if(contains)
{
return bboxinner.X > bboxouter.Y &&
bboxinner.Y > bboxouter.Y &&
bboxinner.Right < bboxouter.Right &&
bboxinner.Bottom < bboxouter.Bottom;
}
else
{
bboxouter.Intersect(bboxinner);
return !bboxouter.IsEmpty;
}
}
private void copytransform(CompositeTransform orig,CompositeTransform copy)
{
copy.TranslateX = orig.TranslateX;
copy.TranslateY = orig.TranslateY;
copy.ScaleX = orig.ScaleX;
copy.ScaleY = orig.ScaleY;
}