I am working on an application which can take input thru touch screen using mouse or stylus.. Found that <InkCanvas> works really great for me, but Windows Store app project does not recognize/support <InkCanvas> tag.
Does any came across similar kind of requirement and scenario.
Any suggestion.
Of course, one of them is but it is not as flexible as <InkCanvas>
Use this control in xaml like: <ctrl:InkCanvas x:Name="inkCanvas" />
Don't forget to reference 'ctrl' like: xmlns:ctrl="using:MyAppNamespace"
using System;
using System.Collections.Generic;
using Windows.Devices.Input;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Input;
using Windows.UI.Input.Inking;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
using System.Linq;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Media.Imaging;
using System.Runtime.InteropServices.WindowsRuntime;
namespace MyAppNamespace
{
public class InkCanvas : Canvas
{
InkManager m_InkManager = new Windows.UI.Input.Inking.InkManager();
private uint m_PenId;
private uint _touchID;
private Point _previousContactPt;
private Point currentContactPt;
private double x1;
private double y1;
private double x2;
private double y2;
private Color m_CurrentDrawingColor = Colors.Black;
private double m_CurrentDrawingSize = 4;
public List<InkStroke> Strokes { get { return m_InkManager.GetStrokes().ToList(); } }
public InkCanvas()
{
m_InkManager.Mode = Windows.UI.Input.Inking.InkManipulationMode.Inking;
SetDefaults(m_CurrentDrawingSize, m_CurrentDrawingColor);
this.PointerPressed += new PointerEventHandler(OnCanvasPointerPressed);
this.PointerMoved += new PointerEventHandler(OnCanvasPointerMoved);
this.PointerReleased += new PointerEventHandler(OnCanvasPointerReleased);
this.PointerExited += new PointerEventHandler(OnCanvasPointerReleased);
}
public void Clear()
{
this.Children.Clear();
var strokes = m_InkManager.GetStrokes();
for (int i = 0; i < strokes.Count; i++)
strokes[i].Selected = true;
m_InkManager.DeleteSelected();
}
public async Task<byte[]> GetBytes()
{
var bytes = new byte[0];
if (Strokes.Count > 0)
{
var tempFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(Guid.NewGuid().ToString() + ".jpg");
var writeStream = await tempFile.OpenAsync(FileAccessMode.ReadWrite);
await m_InkManager.SaveAsync(writeStream);
await writeStream.FlushAsync();
var reader = new DataReader(writeStream.GetInputStreamAt(0));
bytes = new byte[writeStream.Size];
await reader.LoadAsync((uint)writeStream.Size);
reader.ReadBytes(bytes);
reader.DetachStream();
await tempFile.DeleteAsync();
}
return bytes;
}
public async Task<BitmapImage> GetBitmapImage()
{
var bitmapImage = new BitmapImage();
var bytes = await GetBytes();
if (bytes.Length > 0)
{
using (var stream = new InMemoryRandomAccessStream())
{
// For AsBuffer manually add [ using System.Runtime.InteropServices.WindowsRuntime ];
await stream.WriteAsync(bytes.AsBuffer());
stream.Seek(0);
bitmapImage.SetSource(stream);
}
}
return bitmapImage;
}
#region Pointer Event Handlers
public void OnCanvasPointerReleased(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == m_PenId)
{
Windows.UI.Input.PointerPoint pt = e.GetCurrentPoint(this);
// Pass the pointer information to the InkManager.
m_InkManager.ProcessPointerUp(pt);
}
else if (e.Pointer.PointerId == _touchID)
{
// Process touch input
}
_touchID = 0;
m_PenId = 0;
e.Handled = true;
}
private void OnCanvasPointerMoved(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == m_PenId)
{
PointerPoint pt = e.GetCurrentPoint(this);
// Render a red line on the canvas as the pointer moves.
// Distance() is an application-defined function that tests
// whether the pointer has moved far enough to justify
// drawing a new line.
currentContactPt = pt.Position;
x1 = _previousContactPt.X;
y1 = _previousContactPt.Y;
x2 = currentContactPt.X;
y2 = currentContactPt.Y;
var color = m_CurrentDrawingColor;
var size = m_CurrentDrawingSize;
if (Distance(x1, y1, x2, y2) > 2.0)
{
Line line = new Line()
{
X1 = x1,
Y1 = y1,
X2 = x2,
Y2 = y2,
StrokeThickness = size,
Stroke = new SolidColorBrush(color)
};
_previousContactPt = currentContactPt;
// Draw the line on the canvas by adding the Line object as
// a child of the Canvas object.
this.Children.Add(line);
}
// Pass the pointer information to the InkManager.
m_InkManager.ProcessPointerUpdate(pt);
}
else if (e.Pointer.PointerId == _touchID)
{
// Process touch input
}
}
private double Distance(double x1, double y1, double x2, double y2)
{
double d = 0;
d = Math.Sqrt(Math.Pow((x2 - x1), 2) + Math.Pow((y2 - y1), 2));
return d;
}
public void OnCanvasPointerPressed(object sender, PointerRoutedEventArgs e)
{
// Get information about the pointer location.
PointerPoint pt = e.GetCurrentPoint(this);
_previousContactPt = pt.Position;
// Accept input only from a pen or mouse with the left button pressed.
PointerDeviceType pointerDevType = e.Pointer.PointerDeviceType;
if (pointerDevType == PointerDeviceType.Pen ||
pointerDevType == PointerDeviceType.Mouse &&
pt.Properties.IsLeftButtonPressed)
{
// Pass the pointer information to the InkManager.
m_InkManager.ProcessPointerDown(pt);
m_PenId = pt.PointerId;
e.Handled = true;
}
else if (pointerDevType == PointerDeviceType.Touch)
{
// Process touch input
}
}
#endregion
#region Mode Functions
// Change the color and width in the default (used for new strokes) to the values
// currently set in the current context.
private void SetDefaults(double strokeSize, Color color)
{
var newDrawingAttributes = new InkDrawingAttributes();
newDrawingAttributes.Size = new Size(strokeSize, strokeSize);
newDrawingAttributes.Color = color;
newDrawingAttributes.FitToCurve = true;
m_InkManager.SetDefaultDrawingAttributes(newDrawingAttributes);
this.Background = new SolidColorBrush(Colors.White);
}
#endregion
}
}
You use the InkManager class in WinRT instead of WPF's InkCanvas. I think you might need to use your own Canvas control with some Shapes (Polyline?) and handle the Pointer~ events yourself, but I haven't done it myself so I can't say for sure.
Related
I have use WCF Services in an app.
I draw the line when going from 1 lists the coordinates returned from WCF. Then draw the wrong path. While Windows Phone 7 displays properly, using Polyline.
Shown below are the results that I got wrong:
And I want to display:
This is the code that I handle to draw:
void wcl_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
try
{
if (string.IsNullOrEmpty(e.Result) || e.Error != null)
{
MessageBox.Show("Lỗi kết nối! Hãy thử lại");
waitingPage.Visibility = System.Windows.Visibility.Collapsed;
return;
}
XuLyToaDo route = XuLyToaDo.TaoMapRoute();
//Lay ds diem ve
string Ketqua = XuLyToaDo.DanhSachDiemVe(e.Result);
string[] kq = Ketqua.Split('&');
//Lay thong tin toa do
XuLyToaDo routePushpin = XuLyToaDo.TaoMapRoute();
XuLyToaDo routePolyline = XuLyToaDo.TaoMapRoute();
//MessageBox.Show(kq[0]);
//MessageBox.Show(kq[1]);
//MessageBox.Show(kq[2]);
//Tao ds toa do
List<GeoCoordinate> lsToaDoPushpin = routePushpin.TaoDSToaDo(kq[0]);
List<GeoCoordinate> lsToaDoRoute = routePushpin.TaoDSToaDo(kq[1]);
// Lay ds ten duong
string[] MangTenDiaChi = routePushpin.TaoDSDuong(kq[2]);
if (lsToaDoPushpin == null)
{
MessageBox.Show("Không có thông tin");
waitingPage.Visibility = System.Windows.Visibility.Collapsed;
return;
}
for (int i = 0; i < lsToaDoPushpin.Count - 1; i++)
{
AddRoute(lsToaDoPushpin[i], Colors.Blue);
}
//ve duong di
for (int i = 0; i < lsToaDoPushpin.Count - 2; i++)
{
AddRouteMap(lsToaDoPushpin[i], lsToaDoPushpin[i + 1]);
}
//ve duong di
//MyRouteQuery = new RouteQuery()
//{
// TravelMode = TravelMode.Driving,
// Waypoints = lsToaDoRoute
//};
//MyRouteQuery.QueryCompleted += MyRouteQuery_QueryCompleted;
//MyRouteQuery.QueryAsync();
//Them danh sach tram
int k = 0;
foreach (GeoCoordinate geo in lsToaDoPushpin)
{
if (k == lsToaDoPushpin.Count() - 1)
break;
Pushpin pus = new Pushpin();
string str = "Direc_" + k;
pus.Template = Maps.App.Current.Resources[str] as ControlTemplate;
pus.Tag = k;
pus.Content = k.ToString() + ". " + MangTenDiaChi[k];
pus.Tap += new EventHandler<System.Windows.Input.GestureEventArgs>(pus_Tap);
MyMap.Layers.Add(new MapLayer()
{
new MapOverlay()
{
GeoCoordinate = geo,
PositionOrigin = new Point(0.5,0.5),
Content = pus
}
});
k++;
}
MyMap.Center = lsToaDoPushpin[0];
MyMap.ZoomLevel = 15;
waitingPage.Visibility = System.Windows.Visibility.Collapsed;
}
catch (Exception ex)
{
MessageBox.Show("Lỗi kết nối. Hãy thử lại!!" + ex.Message);
}
}
private void AddRouteMap(GeoCoordinate g1, GeoCoordinate g2)
{
List<GeoCoordinate> lsRoute = new List<GeoCoordinate>();
lsRoute.Add(g1);
lsRoute.Add(g2);
MyRouteQuery = new RouteQuery()
{
TravelMode = TravelMode.Walking,
Waypoints = lsRoute
};
MyRouteQuery.QueryCompleted += MyRouteQuery_QueryCompleted;
MyRouteQuery.QueryAsync();
}
void MyRouteQuery_QueryCompleted(object sender, QueryCompletedEventArgs<Route> e)
{
if (e.Error == null)
{
if (MyMapRoute != null)
AddlstMapRoute(MyMapRoute);
MyRoute = e.Result;
MyMapRoute = new MapRoute(MyRoute);
MyMap.AddRoute(MyMapRoute);
}
}
private void AddlstMapRoute(MapRoute maproute)
{
lsMapRoute.Add(maproute);
}
private void AddRoute(GeoCoordinate geo, Color color)
{
MyMap.Layers.Add(new MapLayer()
{
new MapOverlay()
{
GeoCoordinate = geo,
PositionOrigin = new Point(0.5,0.5),
Content = new Ellipse
{
Fill = new SolidColorBrush(color),
Width =5,
Height = 5
}
}
});
}
void pus_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
e.Handled = true;
Pushpin pus = sender as Pushpin;
ToolTipService.SetToolTip(pus, new ToolTip()
{
DataContext = pus,
Style = Application.Current.Resources["CustomInfoboxStyle"] as Style
});
MessageBox.Show(pus.Content.ToString(), "Thông tin trạm", MessageBoxButton.OK);
}
This is the place where I create database:
How can I fix this?
i guess its due to the fact that your travelmode is set to walking and google seems to think that walking there isnt allowed, so it takes the next possible way. try change the travelmode to driving or so.
greetings lars
I'm new to coding in AS3, and I would like some assistance. I've recieved a task where I have to code a Multiplication table (10 rows, 10 columns). I've managed to code the table, but I need help to add the numbers needed without manually adding the text.
It should look somewhat like this;
Can someone here assist me with this task?
Here is my code:
var xColumns:uint=10;
var xRows:uint=10;
var _columnWidth:Number=40;
var _rowHeight:Number=40
var _width:Number=_columnWidth*xColumns;
var _height:Number=_rowHeight*xRows;
graphics.lineStyle(2, 0x0000ff, 1);
for(var i:int=1; i<=xColumns; i++){
graphics.moveTo(i*_columnWidth,0);
graphics.lineTo(i*_columnWidth,_height);
}
for(i=1; i<=xRows; i++){
graphics.moveTo(0,i*_rowHeight);
graphics.lineTo(_width,i*_rowHeight);
}
This is the sample of "Cell" class:
package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
public class Cell extends Sprite
{
//---------------------------------------
protected var m_oLabel:TextField;
protected var m_nWidth:Number = 20;
protected var m_nHeight:Number = 20;
protected var _backgroundColor:Number;
//---------------------------------------
//Group: CONSTRUCTOR
public function Cell()
{
super();
m_oLabel = new TextField();
m_oLabel.text = "999";
m_oLabel.autoSize = TextFieldAutoSize.CENTER;
addChild(m_oLabel);
setLabel("999");
}
//--------------------------------------------------//
// PUBLIC PUBLIC PUBLIC PUBLIC //
//--------------------------------------------------//
public function setLabel(p_sLabel:String):void
{
m_oLabel.text = p_sLabel || "";
updateLayout();
}
public function get backgroundColor():Number
{
return _backgroundColor;
}
public function set backgroundColor(value:Number):void
{
_backgroundColor = value;
redraw();
}
//------------------- OVERRIDDEN -------------------//
override public function get width():Number
{
return m_nWidth;
}
override public function set width(value:Number):void
{
m_nWidth = value;
updateLayout();
redraw();
}
override public function get height():Number
{
return m_nHeight;
}
override public function set height(value:Number):void
{
m_nHeight = value;
updateLayout();
redraw();
}
//--------------------------------------------------//
// PRIVATE/PROTECTED PRIVATE/PROTECTED //
//--------------------------------------------------//
protected function updateLayout():void
{
//adjust layout
if (m_oLabel)
{
m_oLabel.x = width * .5 - m_oLabel.width * .5;
m_oLabel.y = height * .5 - m_oLabel.height * .5;
}
}
protected function redraw():void
{
var g:Graphics = this.graphics;
g.beginFill(_backgroundColor);
g.drawRect(0, 0, width, height);
g.endFill();
}
//------------------- OVERRIDDEN -------------------//
//--------------------------------------------------//
// EVENTS EVENTS EVENTS EVENTS //
//--------------------------------------------------//
//------------------- OVERRIDDEN -------------------//
//--------------------------------------------------//
// UTILS UTILS UTILS UTILS //
//--------------------------------------------------//
//------------------- OVERRIDDEN -------------------//
}
}
and usage:
var container:Sprite = new Sprite();
addChild(container);
container.x = 10;
container.y = 10;
for (var i:int = 0; i <= 10; i++)
{
for (var j:int = 0; j <= 10; j++)
{
var cell:Cell = new Cell();
if (i == 0 || j == 0)
{
//headers
cell.setLabel(Math.max(i, j).toString());
cell.backgroundColor = 0x808080;
}
else
{
var mul:Number = i * j;
cell.setLabel(mul.toString());
cell.backgroundColor = 0xC0C0C0;
}
container.addChild(cell);
cell.x = cell.width * j;
cell.y = cell.height * i;
}
}
which looks like this:
new class "Cell" gives you flexibility and encapsulation of code for creation of single table cell. In my example it is only container for textfield and has ability to draw background. I've created public methods/accessors that allow to modify the "features" of the cell (i.e. what is displayed in TextField and what is colour of background). I had to override default width/height behaviour as otherwise it would return the size of it's content which would vary depending on the TextField content and size and in table we need steady size.
I try to write function that will be resize images. I use WriteableBitmapEx for WinRT/Win8 function Resize();
public class PictureExtension
{
private MemoryRandomAccessStream _memoryRandomAccessStream;
private readonly Stream _dataStream;
private readonly double _height;
private readonly double _width;
public PictureExtension(Stream dataStream, double height, double width)
{
_dataStream = dataStream;
_memoryRandomAccessStream = (_dataStream.ToRandomAccessStream());
_height = height;
_width = width;
}
public byte[] ToArray(double maxSide)
{
if (_height <= maxSide && _width <= maxSide)
{
return _dataStream.ToArray();
}
else
{
var target = new WriteableBitmap((int) _width, (int) _height);
var aspectRatio = (double)_width / _height;
double newHeight;
double newWidth;
if (_width > _height)
{
newWidth = maxSide;
newHeight = newWidth / aspectRatio;
}
else
{
newHeight = maxSide;
newWidth = maxSide * aspectRatio;
}
int count = (int)_dataStream.Length;
using (var bmpStream = target.PixelBuffer.AsStream())
{
bmpStream.Seek(0, SeekOrigin.Begin);
bmpStream.Write(_dataStream.ToArray(), 0, _dataStream.ToArray().Length);
}
var resized = target.Resize((int)newWidth, (int)newHeight, WriteableBitmapExtensions.Interpolation.Bilinear);
return resized.ToByteArray();
}
}
}
}
This function return array of byte but it is not image any more.. I tested with PNG and JPG formats.. What's wrong?
I've been examining this problem before, try the code in this thread:
How to resize Image in C# WinRT/winmd?
The best help would be if you follow your post at the CodePlex site ;) http://writeablebitmapex.codeplex.com/discussions/399624
No need for cross posting.
Not sure if that would help you, but there is a LoadAsync() overload I wrote load a bitmap at the given decode resolution which might help you depending on your scenario.
http://winrtxamltoolkit.codeplex.com/SourceControl/changeset/view/0657c67a93d5#WinRTXamlToolkit%2fImaging%2fWriteableBitmapLoadExtensions.cs
This code plots an XYChart and using combination of right mouse button click and drag perform free hand draw, while with left mouse button click and drag perform Zoom In on selected area.
My problem is about zoom on freehand draw it always get translated. For example try to draw somewhere around a corner.
How can I solve this?
public class Zoom extends Application {
Path path;//Add path for freehand
BorderPane pane;
Rectangle rect;
SimpleDoubleProperty rectinitX = new SimpleDoubleProperty();
SimpleDoubleProperty rectinitY = new SimpleDoubleProperty();
SimpleDoubleProperty rectX = new SimpleDoubleProperty();
SimpleDoubleProperty rectY = new SimpleDoubleProperty();
double initXLowerBound = 0, initXUpperBound = 0, initYLowerBound = 0, initYUpperBound = 0;
#Override
public void start(Stage stage) {
stage.setTitle("Lines plot");
final NumberAxis xAxis = new NumberAxis(1, 12, 1);
final NumberAxis yAxis = new NumberAxis(0.53000, 0.53910, 0.0005);
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
#Override
public String toString(Number object) {
return String.format("%7.5f", object);
}
});
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
lineChart.setCreateSymbols(false);
lineChart.setAlternativeRowFillVisible(false);
lineChart.setAnimated(true);
XYChart.Series series1 = new XYChart.Series();
series1.getData().add(new XYChart.Data(1, 0.53185));
series1.getData().add(new XYChart.Data(2, 0.532235));
series1.getData().add(new XYChart.Data(3, 0.53234));
series1.getData().add(new XYChart.Data(4, 0.538765));
series1.getData().add(new XYChart.Data(5, 0.53442));
series1.getData().add(new XYChart.Data(6, 0.534658));
series1.getData().add(new XYChart.Data(7, 0.53023));
series1.getData().add(new XYChart.Data(8, 0.53001));
series1.getData().add(new XYChart.Data(9, 0.53589));
series1.getData().add(new XYChart.Data(10, 0.53476));
series1.getData().add(new XYChart.Data(11, 0.530123));
series1.getData().add(new XYChart.Data(12, 0.53035));
pane = new BorderPane();
pane.setCenter(lineChart);
Scene scene = new Scene(pane, 800, 600);
lineChart.getData().addAll(series1);
initXLowerBound = ((NumberAxis) lineChart.getXAxis()).getLowerBound();
initXUpperBound = ((NumberAxis) lineChart.getXAxis()).getUpperBound();
initYLowerBound = ((NumberAxis) lineChart.getYAxis()).getLowerBound();
initYUpperBound = ((NumberAxis) lineChart.getYAxis()).getUpperBound();
stage.setScene(scene);
path = new Path();
path.setStrokeWidth(1);
path.setStroke(Color.BLACK);
scene.setOnMouseClicked(mouseHandler);
scene.setOnMouseDragged(mouseHandler);
scene.setOnMouseEntered(mouseHandler);
scene.setOnMouseExited(mouseHandler);
scene.setOnMouseMoved(mouseHandler);
scene.setOnMousePressed(mouseHandler);
scene.setOnMouseReleased(mouseHandler);
pane.getChildren().add(path);
rect = new Rectangle();
rect.setFill(Color.web("blue", 0.1));
rect.setStroke(Color.BLUE);
rect.setStrokeDashOffset(50);
rect.widthProperty().bind(rectX.subtract(rectinitX));
rect.heightProperty().bind(rectY.subtract(rectinitY));
pane.getChildren().add(rect);
stage.show();
}
EventHandler<MouseEvent> mouseHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (mouseEvent.getButton() == MouseButton.PRIMARY)
{
if (mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED) {
rect.setX(mouseEvent.getX());
rect.setY(mouseEvent.getY());
rectinitX.set(mouseEvent.getX());
rectinitY.set(mouseEvent.getY());
} else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) {
rectX.set(mouseEvent.getX());
rectY.set(mouseEvent.getY());
} else if (mouseEvent.getEventType() == MouseEvent.MOUSE_RELEASED) {
if ((rectinitX.get() >= rectX.get())&&(rectinitY.get() >= rectY.get()))
{
LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter();
((NumberAxis) lineChart.getXAxis()).setLowerBound(initXLowerBound);
((NumberAxis) lineChart.getXAxis()).setUpperBound(initXUpperBound);
((NumberAxis) lineChart.getYAxis()).setLowerBound(initYLowerBound);
((NumberAxis) lineChart.getYAxis()).setUpperBound(initYUpperBound);
ZoomFreeHand(path, 1.0, 1.0, 0, 0);
}
else
{
//Zoom In
double Tgap = 0;
double newLowerBound, newUpperBound, axisShift;
double xScaleFactor, yScaleFactor;
double xaxisShift, yaxisShift;
LineChart<Number, Number> lineChart = (LineChart<Number, Number>) pane.getCenter();
// Zoom in Y-axis by changing bound range.
NumberAxis yAxis = (NumberAxis) lineChart.getYAxis();
Tgap = yAxis.getHeight()/(yAxis.getUpperBound() - yAxis.getLowerBound());
axisShift = getSceneShiftY(yAxis);
yaxisShift = axisShift;
newUpperBound = yAxis.getUpperBound() - ((rectinitY.get() - axisShift) / Tgap);
newLowerBound = yAxis.getUpperBound() - (( rectY.get() - axisShift) / Tgap);
if (newUpperBound > yAxis.getUpperBound())
newUpperBound = yAxis.getUpperBound();
yScaleFactor = (yAxis.getUpperBound() - yAxis.getLowerBound())/(newUpperBound - newLowerBound);
yAxis.setLowerBound(newLowerBound);
yAxis.setUpperBound(newUpperBound);
NumberAxis xAxis = (NumberAxis) lineChart.getXAxis();
Tgap = xAxis.getWidth()/(xAxis.getUpperBound() - xAxis.getLowerBound());
axisShift = getSceneShiftX(xAxis);
xaxisShift = axisShift;
newLowerBound = ((rectinitX.get() - axisShift) / Tgap) + xAxis.getLowerBound();
newUpperBound = ((rectX.get() - axisShift) / Tgap) + xAxis.getLowerBound();
if (newUpperBound > xAxis.getUpperBound())
newUpperBound = xAxis.getUpperBound();
xScaleFactor = (xAxis.getUpperBound() - xAxis.getLowerBound())/(newUpperBound - newLowerBound);
xAxis.setLowerBound( newLowerBound );
xAxis.setUpperBound( newUpperBound );
ZoomFreeHand(path, xScaleFactor, yScaleFactor, xaxisShift, yaxisShift);
}
// Hide the rectangle
rectX.set(0);
rectY.set(0);
}
}
else if (mouseEvent.getButton() == MouseButton.SECONDARY) //free hand graphics
{
if(mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED){
path.getElements().clear();
path.getElements().add(new MoveTo(mouseEvent.getX(), mouseEvent.getY()));
}
else if(mouseEvent.getEventType()==MouseEvent.MOUSE_DRAGGED){
path.getElements().add(new LineTo(mouseEvent.getX(), mouseEvent.getY()));
}
}
}
};
private static double getSceneShiftX(Node node) {
double shift = 0;
do {
shift += node.getLayoutX();
node = node.getParent();
} while (node != null);
return shift;
}
private static double getSceneShiftY(Node node) {
double shift = 0;
do {
shift += node.getLayoutY();
node = node.getParent();
} while (node != null);
return shift;
}
private static void ZoomFreeHand(Path path, double xScaleFactor, double yScaleFactor, double xaxisShift, double yaxisShift) {
double layX, layY;
layX = path.getLayoutX();
layY = path.getLayoutY();
path.setScaleX(xScaleFactor);
path.setScaleY(yScaleFactor);
path.setTranslateX(xaxisShift);
path.setTranslateY(yaxisShift);
}
public static void main(String[] args) {
launch(args);
}
}
I think it worth using something like this:
ObservableList<PathElement> mypathElements = path.getElements();
for (int i = 0; i < mypathElements.size(); i++) {
final PathElement element = mypathElements.get(i);
if (element instanceof MoveTo) {
final MoveTo move = (MoveTo)element;
//change move coordinates
} else if (element instanceof LineTo) {
final LineTo line = (LineTo)element;
//change line coordinates
}
}
Same issue as in Javafx 2 chart resize with freehand draw and same answer:
It seems you coordinates are based on wrong anchors. You need to find a node which contains graph itself and work only with this node's coordinates, not axis or scene.
I would even advise to add all mouse events to that node instead of scene to avoid excessive coordinates translation.
Another advise would be use ScenicView tool to investigate your application and see which nodes has what coordinates and verify your math.
I'd recommend replace those:
private static double getSceneShiftX(Node node) {
double shift = 0;
do {
shift += node.getLayoutX();
node = node.getParent();
} while (node != null);
return shift;
}
private static double getSceneShiftY(Node node) {
double shift = 0;
do {
shift += node.getLayoutY();
node = node.getParent();
} while (node != null);
return shift;
}
with Node.localToScene, Node.sceneToLocal conversion methods that took points or Bounds as arguments.
I started playing around with Dart yesterday and thought I would try to make a simple game engine. I'm also new to the canvas element , so I'm sure I'm making a silly mistake somewhere.
Here is my main game loop.
class FunTime {
FunTime(){
gameTime = new Date.now();
gameState = new List<IDrawableGameComponent>();
StartMenu startMenu = new StartMenu();
gameState.add(startMenu);
CanvasElement _canvas = document.query('#canvas');
context = _canvas.getContext('2d');
}
List<IDrawableGameComponent> gameState;
Date gameTime;
CanvasRenderingContext2D context;
}
void main() {
var exit = false;
FunTime game = new FunTime();
Date previousDraw = new Date.now();
while (!exit){
game.gameTime = new Date.now();
//update
game.gameState.last().update(game.gameTime);
int elapsed = game.gameTime.difference(previousDraw).inMilliseconds;
//draw (60 fps)
if(previousDraw == null || elapsed > 16){
//print("Draw Called{$elapsed}");
previousDraw = game.gameTime;
game.gameState.last().draw(game.gameTime, game.context);
}
}
}
Here is the code for the StartMenu code:
class StartMenu implements IDrawableGameComponent{
num positionX = 0;
StartMenu(){
}
void load(){
}
void update(Date gameTime){
//if(positionX < 200)
// positionX++;
}
void draw(Date gameTime, CanvasRenderingContext2D ctx){
ctx.clearRect(0, 0, 800, 600);
ctx.fillStyle = 'black';
ctx.fillRect(0,0,800,600);
ctx.fillStyle = 'white';
ctx.fillRect(positionX, 50, 400, 200);
}
}
For some reason the rectangles are never drawn unless I step through the code. Its almost like the brwoser doesn't have enough time to draw it before the next clear is called. I've tried increasing the draw interval but it doesn't change anything.
Here is how I solved the problem:
class FunTime {
FunTime(){
gameTime = new Date.now();
gameState = new List<IDrawableGameComponent>();
StartMenu startMenu = new StartMenu();
gameState.add(startMenu);
canvas = document.query('#canvas');
context = canvas.getContext('2d');
_previousDraw = 0;
animate(0);
}
animate(int time){
int elapsed = time - _previousDraw;
if( _previousDraw == 0 || elapsed > 16){
this.gameState.last().draw(time, this.context);
_previousDraw = time;
}
this.gameState.last().update(time);
window.webkitRequestAnimationFrame(animate, this.canvas);
}
int _previousDraw;
List<IDrawableGameComponent> gameState;
Date gameTime;
CanvasRenderingContext2D context;
CanvasElement canvas;
}
void main() {
FunTime game = new FunTime();
}
The while loop in the main() method never returns to let the browser thread draw. This is why it only works when you step through it.
This alternative works: using window.setInterval, to call a function every 16ms, but it may not be the correct way for a game loop.
void main() {
var exit = false;
FunTime game = new FunTime();
Date previousDraw = new Date.now();
window.setInterval( () { //note the callback
game.gameTime = new Date.now();
//update
game.gameState.last().update(game.gameTime);
int elapsed = game.gameTime.difference(previousDraw).inMilliseconds;
//draw (60 fps)
if(previousDraw == null || elapsed > 16){
previousDraw = game.gameTime;
game.gameState.last().draw(game.gameTime, game.context);
}
}, 16); //16 ms
}