├── .gitignore ├── LICENSE ├── Preview ├── gradient.png ├── multi.PNG ├── schema.png ├── single.png └── stack.png ├── README.md ├── RealTimeGraphX.UWP.Demo ├── App.xaml ├── App.xaml.cs ├── Assets │ ├── LockScreenLogo.scale-200.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ └── Wide310x150Logo.scale-200.png ├── Converters │ ├── DataPointToStringConverter.cs │ └── TimeSpanToStringConverter.cs ├── MainPage.xaml ├── MainPage.xaml.cs ├── MainPageVM.cs ├── NamedBrush.cs ├── NamedColor.cs ├── Package.appxmanifest ├── Properties │ ├── AssemblyInfo.cs │ └── Default.rd.xml ├── RealTimeGraphX.UWP.Demo.csproj ├── Themes │ └── Generic.xaml └── UwpGraphControl.cs ├── RealTimeGraphX.UWP ├── ExtensionMethods.cs ├── Properties │ ├── AssemblyInfo.cs │ └── RealTimeGraphX.UWP.rd.xml ├── RealTimeGraphX.UWP.csproj ├── RealTimeGraphX.UWP.nuspec ├── Themes │ └── Generic.xaml ├── UwpBindingElement.cs ├── UwpDataTriggerAction.cs ├── UwpDataTriggerElement.cs ├── UwpGraphAxisControl.cs ├── UwpGraphAxisPanel.cs ├── UwpGraphAxisTickData.cs ├── UwpGraphComponentBase.cs ├── UwpGraphController.cs ├── UwpGraphDataSeries.cs ├── UwpGraphGridLines.cs ├── UwpGraphSurface.cs └── icon.png ├── RealTimeGraphX.WPF.Demo ├── App.config ├── App.xaml ├── App.xaml.cs ├── Converters │ └── ObjectEqualityConverter.cs ├── ListGraphItemVM.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MainWindowVM.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── RealTimeGraphX.WPF.Demo.csproj ├── Themes │ └── Generic.xaml └── WpfGraphControl.cs ├── RealTimeGraphX.WPF ├── ExtensionMethods.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── RealTimeGraphX.WPF.csproj ├── RealTimeGraphX.WPF.nuspec ├── Themes │ └── Generic.xaml ├── WpfGraphAxisControl.cs ├── WpfGraphAxisPanel.cs ├── WpfGraphAxisTickData.cs ├── WpfGraphComponentBase.cs ├── WpfGraphController.cs ├── WpfGraphDataSeries.cs ├── WpfGraphGridLines.cs ├── WpfGraphSurface.cs └── icon.png ├── RealTimeGraphX.sln ├── RealTimeGraphX ├── DataPoints │ ├── DateTimeDataPoint.cs │ ├── DoubleDataPoint.cs │ ├── FloatDataPoint.cs │ ├── Int32DataPoint.cs │ └── TimeSpanDataPoint.cs ├── EventArguments │ └── RangeChangedEventArgs.cs ├── GraphCommand.cs ├── GraphController.cs ├── GraphDataPoint.cs ├── GraphDataPointHelper.cs ├── GraphDataPointTypeConverter.cs ├── GraphDataQueue.cs ├── GraphObject.cs ├── GraphRange.cs ├── GraphRangeAutoYFallBackMode.cs ├── GraphRenderer.cs ├── GraphTransform.cs ├── IGraphComponent.cs ├── IGraphController.cs ├── IGraphDataPoint.cs ├── IGraphDataSeries.cs ├── IGraphRenderer.cs ├── IGraphSurface.cs ├── RealTimeGraphX.csproj └── Renderers │ └── ScrollingLineRenderer.cs └── visuals └── icon.png /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015/2017 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # Visual Studio 2017 auto generated files 33 | Generated\ Files/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # Benchmark Results 49 | BenchmarkDotNet.Artifacts/ 50 | 51 | # .NET Core 52 | project.lock.json 53 | project.fragment.lock.json 54 | artifacts/ 55 | **/Properties/launchSettings.json 56 | 57 | # StyleCop 58 | StyleCopReport.xml 59 | 60 | # Files built by Visual Studio 61 | *_i.c 62 | *_p.c 63 | *_i.h 64 | *.ilk 65 | *.meta 66 | *.obj 67 | *.iobj 68 | *.pch 69 | *.pdb 70 | *.ipdb 71 | *.pgc 72 | *.pgd 73 | *.rsp 74 | *.sbr 75 | *.tlb 76 | *.tli 77 | *.tlh 78 | *.tmp 79 | *.tmp_proj 80 | *.log 81 | *.vspscc 82 | *.vssscc 83 | .builds 84 | *.pidb 85 | *.svclog 86 | *.scc 87 | 88 | # Chutzpah Test files 89 | _Chutzpah* 90 | 91 | # Visual C++ cache files 92 | ipch/ 93 | *.aps 94 | *.ncb 95 | *.opendb 96 | *.opensdf 97 | *.sdf 98 | *.cachefile 99 | *.VC.db 100 | *.VC.VC.opendb 101 | 102 | # Visual Studio profiler 103 | *.psess 104 | *.vsp 105 | *.vspx 106 | *.sap 107 | 108 | # Visual Studio Trace Files 109 | *.e2e 110 | 111 | # TFS 2012 Local Workspace 112 | $tf/ 113 | 114 | # Guidance Automation Toolkit 115 | *.gpState 116 | 117 | # ReSharper is a .NET coding add-in 118 | _ReSharper*/ 119 | *.[Rr]e[Ss]harper 120 | *.DotSettings.user 121 | 122 | # JustCode is a .NET coding add-in 123 | .JustCode 124 | 125 | # TeamCity is a build add-in 126 | _TeamCity* 127 | 128 | # DotCover is a Code Coverage Tool 129 | *.dotCover 130 | 131 | # AxoCover is a Code Coverage Tool 132 | .axoCover/* 133 | !.axoCover/settings.json 134 | 135 | # Visual Studio code coverage results 136 | *.coverage 137 | *.coveragexml 138 | 139 | # NCrunch 140 | _NCrunch_* 141 | .*crunch*.local.xml 142 | nCrunchTemp_* 143 | 144 | # MightyMoose 145 | *.mm.* 146 | AutoTest.Net/ 147 | 148 | # Web workbench (sass) 149 | .sass-cache/ 150 | 151 | # Installshield output folder 152 | [Ee]xpress/ 153 | 154 | # DocProject is a documentation generator add-in 155 | DocProject/buildhelp/ 156 | DocProject/Help/*.HxT 157 | DocProject/Help/*.HxC 158 | DocProject/Help/*.hhc 159 | DocProject/Help/*.hhk 160 | DocProject/Help/*.hhp 161 | DocProject/Help/Html2 162 | DocProject/Help/html 163 | 164 | # Click-Once directory 165 | publish/ 166 | 167 | # Publish Web Output 168 | *.[Pp]ublish.xml 169 | *.azurePubxml 170 | # Note: Comment the next line if you want to checkin your web deploy settings, 171 | # but database connection strings (with potential passwords) will be unencrypted 172 | *.pubxml 173 | *.publishproj 174 | 175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 176 | # checkin your Azure Web App publish settings, but sensitive information contained 177 | # in these scripts will be unencrypted 178 | PublishScripts/ 179 | 180 | # NuGet Packages 181 | *.nupkg 182 | # The packages folder can be ignored because of Package Restore 183 | **/[Pp]ackages/* 184 | # except build/, which is used as an MSBuild target. 185 | !**/[Pp]ackages/build/ 186 | # Uncomment if necessary however generally it will be regenerated when needed 187 | #!**/[Pp]ackages/repositories.config 188 | # NuGet v3's project.json files produces more ignorable files 189 | *.nuget.props 190 | *.nuget.targets 191 | 192 | # Microsoft Azure Build Output 193 | csx/ 194 | *.build.csdef 195 | 196 | # Microsoft Azure Emulator 197 | ecf/ 198 | rcf/ 199 | 200 | # Windows Store app package directories and files 201 | AppPackages/ 202 | BundleArtifacts/ 203 | Package.StoreAssociation.xml 204 | _pkginfo.txt 205 | *.appx 206 | 207 | # Visual Studio cache files 208 | # files ending in .cache can be ignored 209 | *.[Cc]ache 210 | # but keep track of directories ending in .cache 211 | !*.[Cc]ache/ 212 | 213 | # Others 214 | ClientBin/ 215 | ~$* 216 | *~ 217 | *.dbmdl 218 | *.dbproj.schemaview 219 | *.jfm 220 | *.pfx 221 | *.publishsettings 222 | orleans.codegen.cs 223 | 224 | # Including strong name files can present a security risk 225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 226 | #*.snk 227 | 228 | # Since there are multiple workflows, uncomment next line to ignore bower_components 229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 230 | #bower_components/ 231 | 232 | # RIA/Silverlight projects 233 | Generated_Code/ 234 | 235 | # Backup & report files from converting an old project file 236 | # to a newer Visual Studio version. Backup files are not needed, 237 | # because we have git ;-) 238 | _UpgradeReport_Files/ 239 | Backup*/ 240 | UpgradeLog*.XML 241 | UpgradeLog*.htm 242 | ServiceFabricBackup/ 243 | *.rptproj.bak 244 | 245 | # SQL Server files 246 | *.mdf 247 | *.ldf 248 | *.ndf 249 | 250 | # Business Intelligence projects 251 | *.rdl.data 252 | *.bim.layout 253 | *.bim_*.settings 254 | *.rptproj.rsuser 255 | 256 | # Microsoft Fakes 257 | FakesAssemblies/ 258 | 259 | # GhostDoc plugin setting file 260 | *.GhostDoc.xml 261 | 262 | # Node.js Tools for Visual Studio 263 | .ntvs_analysis.dat 264 | node_modules/ 265 | 266 | # Visual Studio 6 build log 267 | *.plg 268 | 269 | # Visual Studio 6 workspace options file 270 | *.opt 271 | 272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 273 | *.vbw 274 | 275 | # Visual Studio LightSwitch build output 276 | **/*.HTMLClient/GeneratedArtifacts 277 | **/*.DesktopClient/GeneratedArtifacts 278 | **/*.DesktopClient/ModelManifest.xml 279 | **/*.Server/GeneratedArtifacts 280 | **/*.Server/ModelManifest.xml 281 | _Pvt_Extensions 282 | 283 | # Paket dependency manager 284 | .paket/paket.exe 285 | paket-files/ 286 | 287 | # FAKE - F# Make 288 | .fake/ 289 | 290 | # JetBrains Rider 291 | .idea/ 292 | *.sln.iml 293 | 294 | # CodeRush 295 | .cr/ 296 | 297 | # Python Tools for Visual Studio (PTVS) 298 | __pycache__/ 299 | *.pyc 300 | 301 | # Cake - Uncomment if you are using it 302 | # tools/** 303 | # !tools/packages.config 304 | 305 | # Tabs Studio 306 | *.tss 307 | 308 | # Telerik's JustMock configuration file 309 | *.jmconfig 310 | 311 | # BizTalk build output 312 | *.btp.cs 313 | *.btm.cs 314 | *.odx.cs 315 | *.xsd.cs 316 | 317 | # OpenCover UI analysis results 318 | OpenCover/ 319 | 320 | # Azure Stream Analytics local run output 321 | ASALocalRun/ 322 | 323 | # MSBuild Binary and Structured Log 324 | *.binlog 325 | 326 | # NVidia Nsight GPU debugger configuration file 327 | *.nvuser 328 | 329 | # MFractors (Xamarin productivity tool) working folder 330 | .mfractor/ 331 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Roy Ben Shabat 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Preview/gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/Preview/gradient.png -------------------------------------------------------------------------------- /Preview/multi.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/Preview/multi.PNG -------------------------------------------------------------------------------- /Preview/schema.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/Preview/schema.png -------------------------------------------------------------------------------- /Preview/single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/Preview/single.png -------------------------------------------------------------------------------- /Preview/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/Preview/stack.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RealTimeGraphX 2 | 3 | [![Build Status](https://sirilix.visualstudio.com/RealTimeGraphX/_apis/build/status/RealTimeGraphX?branchName=master)](https://sirilix.visualstudio.com/RealTimeGraphX/_build/latest?definitionId=5&branchName=master) ![GitHub](https://img.shields.io/github/license/royben/RealTimeGraphX) [![Nuget](https://img.shields.io/nuget/v/RealTimeGraphX?label=RealTimeGraphX%20Nuget)](https://www.nuget.org/packages/RealTimeGraphX/) [![Nuget](https://img.shields.io/nuget/v/RealTimeGraphX.WPF?label=RealTimeGraphX.WPF%20Nuget)](https://www.nuget.org/packages/RealTimeGraphX.WPF/) 4 | 5 | RealTimeGraphX is a data type agnostic, high performance plotting library for WPF and UWP. 6 | 7 | The library core components are built using .Net Standard which makes it portable to a range of platforms. 8 | 9 | Typical use case is, scientific measurements applications which requires real-time display with large data volumes. 10 | 11 | RealTimeGraphX has a number of built-in data point types (axis) like Double, Float, Int32 ,TimeSpan and DateTime, but you can easily implement any kind of custom data type by inheriting and implementing the mathematical logic for that type. 12 | 13 | ### Features: 14 | - **High performance** 15 | - **Thread safe** 16 | - **MVVM support** 17 | - **Any type of data point** 18 | - **Zooming and panning** 19 | 20 |
21 |
22 |
23 | 24 | The solution contains demo projects for WPF and UWP. 25 | 26 | **Single Series** 27 | 28 | ![alt tag](https://github.com/royben/RealTimeGraphX/blob/master/Preview/single.png) 29 | 30 | **Multi Series** 31 | 32 | ![alt tag](https://github.com/royben/RealTimeGraphX/blob/master/Preview/multi.PNG) 33 | 34 | **Gradient Fill** 35 | 36 | ![alt tag](https://github.com/royben/RealTimeGraphX/blob/master/Preview/gradient.png) 37 | 38 |
39 |
40 |
41 | 42 | The follwing diagrams demonstrates the connections between graph components and how they are implemented on each platform. 43 | 44 | **Model** 45 | 46 | ![alt tag](https://github.com/royben/RealTimeGraphX/blob/master/Preview/schema.png) 47 | 48 | The graph controller binds to a renderer and a surface. Data points are pushed to the controller, the controller uses the renderer in orderer to prepare and arrange the points for visual display. Finally, the controller directs the renderer to draw the points on the specific surface. 49 | 50 | 51 | **WPF Stack Implementation** 52 | 53 | ![alt tag](https://github.com/royben/RealTimeGraphX/blob/master/Preview/stack.png) 54 | 55 | Each platform (WPF/UWP etc.) should implement it's own *IGraphDataSeries* and *IGraphSurface*. 56 | 57 |
58 |
59 |
60 | 61 |

Example

62 | 63 | ##### Model.cs 64 | 65 | ```csharp 66 | 67 | public class ViewModel 68 | { 69 | //Graph controller with timespan as X axis and double as Y. 70 | public WpfGraphController Controller { get; set; } 71 | 72 | public ViewModel() 73 | { 74 | Controller = new WpfGraphController(); 75 | Controller.Renderer = new ScrollingLineRenderer(); 76 | Controller.DataSeriesCollection.Add(new WpfGraphDataSeries() 77 | { 78 | Name = "Series Name", 79 | Stroke = Colors.Red, 80 | }); 81 | 82 | //We will attach the surface using WPF binding... 83 | //Controller.Surface = null; 84 | } 85 | 86 | private void Start() 87 | { 88 | Stopwatch watch = new Stopwatch(); 89 | watch.Start(); 90 | 91 | Thread thread = new Thread(() => 92 | { 93 | while (true) 94 | { 95 | //Get the current elapsed time and mouse position. 96 | var y = System.Windows.Forms.Cursor.Position.Y; 97 | var x = watch.Elapsed; 98 | 99 | //Push the x,y to the controller. 100 | Controller.PushData(x, y); 101 | 102 | Thread.Sleep(30); 103 | } 104 | }); 105 | thread.Start(); 106 | } 107 | } 108 | 109 | ``` 110 | 111 | ##### View.xaml 112 | 113 | ```xaml 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | ``` 135 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices.WindowsRuntime; 6 | using Windows.ApplicationModel; 7 | using Windows.ApplicationModel.Activation; 8 | using Windows.Foundation; 9 | using Windows.Foundation.Collections; 10 | using Windows.UI.ViewManagement; 11 | using Windows.UI.Xaml; 12 | using Windows.UI.Xaml.Controls; 13 | using Windows.UI.Xaml.Controls.Primitives; 14 | using Windows.UI.Xaml.Data; 15 | using Windows.UI.Xaml.Input; 16 | using Windows.UI.Xaml.Media; 17 | using Windows.UI.Xaml.Navigation; 18 | 19 | namespace RealTimeGraphX.UWP.Demo 20 | { 21 | /// 22 | /// Provides application-specific behavior to supplement the default Application class. 23 | /// 24 | sealed partial class App : Application 25 | { 26 | /// 27 | /// Initializes the singleton application object. This is the first line of authored code 28 | /// executed, and as such is the logical equivalent of main() or WinMain(). 29 | /// 30 | public App() 31 | { 32 | this.InitializeComponent(); 33 | 34 | ApplicationView.PreferredLaunchViewSize = new Size(1168, 577); 35 | ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize; 36 | 37 | this.Suspending += OnSuspending; 38 | } 39 | 40 | /// 41 | /// Invoked when the application is launched normally by the end user. Other entry points 42 | /// will be used such as when the application is launched to open a specific file. 43 | /// 44 | /// Details about the launch request and process. 45 | protected override void OnLaunched(LaunchActivatedEventArgs e) 46 | { 47 | Frame rootFrame = Window.Current.Content as Frame; 48 | 49 | // Do not repeat app initialization when the Window already has content, 50 | // just ensure that the window is active 51 | if (rootFrame == null) 52 | { 53 | // Create a Frame to act as the navigation context and navigate to the first page 54 | rootFrame = new Frame(); 55 | 56 | rootFrame.NavigationFailed += OnNavigationFailed; 57 | 58 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) 59 | { 60 | //TODO: Load state from previously suspended application 61 | } 62 | 63 | // Place the frame in the current Window 64 | Window.Current.Content = rootFrame; 65 | } 66 | 67 | if (e.PrelaunchActivated == false) 68 | { 69 | if (rootFrame.Content == null) 70 | { 71 | // When the navigation stack isn't restored navigate to the first page, 72 | // configuring the new page by passing required information as a navigation 73 | // parameter 74 | rootFrame.Navigate(typeof(MainPage), e.Arguments); 75 | } 76 | // Ensure the current window is active 77 | Window.Current.Activate(); 78 | } 79 | } 80 | 81 | /// 82 | /// Invoked when Navigation to a certain page fails 83 | /// 84 | /// The Frame which failed navigation 85 | /// Details about the navigation failure 86 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e) 87 | { 88 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName); 89 | } 90 | 91 | /// 92 | /// Invoked when application execution is being suspended. Application state is saved 93 | /// without knowing whether the application will be terminated or resumed with the contents 94 | /// of memory still intact. 95 | /// 96 | /// The source of the suspend request. 97 | /// Details about the suspend request. 98 | private void OnSuspending(object sender, SuspendingEventArgs e) 99 | { 100 | var deferral = e.SuspendingOperation.GetDeferral(); 101 | //TODO: Save application state and stop any background activity 102 | deferral.Complete(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.UWP.Demo/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.UWP.Demo/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.UWP.Demo/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.UWP.Demo/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.UWP.Demo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.UWP.Demo/Assets/StoreLogo.png -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.UWP.Demo/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Converters/DataPointToStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Windows.UI.Xaml; 8 | using Windows.UI.Xaml.Data; 9 | 10 | namespace RealTimeGraphX.UWP.Demo.Converters 11 | { 12 | public class DataPointToStringConverter : DependencyObject, IValueConverter 13 | { 14 | public object Convert(object value, Type targetType, object parameter, string language) 15 | { 16 | return value.ToString(); 17 | } 18 | 19 | public object ConvertBack(object value, Type targetType, object parameter, string language) 20 | { 21 | var asm = Assembly.Load("RealTimeGraphX"); 22 | var type = asm.GetType("RealTimeGraphX.DataPoints." + parameter.ToString()); 23 | var instance = Activator.CreateInstance(type) as IGraphDataPoint; 24 | return instance.Parse(value.ToString()); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Converters/TimeSpanToStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.UI.Xaml.Data; 7 | 8 | namespace RealTimeGraphX.UWP.Demo.Converters 9 | { 10 | public class TimeSpanToStringConverter : IValueConverter 11 | { 12 | public object Convert(object value, Type targetType, object parameter, string language) 13 | { 14 | return value.ToString(); 15 | } 16 | 17 | public object ConvertBack(object value, Type targetType, object parameter, string language) 18 | { 19 | return TimeSpan.Parse(value.ToString()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Graphics.Canvas; 2 | using Microsoft.Graphics.Canvas.Brushes; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Runtime.InteropServices.WindowsRuntime; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using Windows.Foundation; 12 | using Windows.Foundation.Collections; 13 | using Windows.UI; 14 | using Windows.UI.ViewManagement; 15 | using Windows.UI.Xaml; 16 | using Windows.UI.Xaml.Controls; 17 | using Windows.UI.Xaml.Controls.Primitives; 18 | using Windows.UI.Xaml.Data; 19 | using Windows.UI.Xaml.Input; 20 | using Windows.UI.Xaml.Media; 21 | using Windows.UI.Xaml.Navigation; 22 | 23 | // The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409 24 | 25 | namespace RealTimeGraphX.UWP.Demo 26 | { 27 | /// 28 | /// An empty page that can be used on its own or navigated to within a Frame. 29 | /// 30 | public sealed partial class MainPage : Page 31 | { 32 | public MainPage() 33 | { 34 | 35 | 36 | this.InitializeComponent(); 37 | 38 | DataContext = new MainPageVM(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/MainPageVM.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.DataPoints; 2 | using RealTimeGraphX.Renderers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using Windows.ApplicationModel.Core; 11 | using Windows.UI; 12 | using Windows.UI.Xaml.Media; 13 | 14 | namespace RealTimeGraphX.UWP.Demo 15 | { 16 | public class MainPageVM : GraphObject 17 | { 18 | public UwpGraphController Controller { get; set; } 19 | 20 | public UwpGraphController MultiController { get; set; } 21 | 22 | public MainPageVM() 23 | { 24 | Controller = new UwpGraphController(); 25 | Controller.Range.MinimumY = 0; 26 | Controller.Range.MaximumY = 1080; 27 | Controller.Range.MaximumX = TimeSpan.FromSeconds(10); 28 | Controller.Range.AutoY = true; 29 | 30 | Controller.DataSeriesCollection.Add(new UwpGraphDataSeries() 31 | { 32 | Name = "Series", 33 | Stroke = Colors.DodgerBlue, 34 | }); 35 | 36 | MultiController = new UwpGraphController(); 37 | MultiController.Range.MinimumY = 0; 38 | MultiController.Range.MaximumY = 1080; 39 | MultiController.Range.MaximumX = TimeSpan.FromSeconds(10); 40 | MultiController.Range.AutoY = true; 41 | 42 | MultiController.DataSeriesCollection.Add(new UwpGraphDataSeries() 43 | { 44 | Name = "Series 1", 45 | Stroke = Colors.Red, 46 | }); 47 | 48 | MultiController.DataSeriesCollection.Add(new UwpGraphDataSeries() 49 | { 50 | Name = "Series 2", 51 | Stroke = Colors.Green, 52 | }); 53 | 54 | MultiController.DataSeriesCollection.Add(new UwpGraphDataSeries() 55 | { 56 | Name = "Series 3", 57 | Stroke = Colors.Blue, 58 | }); 59 | 60 | MultiController.DataSeriesCollection.Add(new UwpGraphDataSeries() 61 | { 62 | Name = "Series 4", 63 | Stroke = Colors.Yellow, 64 | }); 65 | 66 | MultiController.DataSeriesCollection.Add(new UwpGraphDataSeries() 67 | { 68 | Name = "Series 5", 69 | Stroke = Colors.Gray, 70 | }); 71 | 72 | Stopwatch watch = new Stopwatch(); 73 | watch.Start(); 74 | 75 | Task.Factory.StartNew(async () => 76 | { 77 | while (true) 78 | { 79 | double y = 0; 80 | 81 | await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () => 82 | { 83 | y = Windows.UI.Core.CoreWindow.GetForCurrentThread().PointerPosition.Y; 84 | }); 85 | 86 | List yy = new List() 87 | { 88 | y, 89 | y + 20, 90 | y + 40, 91 | y + 60, 92 | y + 80, 93 | }; 94 | 95 | var x = watch.Elapsed; 96 | 97 | List xx = new List() 98 | { 99 | x, 100 | x, 101 | x, 102 | x, 103 | x 104 | }; 105 | 106 | Controller.PushData(x, y); 107 | MultiController.PushData(xx, yy); 108 | 109 | Thread.Sleep(30); 110 | } 111 | }); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/NamedBrush.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.UI.Xaml; 7 | using Windows.UI.Xaml.Media; 8 | 9 | namespace RealTimeGraphX.UWP.Demo 10 | { 11 | public class NamedBrush : DependencyObject 12 | { 13 | public Brush Brush 14 | { 15 | get { return (Brush)GetValue(BrushProperty); } 16 | set { SetValue(BrushProperty, value); } 17 | } 18 | public static readonly DependencyProperty BrushProperty = 19 | DependencyProperty.Register("Brush", typeof(Brush), typeof(NamedBrush), new PropertyMetadata(null)); 20 | 21 | public String Name 22 | { 23 | get 24 | { 25 | if (Brush is SolidColorBrush) 26 | { 27 | return (Brush as SolidColorBrush).Color.ToString(); 28 | } 29 | else 30 | { 31 | return "Gradient"; 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/NamedColor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.UI; 7 | using Windows.UI.Xaml; 8 | 9 | namespace RealTimeGraphX.UWP.Demo 10 | { 11 | public class NamedColor : DependencyObject 12 | { 13 | public Color Color 14 | { 15 | get { return (Color)GetValue(ColorProperty); } 16 | set { SetValue(ColorProperty, value); } 17 | } 18 | public static readonly DependencyProperty ColorProperty = 19 | DependencyProperty.Register("Color", typeof(Color), typeof(NamedColor), new PropertyMetadata(null)); 20 | 21 | public String Name 22 | { 23 | get { return Color.ToString(); } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | RealTimeGraphX.UWP.Demo 7 | Roy 8 | Assets\StoreLogo.png 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RealTimeGraphX.UWP.Demo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("RealTimeGraphX.UWP.Demo")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Properties/Default.rd.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 53 | 54 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP.Demo/UwpGraphControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.InteropServices.WindowsRuntime; 5 | using Windows.UI.Xaml; 6 | using Windows.UI.Xaml.Controls; 7 | using Windows.UI.Xaml.Data; 8 | using Windows.UI.Xaml.Documents; 9 | using Windows.UI.Xaml.Input; 10 | using Windows.UI.Xaml.Media; 11 | 12 | namespace RealTimeGraphX.UWP.Demo 13 | { 14 | public sealed class UwpGraphControl : Control 15 | { 16 | /// 17 | /// Gets or sets the graph controller. 18 | /// 19 | public IGraphController Controller 20 | { 21 | get { return (IGraphController)GetValue(ControllerProperty); } 22 | set { SetValue(ControllerProperty, value); } 23 | } 24 | public static readonly DependencyProperty ControllerProperty = 25 | DependencyProperty.Register("Controller", typeof(IGraphController), typeof(UwpGraphControl), new PropertyMetadata(null)); 26 | 27 | /// 28 | /// Gets or sets a value indicating whether to display a tool tip with the current cursor value. 29 | /// 30 | public bool DisplayToolTip 31 | { 32 | get { return (bool)GetValue(DisplayToolTipProperty); } 33 | set { SetValue(DisplayToolTipProperty, value); } 34 | } 35 | public static readonly DependencyProperty DisplayToolTipProperty = 36 | DependencyProperty.Register("DisplayToolTip", typeof(bool), typeof(UwpGraphControl), new PropertyMetadata(false)); 37 | 38 | public UwpGraphControl() 39 | { 40 | this.DefaultStyleKey = typeof(UwpGraphControl); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Graphics.Canvas; 2 | using Microsoft.Graphics.Canvas.Geometry; 3 | using RealTimeGraphX; 4 | using RealTimeGraphX.UWP; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Numerics; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | using Windows.UI; 12 | using Windows.UI.Xaml.Media; 13 | 14 | /// 15 | /// Contains a collection of extension methods. 16 | /// 17 | internal static class ExtensionMethods 18 | { 19 | /// 20 | /// Draws a polyline. 21 | /// 22 | /// The session. 23 | /// The points. 24 | /// The color. 25 | /// The stroke thickness. 26 | public static void DrawPolyline(this CanvasDrawingSession session, List points, Color color, float strokeThickness) 27 | { 28 | CanvasPathBuilder pathBuilder = new CanvasPathBuilder(session); 29 | 30 | pathBuilder.BeginFigure(points[0].X, points[0].Y); 31 | 32 | for (int i = 1; i < points.Count; i++) 33 | { 34 | pathBuilder.AddLine(points[i].X, points[i].Y); 35 | } 36 | 37 | pathBuilder.EndFigure(CanvasFigureLoop.Open); 38 | 39 | session.DrawGeometry(CanvasGeometry.CreatePath(pathBuilder), color, strokeThickness); 40 | } 41 | 42 | /// 43 | /// Fills a polygon. 44 | /// 45 | /// The session. 46 | /// The surface. 47 | /// The series. 48 | /// The points. 49 | /// The brush. 50 | public static void FillPolygon(this CanvasDrawingSession session, UwpGraphSurface surface, UwpGraphDataSeries series, List points, Brush brush) 51 | { 52 | var size = surface.GetSize(); 53 | var geometry = CanvasGeometry.CreatePolygon(session, points.ToArray()); 54 | var v = series.GetCanvasBrush(session, size.Width, size.Height); 55 | session.FillGeometry(geometry, v); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("RealTimeGraphX.UWP")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("RealTimeGraphX.UWP")] 13 | [assembly: AssemblyCopyright("Copyright © 2018")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/Properties/RealTimeGraphX.UWP.rd.xml: -------------------------------------------------------------------------------- 1 | 2 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/RealTimeGraphX.UWP.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RealTimeGraphX.UWP 5 | 1.0.0 6 | RealTimeGraphX is a data type agnostic, high performance plotting library for WPF and UWP. 7 | RealTimeGraphX.WPF 8 | Roy Ben Shabat 9 | false 10 | MIT 11 | https://github.com/royben/RealTimeGraphX 12 | icon.png 13 | Chart Graph Plotting RealTime WPF UWP 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpDataTriggerAction.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xaml.Interactivity; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Shapes; 10 | 11 | namespace RealTimeGraphX.UWP 12 | { 13 | /// 14 | /// Represents a data trigger action. 15 | /// 16 | /// 17 | /// 18 | internal class UwpDataTriggerAction : DependencyObject, IAction 19 | { 20 | /// 21 | /// Gets or sets the target object. 22 | /// 23 | public FrameworkElement TargetObject 24 | { 25 | get { return (FrameworkElement)GetValue(TargetObjectProperty); } 26 | set { SetValue(TargetObjectProperty, value); } 27 | } 28 | public static readonly DependencyProperty TargetObjectProperty = 29 | DependencyProperty.Register("TargetObject", typeof(FrameworkElement), typeof(UwpDataTriggerAction), new PropertyMetadata(null)); 30 | 31 | /// 32 | /// Gets or sets the name of the property. 33 | /// 34 | public String PropertyName 35 | { 36 | get { return (String)GetValue(PropertyNameProperty); } 37 | set { SetValue(PropertyNameProperty, value); } 38 | } 39 | public static readonly DependencyProperty PropertyNameProperty = 40 | DependencyProperty.Register("PropertyName", typeof(String), typeof(UwpDataTriggerAction), new PropertyMetadata(null)); 41 | 42 | /// 43 | /// Gets or sets the value. 44 | /// 45 | public Object Value 46 | { 47 | get { return (Object)GetValue(ValueProperty); } 48 | set { SetValue(ValueProperty, value); } 49 | } 50 | public static readonly DependencyProperty ValueProperty = 51 | DependencyProperty.Register("Value", typeof(Object), typeof(UwpDataTriggerAction), new PropertyMetadata(null)); 52 | 53 | /// 54 | /// Executes the action. 55 | /// 56 | /// The that is passed to the action by the behavior. Generally this is or a target object. 57 | /// The value of this parameter is determined by the caller. 58 | /// 59 | /// Returns the result of the action. 60 | /// 61 | /// 62 | /// An example of parameter usage is EventTriggerBehavior, which passes the EventArgs as a parameter to its actions. 63 | /// 64 | public object Execute(object sender, object parameter) 65 | { 66 | List props = new List(); 67 | List fields = new List(); 68 | 69 | Type type = TargetObject.GetType(); 70 | 71 | while (type != null) 72 | { 73 | props.AddRange(type.GetTypeInfo().DeclaredProperties); 74 | fields.AddRange(type.GetTypeInfo().DeclaredFields); 75 | type = type.BaseType; 76 | 77 | var prop = props.SingleOrDefault(x => x.Name == PropertyName + "Property"); 78 | 79 | if (prop != null) 80 | { 81 | var propValue = props.SingleOrDefault(x => x.Name == PropertyName); 82 | var _element_dp = prop.GetValue(TargetObject) as DependencyProperty; 83 | TargetObject.SetValue(_element_dp, Convert.ChangeType(Value, propValue.PropertyType)); 84 | return null; 85 | } 86 | else 87 | { 88 | var field = fields.SingleOrDefault(x => x.Name == PropertyName + "Property"); 89 | 90 | if (field != null) 91 | { 92 | var propValue = props.SingleOrDefault(x => x.Name == PropertyName); 93 | 94 | var _element_dp = field.GetValue(TargetObject) as DependencyProperty; 95 | TargetObject.SetValue(_element_dp, Convert.ChangeType(Value, propValue.PropertyType)); 96 | return null; 97 | } 98 | } 99 | } 100 | 101 | return null; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpDataTriggerElement.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Xaml.Interactions.Core; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Media; 11 | 12 | namespace RealTimeGraphX.UWP 13 | { 14 | /// 15 | /// Represents an invisible element which can be used to reevaluate a data trigger behavior binding inside a style. 16 | /// 17 | /// 18 | internal class UwpDataTriggerElement : Control 19 | { 20 | private FrameworkElement _parent; 21 | private DataTriggerBehavior _dataTrigger; 22 | 23 | #region Properties 24 | 25 | /// 26 | /// Gets or sets the name of the data trigger behavior element. 27 | /// 28 | public String ElementName 29 | { 30 | get { return (String)GetValue(ElementNameProperty); } 31 | set { SetValue(ElementNameProperty, value); } 32 | } 33 | public static readonly DependencyProperty ElementNameProperty = 34 | DependencyProperty.Register("ElementName", typeof(String), typeof(UwpDataTriggerElement), new PropertyMetadata(null)); 35 | 36 | /// 37 | /// Gets or sets the data context path that will cause the evaluation when changed. 38 | /// 39 | public String DataContextPath 40 | { 41 | get { return (String)GetValue(DataContextPathProperty); } 42 | set { SetValue(DataContextPathProperty, value); } 43 | } 44 | public static readonly DependencyProperty DataContextPathProperty = 45 | DependencyProperty.Register("DataContextPath", typeof(String), typeof(UwpDataTriggerElement), new PropertyMetadata(null, (d, e) => (d as UwpDataTriggerElement).OnBindingChanged())); 46 | 47 | #endregion 48 | 49 | #region Constructors 50 | 51 | /// 52 | /// Initializes a new instance of the class. 53 | /// 54 | public UwpDataTriggerElement() 55 | { 56 | Loaded += DataTriggerElement_Loaded; 57 | } 58 | 59 | #endregion 60 | 61 | #region Event Handlers 62 | 63 | /// 64 | /// Handles the Loaded event of the DataTriggerElement control. 65 | /// 66 | /// The source of the event. 67 | /// The instance containing the event data. 68 | private void DataTriggerElement_Loaded(object sender, RoutedEventArgs e) 69 | { 70 | _parent = VisualTreeHelper.GetParent(this) as FrameworkElement; 71 | _dataTrigger = (_parent as FrameworkElement).FindName(ElementName) as DataTriggerBehavior; 72 | OnBindingChanged(); 73 | } 74 | 75 | #endregion 76 | 77 | #region Virtual Methods 78 | 79 | /// 80 | /// Called when the has changed. 81 | /// 82 | /// The sender. 83 | /// The dependency property. 84 | protected virtual void OnDataContextPropertyChanged(DependencyObject sender, DependencyProperty dp) 85 | { 86 | var value = (DataContext as DependencyObject).GetValue(dp); 87 | 88 | if (value.ToString() == _dataTrigger.Value.ToString()) 89 | { 90 | UpdateBinding(); 91 | } 92 | } 93 | 94 | #endregion 95 | 96 | #region Private Methods 97 | 98 | /// 99 | /// Reevaluates the binding. 100 | /// 101 | private void OnBindingChanged() 102 | { 103 | if (DataContext != null) 104 | { 105 | var dataContextPropInfo = DataContext.GetType().GetField(DataContextPath + "Property", BindingFlags.Static | BindingFlags.Public); 106 | 107 | if (dataContextPropInfo != null) 108 | { 109 | var _datacontext_dp = dataContextPropInfo.GetValue(DataContext) as DependencyProperty; 110 | 111 | (DataContext as DependencyObject).RegisterPropertyChangedCallback(_datacontext_dp, OnDataContextPropertyChanged); 112 | 113 | if ((DataContext as DependencyObject).GetValue(_datacontext_dp).ToString() == _dataTrigger.Value.ToString()) 114 | { 115 | UpdateBinding(); 116 | } 117 | } 118 | } 119 | } 120 | 121 | /// 122 | /// Updates the binding. 123 | /// 124 | private void UpdateBinding() 125 | { 126 | foreach (var action in _dataTrigger.Actions.OfType()) 127 | { 128 | action.Execute(_dataTrigger, _dataTrigger.Value); 129 | } 130 | } 131 | 132 | #endregion 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpGraphAxisControl.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.EventArguments; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Collections.ObjectModel; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows; 10 | using Windows.UI.Xaml; 11 | using Windows.UI.Xaml.Controls; 12 | 13 | namespace RealTimeGraphX.UWP 14 | { 15 | /// 16 | /// Represents a horizontal/vertical graph axis control. 17 | /// 18 | /// 19 | public class UwpGraphAxisControl : UwpGraphComponentBase 20 | { 21 | private ItemsControl _items_control; 22 | 23 | /// 24 | /// Gets or sets the control orientation. 25 | /// 26 | public Orientation Orientation 27 | { 28 | get { return (Orientation)GetValue(OrientationProperty); } 29 | set { SetValue(OrientationProperty, value); } 30 | } 31 | public static readonly DependencyProperty OrientationProperty = 32 | DependencyProperty.Register("Orientation", typeof(Orientation), typeof(UwpGraphAxisControl), new PropertyMetadata(Orientation.Vertical)); 33 | 34 | /// 35 | /// Gets or sets the tick item template. 36 | /// 37 | public DataTemplate ItemTemplate 38 | { 39 | get { return (DataTemplate)GetValue(ItemTemplateProperty); } 40 | set { SetValue(ItemTemplateProperty, value); } 41 | } 42 | public static readonly DependencyProperty ItemTemplateProperty = 43 | DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(UwpGraphAxisControl), new PropertyMetadata(null)); 44 | 45 | /// 46 | /// Gets or sets the tick items. 47 | /// 48 | internal ObservableCollection Items 49 | { 50 | get { return (ObservableCollection)GetValue(ItemsProperty); } 51 | set { SetValue(ItemsProperty, value); } 52 | } 53 | public static readonly DependencyProperty ItemsProperty = 54 | DependencyProperty.Register("Items", typeof(ObservableCollection), typeof(UwpGraphAxisControl), new PropertyMetadata(null)); 55 | 56 | /// 57 | /// Gets or sets the number of ticks to display on the control. 58 | /// 59 | public int Ticks 60 | { 61 | get { return (int)GetValue(TicksProperty); } 62 | set { SetValue(TicksProperty, value); } 63 | } 64 | public static readonly DependencyProperty TicksProperty = 65 | DependencyProperty.Register("Ticks", typeof(int), typeof(UwpGraphAxisControl), new PropertyMetadata(9, (d, e) => (d as UwpGraphAxisControl).OnTicksChanged())); 66 | 67 | /// 68 | /// Gets or sets the string format which is used to format the ticks value. 69 | /// 70 | public String StringFormat 71 | { 72 | get { return (String)GetValue(StringFormatProperty); } 73 | set { SetValue(StringFormatProperty, value); } 74 | } 75 | public static readonly DependencyProperty StringFormatProperty = 76 | DependencyProperty.Register("StringFormat", typeof(String), typeof(UwpGraphAxisControl), new PropertyMetadata(null)); 77 | 78 | /// 79 | /// Initializes a new instance of the class. 80 | /// 81 | public UwpGraphAxisControl() 82 | { 83 | this.DefaultStyleKey = typeof(UwpGraphAxisControl); 84 | } 85 | 86 | /// 87 | /// Invoked whenever application code or internal processes (such as a rebuilding layout pass) call ApplyTemplate. In simplest terms, this means the method is called just before a UI element displays in your app. Override this method to influence the default post-template logic of a class. 88 | /// 89 | protected override void OnApplyTemplate() 90 | { 91 | base.OnApplyTemplate(); 92 | 93 | _items_control = GetTemplateChild("PART_ItemsControl") as ItemsControl; 94 | OnTicksChanged(); 95 | } 96 | 97 | /// 98 | /// Called when the property has changed. 99 | /// 100 | protected virtual void OnTicksChanged() 101 | { 102 | Items = new ObservableCollection(Enumerable.Range(0, Ticks).Select(x => new UwpGraphAxisTickData())); 103 | 104 | if (Controller != null) 105 | { 106 | Controller.RequestVirtualRangeChange(); 107 | } 108 | } 109 | 110 | /// 111 | /// Called when the controller has changed. 112 | /// 113 | /// The old controller. 114 | /// The new controller. 115 | protected override void OnControllerChanged(IGraphController oldController, IGraphController newController) 116 | { 117 | base.OnControllerChanged(oldController, newController); 118 | 119 | if (newController != null) 120 | { 121 | newController.RequestVirtualRangeChange(); 122 | } 123 | } 124 | 125 | /// 126 | /// Handles the event. 127 | /// 128 | /// The source of the event. 129 | /// The event arguments. 130 | protected override void OnVirtualRangeChanged(object sender, RangeChangedEventArgs e) 131 | { 132 | base.OnVirtualRangeChanged(sender, e); 133 | 134 | InvokeUI(() => 135 | { 136 | if (Orientation == Orientation.Vertical) 137 | { 138 | if (Items != null) 139 | { 140 | var steps = e.MinimumY.CreateRange(e.MinimumY, e.MaximumY, Ticks).Reverse().ToList(); 141 | 142 | for (int i = 0; i < steps.Count; i++) 143 | { 144 | var tick_data = Items[i]; 145 | tick_data.Data = steps[i]; 146 | tick_data.DisplayText = tick_data.Data.ToString(StringFormat); 147 | tick_data.IsFirst = i == 0; 148 | tick_data.IsLast = i == steps.Count - 1; 149 | tick_data.IsEven = i % 2 == 0; 150 | } 151 | } 152 | } 153 | else 154 | { 155 | if (Items != null) 156 | { 157 | var steps = e.MinimumX.CreateRange(e.MinimumX, e.MaximumX, Ticks).ToList(); 158 | 159 | for (int i = 0; i < steps.Count; i++) 160 | { 161 | var tick_data = Items[i]; 162 | tick_data.Data = steps[i]; 163 | tick_data.DisplayText = tick_data.Data.ToString(StringFormat); 164 | tick_data.IsFirst = i == 0; 165 | tick_data.IsLast = i == steps.Count - 1; 166 | tick_data.IsEven = i % 2 == 0; 167 | } 168 | } 169 | } 170 | }); 171 | } 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpGraphAxisPanel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using Windows.Foundation; 8 | using Windows.UI.Xaml; 9 | using Windows.UI.Xaml.Controls; 10 | using Windows.UI.Xaml.Media; 11 | 12 | namespace RealTimeGraphX.UWP 13 | { 14 | /// 15 | /// Represents a panel that will align its children in an axis labels like arrangement. 16 | /// 17 | /// 18 | public class UwpGraphAxisPanel : Grid 19 | { 20 | private List _measured_childs; 21 | 22 | /// 23 | /// Gets or sets the panel orientation. 24 | /// 25 | public Orientation Orientation 26 | { 27 | get { return (Orientation)GetValue(OrientationProperty); } 28 | set { SetValue(OrientationProperty, value); } 29 | } 30 | public static readonly DependencyProperty OrientationProperty = 31 | DependencyProperty.Register("Orientation", typeof(Orientation), typeof(UwpGraphAxisPanel), new PropertyMetadata(Orientation.Vertical)); 32 | 33 | /// 34 | /// Initializes a new instance of the class. 35 | /// 36 | public UwpGraphAxisPanel() 37 | { 38 | _measured_childs = new List(); 39 | Loaded += VerticalAxisPanel_Loaded; 40 | } 41 | 42 | /// 43 | /// Handles the Loaded event of the VerticalAxisGrid control. 44 | /// 45 | /// The source of the event. 46 | /// The instance containing the event data. 47 | private void VerticalAxisPanel_Loaded(object sender, RoutedEventArgs e) 48 | { 49 | UpdatePanel(); 50 | } 51 | 52 | /// 53 | /// Provides the behavior for the "Measure" pass of the layout cycle. Classes can override this method to define their own "Measure" pass behavior. 54 | /// 55 | /// The available size that this object can give to child objects. Infinity can be specified as a value to indicate that the object will size to whatever content is available. 56 | /// 57 | /// The size that this object determines it needs during layout, based on its calculations of the allocated sizes for child objects or based on other considerations such as a fixed container size. 58 | /// 59 | protected override Size MeasureOverride(Size availableSize) 60 | { 61 | UpdatePanel(); 62 | return base.MeasureOverride(availableSize); 63 | } 64 | 65 | /// 66 | /// Updates the panel. 67 | /// 68 | private void UpdatePanel() 69 | { 70 | if (!Children.Any(x => !_measured_childs.Contains(x))) return; 71 | 72 | RowDefinitions.Clear(); 73 | ColumnDefinitions.Clear(); 74 | 75 | 76 | if (Orientation == Orientation.Vertical) 77 | { 78 | for (int i = 0; i < Children.Count; i++) 79 | { 80 | FrameworkElement element = Children[i] as FrameworkElement; 81 | 82 | _measured_childs.Add(element); 83 | 84 | if (i < Children.Count - 1) 85 | { 86 | RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) }); 87 | Grid.SetRow(element, i); 88 | 89 | //if (element.DataContext is GraphAxisTickData) 90 | //{ 91 | // (element.DataContext as GraphAxisTickData).Row = i; 92 | //} 93 | 94 | element.VerticalAlignment = VerticalAlignment.Top; 95 | 96 | element.SizeChanged += (_, __) => 97 | { 98 | element.Margin = new Thickness(0, (element.ActualHeight / 2) * -1, 0, 0); 99 | }; 100 | } 101 | else 102 | { 103 | Grid.SetRow(element, i); 104 | 105 | //if (element.DataContext is GraphAxisTickData) 106 | //{ 107 | // (element.DataContext as GraphAxisTickData).Row = i; 108 | //} 109 | 110 | element.VerticalAlignment = VerticalAlignment.Bottom; 111 | 112 | element.SizeChanged += (_, __) => 113 | { 114 | element.Margin = new Thickness(0, 0, 0, (element.ActualHeight / 2) * -1); 115 | }; 116 | } 117 | } 118 | } 119 | else 120 | { 121 | for (int i = 0; i < Children.Count; i++) 122 | { 123 | FrameworkElement element = Children[i] as FrameworkElement; 124 | 125 | _measured_childs.Add(element); 126 | 127 | if (i < Children.Count - 1) 128 | { 129 | ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); 130 | Grid.SetColumn(element, i); 131 | element.HorizontalAlignment = HorizontalAlignment.Left; 132 | 133 | //if (element.DataContext is GraphAxisTickData) 134 | //{ 135 | // (element.DataContext as GraphAxisTickData).Column = i; 136 | //} 137 | 138 | element.SizeChanged += (_, __) => 139 | { 140 | element.Margin = new Thickness((element.ActualWidth / 2) * -1, 0, 0, 0); 141 | }; 142 | } 143 | else 144 | { 145 | Grid.SetColumn(element, i); 146 | element.HorizontalAlignment = HorizontalAlignment.Right; 147 | 148 | //if (element.DataContext is GraphAxisTickData) 149 | //{ 150 | // (element.DataContext as GraphAxisTickData).Column = i; 151 | //} 152 | 153 | element.SizeChanged += (_, __) => 154 | { 155 | element.Margin = new Thickness(0, 0, (element.ActualWidth / 2) * -1, 0); 156 | }; 157 | } 158 | } 159 | } 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpGraphAxisTickData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.UI.Xaml; 7 | using Windows.UI.Xaml.Controls; 8 | 9 | namespace RealTimeGraphX.UWP 10 | { 11 | /// 12 | /// Represents a graph axis data point tick value wrapper. 13 | /// 14 | public class UwpGraphAxisTickData : DependencyObject 15 | { 16 | /// 17 | /// Gets or sets a value indicating whether this tick is the first tick. 18 | /// 19 | public bool IsFirst 20 | { 21 | get { return (bool)GetValue(IsFirstProperty); } 22 | set { SetValue(IsFirstProperty, value); } 23 | } 24 | public static readonly DependencyProperty IsFirstProperty = 25 | DependencyProperty.Register("IsFirst", typeof(bool), typeof(UwpGraphAxisTickData), new PropertyMetadata(false)); 26 | 27 | /// 28 | /// Gets or sets a value indicating whether this tick is the last tick. 29 | /// 30 | public bool IsLast 31 | { 32 | get { return (bool)GetValue(IsLastProperty); } 33 | set { SetValue(IsLastProperty, value); } 34 | } 35 | public static readonly DependencyProperty IsLastProperty = 36 | DependencyProperty.Register("IsLast", typeof(bool), typeof(UwpGraphAxisTickData), new PropertyMetadata(false)); 37 | 38 | /// 39 | /// Gets or sets a value indicating whether this tick is not the first or last. 40 | /// 41 | public bool IsCenter 42 | { 43 | get { return !IsFirst && !IsLast; } 44 | } 45 | 46 | /// 47 | /// Gets or sets a value indicating whether this tick index is even. 48 | /// 49 | public bool IsEven 50 | { 51 | get { return (bool)GetValue(IsEvenProperty); } 52 | set { SetValue(IsEvenProperty, value); } 53 | } 54 | public static readonly DependencyProperty IsEvenProperty = 55 | DependencyProperty.Register("IsEven", typeof(bool), typeof(UwpGraphAxisTickData), new PropertyMetadata(false)); 56 | 57 | /// 58 | /// Gets a value indicating whether this tick index is odd. 59 | /// 60 | public bool IsOdd 61 | { 62 | get { return !IsEven; } 63 | } 64 | 65 | /// 66 | /// Gets or sets the actual graph data point. 67 | /// 68 | public IGraphDataPoint Data 69 | { 70 | get { return (IGraphDataPoint)GetValue(DataProperty); } 71 | set { SetValue(DataProperty, value); } 72 | } 73 | public static readonly DependencyProperty DataProperty = 74 | DependencyProperty.Register("Data", typeof(IGraphDataPoint), typeof(UwpGraphAxisTickData), new PropertyMetadata(null)); 75 | 76 | /// 77 | /// Gets or sets the display text. 78 | /// 79 | public String DisplayText 80 | { 81 | get { return (String)GetValue(DisplayTextProperty); } 82 | set { SetValue(DisplayTextProperty, value); } 83 | } 84 | public static readonly DependencyProperty DisplayTextProperty = 85 | DependencyProperty.Register("DisplayText", typeof(String), typeof(UwpGraphAxisTickData), new PropertyMetadata(null)); 86 | 87 | /// 88 | /// Gets the data point value. 89 | /// 90 | public object Value 91 | { 92 | get 93 | { 94 | return Data != null ? Data.GetValue() : null; 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpGraphComponentBase.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.EventArguments; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using Windows.UI.Xaml; 8 | using Windows.UI.Xaml.Controls; 9 | 10 | namespace RealTimeGraphX.UWP 11 | { 12 | /// 13 | /// Represents a graph component base class. 14 | /// 15 | /// 16 | public class UwpGraphComponentBase : Control 17 | { 18 | /// 19 | /// Gets or sets the graph controller. 20 | /// 21 | public IGraphController Controller 22 | { 23 | get { return (IGraphController)GetValue(ControllerProperty); } 24 | set { SetValue(ControllerProperty, value); } 25 | } 26 | public static readonly DependencyProperty ControllerProperty = 27 | DependencyProperty.Register("Controller", typeof(IGraphController), typeof(UwpGraphComponentBase), new PropertyMetadata(null,(d,e) => (d as UwpGraphComponentBase).OnControllerChanged(e.OldValue as IGraphController, e.NewValue as IGraphController))); 28 | 29 | 30 | /// 31 | /// Called when the controller has changed. 32 | /// 33 | /// The old controller. 34 | /// The new controller. 35 | protected virtual void OnControllerChanged(IGraphController oldController, IGraphController newController) 36 | { 37 | if (oldController != null) 38 | { 39 | oldController.VirtualRangeChanged -= OnVirtualRangeChanged; 40 | } 41 | 42 | if (newController != null) 43 | { 44 | newController.VirtualRangeChanged += OnVirtualRangeChanged; 45 | } 46 | } 47 | 48 | /// 49 | /// Handles the event. 50 | /// 51 | /// The source of the event. 52 | /// The event arguments. 53 | protected virtual void OnVirtualRangeChanged(object sender, RangeChangedEventArgs e) 54 | { 55 | //Optional 56 | } 57 | 58 | /// 59 | /// Invokes the specified method on the component dispatcher. 60 | /// 61 | /// The action. 62 | protected async void InvokeUI(Action action) 63 | { 64 | await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { action(); }); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpGraphController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Windows.UI; 7 | using Windows.UI.Xaml.Media; 8 | 9 | namespace RealTimeGraphX.UWP 10 | { 11 | /// 12 | /// Represents a UWP graph controller. 13 | /// 14 | /// The type of the x data point. 15 | /// The type of the y data point. 16 | /// 17 | public class UwpGraphController : GraphController 18 | where TXDataPoint : GraphDataPoint 19 | where TYDataPoint : GraphDataPoint 20 | { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpGraphDataSeries.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Graphics.Canvas; 2 | using Microsoft.Graphics.Canvas.Brushes; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using Windows.UI; 9 | using Windows.UI.Xaml; 10 | using Windows.UI.Xaml.Media; 11 | 12 | namespace RealTimeGraphX.UWP 13 | { 14 | /// 15 | /// Represents a UWP data series. 16 | /// 17 | /// 18 | /// 19 | public class UwpGraphDataSeries : GraphObject, IGraphDataSeries 20 | { 21 | private class Stop 22 | { 23 | public float Offset { get; set; } 24 | public Color Color { get; set; } 25 | } 26 | private Stop[] _stopCollection; 27 | 28 | 29 | 30 | private String _name; 31 | /// 32 | /// Gets or sets the series name. 33 | /// 34 | public String Name 35 | { 36 | get { return _name; } 37 | set { _name = value; RaisePropertyChangedAuto(); } 38 | } 39 | 40 | private float _strokeThickness; 41 | /// 42 | /// Gets or sets the stroke thickness. 43 | /// 44 | public float StrokeThickness 45 | { 46 | get 47 | { 48 | return _strokeThickness; 49 | } 50 | set 51 | { 52 | _strokeThickness = value; 53 | RaisePropertyChangedAuto(); 54 | } 55 | } 56 | 57 | private bool _isVisible; 58 | /// 59 | /// Gets or sets a value indicating whether this series should be visible. 60 | /// 61 | public bool IsVisible 62 | { 63 | get { return _isVisible; } 64 | set { _isVisible = value; RaisePropertyChangedAuto(); } 65 | } 66 | 67 | private Color _stroke; 68 | /// 69 | /// Gets or sets the series stroke color. 70 | /// 71 | public Color Stroke 72 | { 73 | get { return _stroke; } 74 | set 75 | { 76 | _stroke = value; 77 | RaisePropertyChangedAuto(); 78 | } 79 | } 80 | 81 | private Brush _fill; 82 | /// 83 | /// Gets or sets the series fill brush. 84 | /// 85 | public Brush Fill 86 | { 87 | get { return _fill; } 88 | set 89 | { 90 | _fill = value; 91 | 92 | if (_fill != null) 93 | { 94 | if (_fill is SolidColorBrush) 95 | { 96 | _stopCollection = new Stop[] { new Stop() { Color = (_fill as SolidColorBrush).Color, Offset = 0 } }; 97 | } 98 | else if (_fill is LinearGradientBrush) 99 | { 100 | _stopCollection = (_fill as LinearGradientBrush).GradientStops.Select(x => new Stop() { Color = x.Color, Offset = (float)x.Offset }).ToArray(); 101 | } 102 | } 103 | 104 | RaisePropertyChangedAuto(); 105 | } 106 | } 107 | 108 | /// 109 | /// Gets or sets a value indicating whether to fill the series. 110 | /// 111 | public bool UseFill 112 | { 113 | get { return Fill != null; } 114 | } 115 | 116 | private Object _currentValue; 117 | /// 118 | /// Gets the current value. 119 | /// 120 | public Object CurrentValue 121 | { 122 | get { return _currentValue; } 123 | set 124 | { 125 | _currentValue = value; 126 | } 127 | } 128 | 129 | /// 130 | /// Initializes a new instance of the class. 131 | /// 132 | public UwpGraphDataSeries() 133 | { 134 | StrokeThickness = 1; 135 | IsVisible = true; 136 | Stroke = Colors.DodgerBlue; 137 | } 138 | 139 | /// 140 | /// Gets the canvas brush. 141 | /// 142 | /// The creator. 143 | /// The width. 144 | /// The height. 145 | /// 146 | internal ICanvasBrush GetCanvasBrush(ICanvasResourceCreator creator, double width, double height) 147 | { 148 | if (_stopCollection.Length == 1) 149 | { 150 | return new CanvasSolidColorBrush(creator, _stopCollection[0].Color); 151 | } 152 | else 153 | { 154 | return new CanvasLinearGradientBrush(creator, _stopCollection.Select(x => new CanvasGradientStop() { Color = x.Color, Position = (float)(x.Offset) }).ToArray()) { StartPoint = new System.Numerics.Vector2(0, 0), EndPoint = new System.Numerics.Vector2((float)width, (float)height) }; 155 | } 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/UwpGraphGridLines.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using Windows.UI.Xaml; 8 | 9 | namespace RealTimeGraphX.UWP 10 | { 11 | /// 12 | /// Represents a graph grid lines component. 13 | /// 14 | /// 15 | public class UwpGraphGridLines : UwpGraphComponentBase 16 | { 17 | /// 18 | /// Gets or sets the number of grid rows. 19 | /// 20 | public int Rows 21 | { 22 | get { return (int)GetValue(RowsProperty); } 23 | set { SetValue(RowsProperty, value); } 24 | } 25 | public static readonly DependencyProperty RowsProperty = 26 | DependencyProperty.Register("Rows", typeof(int), typeof(UwpGraphGridLines), new PropertyMetadata(8, (d, e) => (d as UwpGraphGridLines).UpdateGridLines())); 27 | 28 | /// 29 | /// Gets or sets the number of grid columns. 30 | /// 31 | public int Columns 32 | { 33 | get { return (int)GetValue(ColumnsProperty); } 34 | set { SetValue(ColumnsProperty, value); } 35 | } 36 | public static readonly DependencyProperty ColumnsProperty = 37 | DependencyProperty.Register("Columns", typeof(int), typeof(UwpGraphGridLines), new PropertyMetadata(8, (d, e) => (d as UwpGraphGridLines).UpdateGridLines())); 38 | 39 | /// 40 | /// Gets or sets the vertical items. 41 | /// 42 | internal IEnumerable VerticalItems 43 | { 44 | get { return (IEnumerable)GetValue(VerticalItemsProperty); } 45 | set { SetValue(VerticalItemsProperty, value); } 46 | } 47 | public static readonly DependencyProperty VerticalItemsProperty = 48 | DependencyProperty.Register("VerticalItems", typeof(IEnumerable), typeof(UwpGraphGridLines), new PropertyMetadata(null)); 49 | 50 | /// 51 | /// Gets or sets the horizontal items. 52 | /// 53 | internal IEnumerable HorizontalItems 54 | { 55 | get { return (IEnumerable)GetValue(HorizontalItemsProperty); } 56 | set { SetValue(HorizontalItemsProperty, value); } 57 | } 58 | public static readonly DependencyProperty HorizontalItemsProperty = 59 | DependencyProperty.Register("HorizontalItems", typeof(IEnumerable), typeof(UwpGraphGridLines), new PropertyMetadata(null)); 60 | 61 | /// 62 | /// Initializes a new instance of the class. 63 | /// 64 | public UwpGraphGridLines() 65 | { 66 | this.DefaultStyleKey = typeof(UwpGraphGridLines); 67 | Loaded += GridLines_Loaded; 68 | } 69 | 70 | /// 71 | /// Handles the Loaded event of the GridLines control. 72 | /// 73 | /// The source of the event. 74 | /// The instance containing the event data. 75 | private void GridLines_Loaded(object sender, RoutedEventArgs e) 76 | { 77 | UpdateGridLines(); 78 | } 79 | 80 | /// 81 | /// Updates the grid lines. 82 | /// 83 | private void UpdateGridLines() 84 | { 85 | VerticalItems = Enumerable.Range(0, Rows).ToList(); 86 | HorizontalItems = Enumerable.Range(0, Columns).ToList(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /RealTimeGraphX.UWP/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.UWP/icon.png -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace RealTimeGraphX.WPF.Demo 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/Converters/ObjectEqualityConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Data; 8 | 9 | namespace RealTimeGraphX.WPF.Demo.Converters 10 | { 11 | public class ObjectEqualityConverter : IMultiValueConverter 12 | { 13 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 14 | { 15 | return values[0] == values[1]; 16 | } 17 | 18 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 19 | { 20 | throw new NotImplementedException(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/ListGraphItemVM.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.DataPoints; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Media; 8 | 9 | namespace RealTimeGraphX.WPF.Demo 10 | { 11 | public class ListGraphItemVM 12 | { 13 | public WpfGraphController Controller { get; set; } 14 | 15 | public String Name { get; set; } 16 | 17 | public String StringFormat { get; set; } 18 | 19 | public Color Color 20 | { 21 | get { return Controller.DataSeriesCollection[0].Stroke; } 22 | set { Controller.DataSeriesCollection[0].Stroke = value; } 23 | } 24 | 25 | public ListGraphItemVM() 26 | { 27 | Controller = new WpfGraphController(); 28 | Controller.Range.MinimumY = 0; 29 | Controller.Range.MaximumY = 1080; 30 | Controller.Range.MaximumX = TimeSpan.FromSeconds(10); 31 | Controller.Range.AutoY = true; 32 | Controller.Range.AutoYFallbackMode = GraphRangeAutoYFallBackMode.MinMax; 33 | 34 | Controller.DataSeriesCollection.Add(new WpfGraphDataSeries() 35 | { 36 | Name = "Series", 37 | Stroke = Colors.DodgerBlue, 38 | }); 39 | 40 | StringFormat = "0.0"; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace RealTimeGraphX.WPF.Demo 17 | { 18 | /// 19 | /// Interaction logic for MainWindow.xaml 20 | /// 21 | public partial class MainWindow : Window 22 | { 23 | public MainWindow() 24 | { 25 | InitializeComponent(); 26 | DataContext = new MainWindowVM(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/MainWindowVM.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.DataPoints; 2 | using RealTimeGraphX.Renderers; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using System.Windows; 11 | using System.Windows.Media; 12 | 13 | namespace RealTimeGraphX.WPF.Demo 14 | { 15 | public class MainWindowVM 16 | { 17 | private Random r = new Random(); 18 | 19 | public WpfGraphController Controller { get; set; } 20 | 21 | public WpfGraphController MultiController { get; set; } 22 | 23 | public List ListItems { get; set; } 24 | 25 | public List ListItems2 { get; set; } 26 | 27 | public MainWindowVM() 28 | { 29 | Controller = new WpfGraphController(); 30 | Controller.Range.MinimumY = 0; 31 | Controller.Range.MaximumY = 1080; 32 | Controller.Range.MaximumX = TimeSpan.FromSeconds(10); 33 | Controller.Range.AutoY = true; 34 | Controller.Range.AutoYFallbackMode = GraphRangeAutoYFallBackMode.MinMax; 35 | 36 | Controller.DataSeriesCollection.Add(new WpfGraphDataSeries() 37 | { 38 | Name = "Series", 39 | Stroke = Colors.DodgerBlue, 40 | }); 41 | 42 | MultiController = new WpfGraphController(); 43 | MultiController.Range.MinimumY = 0; 44 | MultiController.Range.MaximumY = 1080; 45 | MultiController.Range.MaximumX = TimeSpan.FromSeconds(10); 46 | MultiController.Range.AutoY = true; 47 | 48 | MultiController.DataSeriesCollection.Add(new WpfGraphDataSeries() 49 | { 50 | Name = "Series 1", 51 | Stroke = Colors.Red, 52 | }); 53 | 54 | MultiController.DataSeriesCollection.Add(new WpfGraphDataSeries() 55 | { 56 | Name = "Series 2", 57 | Stroke = Colors.Green, 58 | }); 59 | 60 | MultiController.DataSeriesCollection.Add(new WpfGraphDataSeries() 61 | { 62 | Name = "Series 3", 63 | Stroke = Colors.Blue, 64 | }); 65 | 66 | MultiController.DataSeriesCollection.Add(new WpfGraphDataSeries() 67 | { 68 | Name = "Series 4", 69 | Stroke = Colors.Yellow, 70 | }); 71 | 72 | MultiController.DataSeriesCollection.Add(new WpfGraphDataSeries() 73 | { 74 | Name = "Series 5", 75 | Stroke = Colors.Gray, 76 | }); 77 | 78 | ListItems = new List(); 79 | 80 | for (int i = 1; i < 6; i++) 81 | { 82 | var item = new ListGraphItemVM(); 83 | item.Name = $"Item {i}"; 84 | item.StringFormat = $"F{i}"; 85 | item.Color = GetRandomColor(); 86 | ListItems.Add(item); 87 | } 88 | 89 | ListItems2 = new List(); 90 | 91 | for (int i = 1; i < 6; i++) 92 | { 93 | var item = new ListGraphItemVM(); 94 | item.Name = $"Item {i}"; 95 | item.StringFormat = $"F{i}"; 96 | item.Color = GetRandomColor(); 97 | ListItems2.Add(item); 98 | } 99 | 100 | Application.Current.MainWindow.ContentRendered += (_, __) => Start(); 101 | } 102 | 103 | private void Start() 104 | { 105 | Task.Factory.StartNew(() => 106 | { 107 | Stopwatch watch = new Stopwatch(); 108 | watch.Start(); 109 | 110 | while (true) 111 | { 112 | var y = System.Windows.Forms.Cursor.Position.Y; 113 | 114 | List yy = new List() 115 | { 116 | y, 117 | y + 20, 118 | y + 40, 119 | y + 60, 120 | y + 80, 121 | }; 122 | 123 | var x = watch.Elapsed; 124 | 125 | List xx = new List() 126 | { 127 | x, 128 | x, 129 | x, 130 | x, 131 | x 132 | }; 133 | 134 | Controller.PushData(x, y); 135 | MultiController.PushData(xx, yy); 136 | 137 | for (int i = 0; i < ListItems.Count; i++) 138 | { 139 | ListItems[i].Controller.PushData(x, y + r.Next(0, 50 * (i + 1))); 140 | ListItems2[i].Controller.PushData(x, y + r.Next(0, 50 * (i + 1))); 141 | } 142 | 143 | Thread.Sleep(30); 144 | } 145 | }, TaskCreationOptions.LongRunning); 146 | } 147 | 148 | private Color GetRandomColor() 149 | { 150 | return Color.FromRgb((byte)r.Next(50, 255), (byte)r.Next(50, 255), (byte)r.Next(50, 255)); 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("RealTimeGraphX.WPF.Demo")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("RealTimeGraphX.WPF.Demo")] 15 | [assembly: AssemblyCopyright("Copyright © 2018")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace RealTimeGraphX.WPF.Demo.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RealTimeGraphX.WPF.Demo.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace RealTimeGraphX.WPF.Demo.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/RealTimeGraphX.WPF.Demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B822CBD9-1113-4668-85C9-22AA9C24CE60} 8 | WinExe 9 | RealTimeGraphX.WPF.Demo 10 | RealTimeGraphX.WPF.Demo 11 | v4.6.1 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 4.0 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | MSBuild:Compile 57 | Designer 58 | 59 | 60 | 61 | 62 | 63 | MSBuild:Compile 64 | Designer 65 | 66 | 67 | App.xaml 68 | Code 69 | 70 | 71 | MainWindow.xaml 72 | Code 73 | 74 | 75 | MSBuild:Compile 76 | Designer 77 | 78 | 79 | 80 | 81 | 82 | Code 83 | 84 | 85 | True 86 | True 87 | Resources.resx 88 | 89 | 90 | True 91 | Settings.settings 92 | True 93 | 94 | 95 | ResXFileCodeGenerator 96 | Resources.Designer.cs 97 | 98 | 99 | SettingsSingleFileGenerator 100 | Settings.Designer.cs 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | {6b9774f7-960d-438e-ad81-c6b9be328d50} 109 | RealTimeGraphX.WPF 110 | 111 | 112 | {61f001e1-6e17-4ca6-8f3a-8a11d7166815} 113 | RealTimeGraphX 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 55 | 56 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF.Demo/WpfGraphControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace RealTimeGraphX.WPF.Demo 17 | { 18 | public class WpfGraphControl : Control 19 | { 20 | /// 21 | /// Gets or sets the graph controller. 22 | /// 23 | public IGraphController Controller 24 | { 25 | get { return (IGraphController)GetValue(ControllerProperty); } 26 | set { SetValue(ControllerProperty, value); } 27 | } 28 | public static readonly DependencyProperty ControllerProperty = 29 | DependencyProperty.Register("Controller", typeof(IGraphController), typeof(WpfGraphControl), new PropertyMetadata(null)); 30 | 31 | /// 32 | /// Gets or sets a value indicating whether to display a tool tip with the current cursor value. 33 | /// 34 | public bool DisplayToolTip 35 | { 36 | get { return (bool)GetValue(DisplayToolTipProperty); } 37 | set { SetValue(DisplayToolTipProperty, value); } 38 | } 39 | public static readonly DependencyProperty DisplayToolTipProperty = 40 | DependencyProperty.Register("DisplayToolTip", typeof(bool), typeof(WpfGraphControl), new PropertyMetadata(false)); 41 | 42 | /// 43 | /// Gets or sets the string format for the X Axis. 44 | /// 45 | public String StringFormatX 46 | { 47 | get { return (String)GetValue(StringFormatXProperty); } 48 | set { SetValue(StringFormatXProperty, value); } 49 | } 50 | public static readonly DependencyProperty StringFormatXProperty = 51 | DependencyProperty.Register("StringFormatX", typeof(String), typeof(WpfGraphControl), new PropertyMetadata("0.0")); 52 | 53 | /// 54 | /// Gets or sets the string format for the Y Axis. 55 | /// 56 | public String StringFormatY 57 | { 58 | get { return (String)GetValue(StringFormatYProperty); } 59 | set { SetValue(StringFormatYProperty, value); } 60 | } 61 | public static readonly DependencyProperty StringFormatYProperty = 62 | DependencyProperty.Register("StringFormatY", typeof(String), typeof(WpfGraphControl), new PropertyMetadata("hh\\:mm\\:ss")); 63 | 64 | 65 | /// 66 | /// Initializes the class. 67 | /// 68 | static WpfGraphControl() 69 | { 70 | DefaultStyleKeyProperty.OverrideMetadata(typeof(WpfGraphControl), new FrameworkPropertyMetadata(typeof(WpfGraphControl))); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Drawing; 5 | using System.Drawing.Drawing2D; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace RealTimeGraphX.WPF 11 | { 12 | /// 13 | /// Contains a collection of extension methods. 14 | /// 15 | internal static class ExtensionMethods 16 | { 17 | /// 18 | /// Converts this WPF color to a GDI color. 19 | /// 20 | /// The color. 21 | /// 22 | internal static Color ToGdiColor(this System.Windows.Media.Color color) 23 | { 24 | return Color.FromArgb(color.A, color.R, color.G, color.B); 25 | } 26 | 27 | /// 28 | /// Converts this WPF brush to a GDI brush. 29 | /// 30 | /// The brush. 31 | /// 32 | internal static Brush ToGdiBrush(this System.Windows.Media.Brush brush) 33 | { 34 | if (brush.GetType() == typeof(System.Windows.Media.SolidColorBrush)) 35 | { 36 | return new SolidBrush((brush as System.Windows.Media.SolidColorBrush).Color.ToGdiColor()); 37 | } 38 | else if (brush.GetType() == typeof(System.Windows.Media.LinearGradientBrush)) 39 | { 40 | System.Windows.Media.LinearGradientBrush b = brush as System.Windows.Media.LinearGradientBrush; 41 | 42 | double angle = Math.Atan2(b.EndPoint.Y - b.StartPoint.Y, b.EndPoint.X - b.StartPoint.X) * 180 / Math.PI; 43 | 44 | LinearGradientBrush gradient = new LinearGradientBrush(new Rectangle(0, 0, 200, 100), Color.Black, Color.Black, (float)angle); 45 | 46 | ColorBlend blend = new ColorBlend(); 47 | 48 | List colors = new List(); 49 | List offsets = new List(); 50 | 51 | foreach (var stop in b.GradientStops) 52 | { 53 | colors.Add(stop.Color.ToGdiColor()); 54 | offsets.Add((float)stop.Offset); 55 | } 56 | 57 | blend.Colors = colors.ToArray(); 58 | blend.Positions = offsets.ToArray(); 59 | 60 | gradient.InterpolationColors = blend; 61 | 62 | return gradient; 63 | } 64 | else 65 | { 66 | return new LinearGradientBrush(new PointF(0, 0), new Point(200, 100), Color.Black, Color.Black); 67 | } 68 | } 69 | 70 | /// 71 | /// Determines whether this dependency object is running in design mode. 72 | /// 73 | /// The object. 74 | internal static bool IsInDesignMode(this System.Windows.DependencyObject obj) 75 | { 76 | return (DesignerProperties.GetIsInDesignMode(obj)); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("RealTimeGraphX.WPF")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("RealTimeGraphX.WPF")] 15 | [assembly: AssemblyCopyright("Copyright © 2018")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly:ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace RealTimeGraphX.WPF.Properties { 12 | 13 | 14 | /// 15 | /// A strongly-typed resource class, for looking up localized strings, etc. 16 | /// 17 | // This class was auto-generated by the StronglyTypedResourceBuilder 18 | // class via a tool like ResGen or Visual Studio. 19 | // To add or remove a member, edit your .ResX file then rerun ResGen 20 | // with the /str option, or rebuild your VS project. 21 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 22 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 23 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 24 | internal class Resources { 25 | 26 | private static global::System.Resources.ResourceManager resourceMan; 27 | 28 | private static global::System.Globalization.CultureInfo resourceCulture; 29 | 30 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 31 | internal Resources() { 32 | } 33 | 34 | /// 35 | /// Returns the cached ResourceManager instance used by this class. 36 | /// 37 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 38 | internal static global::System.Resources.ResourceManager ResourceManager { 39 | get { 40 | if ((resourceMan == null)) { 41 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RealTimeGraphX.WPF.Properties.Resources", typeof(Resources).Assembly); 42 | resourceMan = temp; 43 | } 44 | return resourceMan; 45 | } 46 | } 47 | 48 | /// 49 | /// Overrides the current thread's CurrentUICulture property for all 50 | /// resource lookups using this strongly typed resource class. 51 | /// 52 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 53 | internal static global::System.Globalization.CultureInfo Culture { 54 | get { 55 | return resourceCulture; 56 | } 57 | set { 58 | resourceCulture = value; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace RealTimeGraphX.WPF.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/RealTimeGraphX.WPF.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6B9774F7-960D-438E-AD81-C6B9BE328D50} 8 | library 9 | RealTimeGraphX.WPF 10 | RealTimeGraphX.WPF 11 | v4.6.1 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | bin\Release\RealTimeGraphX.WPF.xml 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 4.0 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | MSBuild:Compile 54 | Designer 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Code 66 | 67 | 68 | 69 | 70 | Code 71 | 72 | 73 | True 74 | True 75 | Resources.resx 76 | 77 | 78 | True 79 | Settings.settings 80 | True 81 | 82 | 83 | ResXFileCodeGenerator 84 | Resources.Designer.cs 85 | 86 | 87 | SettingsSingleFileGenerator 88 | Settings.Designer.cs 89 | 90 | 91 | 92 | 93 | 94 | {61f001e1-6e17-4ca6-8f3a-8a11d7166815} 95 | RealTimeGraphX 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/RealTimeGraphX.WPF.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | RealTimeGraphX.WPF 5 | 1.0.0 6 | RealTimeGraphX is a data type agnostic, high performance plotting library for WPF and UWP. 7 | RealTimeGraphX.WPF 8 | Roy Ben Shabat 9 | false 10 | MIT 11 | https://github.com/royben/RealTimeGraphX 12 | icon.png 13 | Chart Graph Plotting RealTime WPF UWP 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/WpfGraphAxisPanel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | 9 | namespace RealTimeGraphX.WPF 10 | { 11 | /// 12 | /// Represents a panel that will align its children in an axis labels like arrangement. 13 | /// 14 | /// 15 | public class WpfGraphAxisPanel : Grid 16 | { 17 | /// 18 | /// Gets or sets the panel orientation. 19 | /// 20 | public Orientation Orientation 21 | { 22 | get { return (Orientation)GetValue(OrientationProperty); } 23 | set { SetValue(OrientationProperty, value); } 24 | } 25 | public static readonly DependencyProperty OrientationProperty = 26 | DependencyProperty.Register("Orientation", typeof(Orientation), typeof(WpfGraphAxisPanel), new PropertyMetadata(Orientation.Vertical)); 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | public WpfGraphAxisPanel() 32 | { 33 | Loaded += VerticalAxisPanel_Loaded; 34 | } 35 | 36 | /// 37 | /// Handles the Loaded event of the VerticalAxisGrid control. 38 | /// 39 | /// The source of the event. 40 | /// The instance containing the event data. 41 | private void VerticalAxisPanel_Loaded(object sender, RoutedEventArgs e) 42 | { 43 | UpdatePanel(); 44 | } 45 | 46 | /// 47 | /// Updates the panel. 48 | /// 49 | public void UpdatePanel() 50 | { 51 | RowDefinitions.Clear(); 52 | ColumnDefinitions.Clear(); 53 | 54 | 55 | if (Orientation == Orientation.Vertical) 56 | { 57 | for (int i = 0; i < InternalChildren.Count; i++) 58 | { 59 | FrameworkElement element = InternalChildren[i] as FrameworkElement; 60 | 61 | if (i < InternalChildren.Count - 1) 62 | { 63 | RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) }); 64 | Grid.SetRow(element, i); 65 | element.VerticalAlignment = VerticalAlignment.Top; 66 | 67 | element.SizeChanged += (_, __) => 68 | { 69 | element.Margin = new Thickness(0, (element.ActualHeight / 2) * -1, 0, 0); 70 | }; 71 | } 72 | else 73 | { 74 | Grid.SetRow(element, i); 75 | element.VerticalAlignment = VerticalAlignment.Bottom; 76 | 77 | element.SizeChanged += (_, __) => 78 | { 79 | element.Margin = new Thickness(0, 0, 0, (element.ActualHeight / 2) * -1); 80 | }; 81 | } 82 | } 83 | } 84 | else 85 | { 86 | for (int i = 0; i < InternalChildren.Count; i++) 87 | { 88 | FrameworkElement element = InternalChildren[i] as FrameworkElement; 89 | 90 | if (i < InternalChildren.Count - 1) 91 | { 92 | ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); 93 | Grid.SetColumn(element, i); 94 | element.HorizontalAlignment = HorizontalAlignment.Left; 95 | 96 | element.SizeChanged += (_, __) => 97 | { 98 | element.Margin = new Thickness((element.ActualWidth / 2) * -1, 0, 0, 0); 99 | }; 100 | } 101 | else 102 | { 103 | Grid.SetColumn(element, i); 104 | element.HorizontalAlignment = HorizontalAlignment.Right; 105 | 106 | element.SizeChanged += (_, __) => 107 | { 108 | element.Margin = new Thickness(0, 0, (element.ActualWidth / 2) * -1, 0); 109 | }; 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/WpfGraphAxisTickData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace RealTimeGraphX.WPF 10 | { 11 | /// 12 | /// Represents a graph axis data point tick value wrapper. 13 | /// 14 | public class WpfGraphAxisTickData : DependencyObject 15 | { 16 | /// 17 | /// Gets or sets a value indicating whether this tick is the first tick. 18 | /// 19 | public bool IsFirst 20 | { 21 | get { return (bool)GetValue(IsFirstProperty); } 22 | set { SetValue(IsFirstProperty, value); } 23 | } 24 | public static readonly DependencyProperty IsFirstProperty = 25 | DependencyProperty.Register("IsFirst", typeof(bool), typeof(WpfGraphAxisTickData), new PropertyMetadata(false)); 26 | 27 | /// 28 | /// Gets or sets a value indicating whether this tick is the last tick. 29 | /// 30 | public bool IsLast 31 | { 32 | get { return (bool)GetValue(IsLastProperty); } 33 | set { SetValue(IsLastProperty, value); } 34 | } 35 | public static readonly DependencyProperty IsLastProperty = 36 | DependencyProperty.Register("IsLast", typeof(bool), typeof(WpfGraphAxisTickData), new PropertyMetadata(false)); 37 | 38 | /// 39 | /// Gets or sets a value indicating whether this tick is not the first or last. 40 | /// 41 | public bool IsCenter 42 | { 43 | get { return !IsFirst && !IsLast; } 44 | } 45 | 46 | /// 47 | /// Gets or sets a value indicating whether this tick index is even. 48 | /// 49 | public bool IsEven 50 | { 51 | get { return (bool)GetValue(IsEvenProperty); } 52 | set { SetValue(IsEvenProperty, value); } 53 | } 54 | public static readonly DependencyProperty IsEvenProperty = 55 | DependencyProperty.Register("IsEven", typeof(bool), typeof(WpfGraphAxisTickData), new PropertyMetadata(false)); 56 | 57 | /// 58 | /// Gets a value indicating whether this tick index is odd. 59 | /// 60 | public bool IsOdd 61 | { 62 | get { return !IsEven; } 63 | } 64 | 65 | /// 66 | /// Gets or sets the actual graph data point. 67 | /// 68 | public IGraphDataPoint Data 69 | { 70 | get { return (IGraphDataPoint)GetValue(DataProperty); } 71 | set { SetValue(DataProperty, value); } 72 | } 73 | public static readonly DependencyProperty DataProperty = 74 | DependencyProperty.Register("Data", typeof(IGraphDataPoint), typeof(WpfGraphAxisTickData), new PropertyMetadata(null)); 75 | 76 | /// 77 | /// Gets or sets the display text. 78 | /// 79 | public String DisplayText 80 | { 81 | get { return (String)GetValue(DisplayTextProperty); } 82 | set { SetValue(DisplayTextProperty, value); } 83 | } 84 | public static readonly DependencyProperty DisplayTextProperty = 85 | DependencyProperty.Register("DisplayText", typeof(String), typeof(WpfGraphAxisTickData), new PropertyMetadata(null)); 86 | 87 | /// 88 | /// Gets the Data Point value. 89 | /// 90 | public object Value 91 | { 92 | get 93 | { 94 | return Data != null ? Data.GetValue() : null; 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/WpfGraphComponentBase.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.EventArguments; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | 10 | namespace RealTimeGraphX.WPF 11 | { 12 | /// 13 | /// Represents a graph component base class. 14 | /// 15 | /// 16 | public abstract class WpfGraphComponentBase : Control 17 | { 18 | /// 19 | /// Gets or sets the graph controller. 20 | /// 21 | public IGraphController Controller 22 | { 23 | get { return (IGraphController)GetValue(ControllerProperty); } 24 | set { SetValue(ControllerProperty, value); } 25 | } 26 | public static readonly DependencyProperty ControllerProperty = 27 | DependencyProperty.Register("Controller", typeof(IGraphController), typeof(WpfGraphComponentBase), new PropertyMetadata(null, (d, e) => (d as WpfGraphComponentBase).OnControllerChanged(e.OldValue as IGraphController, e.NewValue as IGraphController))); 28 | 29 | /// 30 | /// Called when the controller has changed. 31 | /// 32 | /// The old controller. 33 | /// The new controller. 34 | protected virtual void OnControllerChanged(IGraphController oldController, IGraphController newController) 35 | { 36 | if (oldController != null) 37 | { 38 | oldController.VirtualRangeChanged -= OnVirtualRangeChanged; 39 | } 40 | 41 | if (newController != null) 42 | { 43 | newController.VirtualRangeChanged += OnVirtualRangeChanged; 44 | } 45 | } 46 | 47 | /// 48 | /// Handles the event. 49 | /// 50 | /// The source of the event. 51 | /// The event arguments. 52 | protected virtual void OnVirtualRangeChanged(object sender, RangeChangedEventArgs e) 53 | { 54 | //Optional 55 | } 56 | 57 | /// 58 | /// Invokes the specified method on the component dispatcher. 59 | /// 60 | /// The action. 61 | protected void InvokeUI(Action action) 62 | { 63 | Dispatcher.BeginInvoke(action); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/WpfGraphController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Media; 7 | 8 | namespace RealTimeGraphX.WPF 9 | { 10 | /// 11 | /// Represents a WPF graph controller. 12 | /// 13 | /// The type of the x data point. 14 | /// The type of the y data point. 15 | /// 16 | public class WpfGraphController : GraphController 17 | where TXDataPoint : GraphDataPoint 18 | where TYDataPoint : GraphDataPoint 19 | { 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/WpfGraphDataSeries.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Media; 7 | 8 | namespace RealTimeGraphX.WPF 9 | { 10 | /// 11 | /// Represents a WPF data series. 12 | /// 13 | /// 14 | /// 15 | public class WpfGraphDataSeries : GraphObject, IGraphDataSeries 16 | { 17 | #region Internal Properties 18 | 19 | /// 20 | /// Gets the GDI stroke color. 21 | /// 22 | internal System.Drawing.Color GdiStroke { get; private set; } 23 | 24 | /// 25 | /// Gets the GDI fill brush. 26 | /// 27 | internal System.Drawing.Brush GdiFill { get; private set; } 28 | 29 | /// 30 | /// Gets or sets the GDI pen. 31 | /// 32 | internal System.Drawing.Pen GdiPen { get; set; } 33 | 34 | #endregion 35 | 36 | private String _name; 37 | /// 38 | /// Gets or sets the series name. 39 | /// 40 | public String Name 41 | { 42 | get { return _name; } 43 | set { _name = value; RaisePropertyChangedAuto(); } 44 | } 45 | 46 | private float _strokeThickness; 47 | /// 48 | /// Gets or sets the stroke thickness. 49 | /// 50 | public float StrokeThickness 51 | { 52 | get 53 | { 54 | return _strokeThickness; 55 | } 56 | set 57 | { 58 | _strokeThickness = value; 59 | GdiPen = new System.Drawing.Pen(GdiStroke, _strokeThickness); 60 | RaisePropertyChangedAuto(); 61 | } 62 | } 63 | 64 | private bool _isVisible; 65 | /// 66 | /// Gets or sets a value indicating whether this series should be visible. 67 | /// 68 | public bool IsVisible 69 | { 70 | get { return _isVisible; } 71 | set { _isVisible = value; RaisePropertyChangedAuto(); } 72 | } 73 | 74 | private Color _stroke; 75 | /// 76 | /// Gets or sets the series stroke color. 77 | /// 78 | public Color Stroke 79 | { 80 | get { return _stroke; } 81 | set 82 | { 83 | _stroke = value; 84 | RaisePropertyChangedAuto(); 85 | 86 | if (_stroke != null) 87 | { 88 | GdiStroke = _stroke.ToGdiColor(); 89 | GdiPen = new System.Drawing.Pen(GdiStroke, StrokeThickness); 90 | } 91 | else 92 | { 93 | GdiStroke = System.Drawing.Color.Transparent; 94 | } 95 | } 96 | } 97 | 98 | private Brush _fill; 99 | /// 100 | /// Gets or sets the series fill brush. 101 | /// 102 | public Brush Fill 103 | { 104 | get { return _fill; } 105 | set 106 | { 107 | _fill = value; 108 | RaisePropertyChangedAuto(); 109 | 110 | if (_fill != null) 111 | { 112 | GdiFill = _fill.ToGdiBrush(); 113 | } 114 | else 115 | { 116 | GdiFill = null; 117 | } 118 | } 119 | } 120 | 121 | /// 122 | /// Initializes a new instance of the class. 123 | /// 124 | public WpfGraphDataSeries() 125 | { 126 | StrokeThickness = 1; 127 | IsVisible = true; 128 | Stroke = Colors.DodgerBlue; 129 | } 130 | 131 | /// 132 | /// Gets or sets a value indicating whether to fill the series. 133 | /// 134 | public bool UseFill 135 | { 136 | get { return Fill != null; } 137 | } 138 | 139 | private object _currentValue; 140 | /// 141 | /// Gets the current value. 142 | /// 143 | public object CurrentValue 144 | { 145 | get { return _currentValue; } 146 | set { _currentValue = value; RaisePropertyChangedAuto(); } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/WpfGraphGridLines.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Windows; 4 | 5 | namespace RealTimeGraphX.WPF 6 | { 7 | /// 8 | /// Represents a graph grid lines component. 9 | /// 10 | /// 11 | public class WpfGraphGridLines : WpfGraphComponentBase 12 | { 13 | /// 14 | /// Gets or sets the number of grid rows. 15 | /// 16 | public int Rows 17 | { 18 | get { return (int)GetValue(RowsProperty); } 19 | set { SetValue(RowsProperty, value); } 20 | } 21 | public static readonly DependencyProperty RowsProperty = 22 | DependencyProperty.Register("Rows", typeof(int), typeof(WpfGraphGridLines), new PropertyMetadata(8, (d, e) => (d as WpfGraphGridLines).UpdateGridLines())); 23 | 24 | /// 25 | /// Gets or sets the number of grid columns. 26 | /// 27 | public int Columns 28 | { 29 | get { return (int)GetValue(ColumnsProperty); } 30 | set { SetValue(ColumnsProperty, value); } 31 | } 32 | public static readonly DependencyProperty ColumnsProperty = 33 | DependencyProperty.Register("Columns", typeof(int), typeof(WpfGraphGridLines), new PropertyMetadata(8, (d, e) => (d as WpfGraphGridLines).UpdateGridLines())); 34 | 35 | /// 36 | /// Gets or sets the vertical items. 37 | /// 38 | internal IEnumerable VerticalItems 39 | { 40 | get { return (IEnumerable)GetValue(VerticalItemsProperty); } 41 | set { SetValue(VerticalItemsProperty, value); } 42 | } 43 | internal static readonly DependencyProperty VerticalItemsProperty = 44 | DependencyProperty.Register("VerticalItems", typeof(IEnumerable), typeof(WpfGraphGridLines), new PropertyMetadata(null)); 45 | 46 | /// 47 | /// Gets or sets the horizontal items. 48 | /// 49 | internal IEnumerable HorizontalItems 50 | { 51 | get { return (IEnumerable)GetValue(HorizontalItemsProperty); } 52 | set { SetValue(HorizontalItemsProperty, value); } 53 | } 54 | internal static readonly DependencyProperty HorizontalItemsProperty = 55 | DependencyProperty.Register("HorizontalItems", typeof(IEnumerable), typeof(WpfGraphGridLines), new PropertyMetadata(null)); 56 | 57 | /// 58 | /// Initializes the class. 59 | /// 60 | static WpfGraphGridLines() 61 | { 62 | DefaultStyleKeyProperty.OverrideMetadata(typeof(WpfGraphGridLines), new FrameworkPropertyMetadata(typeof(WpfGraphGridLines))); 63 | } 64 | 65 | /// 66 | /// Initializes a new instance of the class. 67 | /// 68 | public WpfGraphGridLines() 69 | { 70 | Loaded += GridLines_Loaded; 71 | } 72 | 73 | /// 74 | /// Handles the Loaded event of the GridLines control. 75 | /// 76 | /// The source of the event. 77 | /// The instance containing the event data. 78 | private void GridLines_Loaded(object sender, RoutedEventArgs e) 79 | { 80 | UpdateGridLines(); 81 | } 82 | 83 | /// 84 | /// Updates the grid lines. 85 | /// 86 | private void UpdateGridLines() 87 | { 88 | VerticalItems = Enumerable.Range(0, Rows).ToList(); 89 | HorizontalItems = Enumerable.Range(0, Columns).ToList(); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /RealTimeGraphX.WPF/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/RealTimeGraphX.WPF/icon.png -------------------------------------------------------------------------------- /RealTimeGraphX/DataPoints/DoubleDataPoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RealTimeGraphX.DataPoints 8 | { 9 | /// 10 | /// Represents a graph value data point. 11 | /// 12 | /// 13 | public class DoubleDataPoint : GraphDataPoint 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | public DoubleDataPoint() : base() 19 | { 20 | 21 | } 22 | 23 | /// 24 | /// Initializes a new instance of the class. 25 | /// 26 | /// The value. 27 | public DoubleDataPoint(double value) : base(value) 28 | { 29 | 30 | } 31 | 32 | /// 33 | /// Performs an implicit conversion from to . 34 | /// 35 | /// The value. 36 | /// 37 | /// The result of the conversion. 38 | /// 39 | public static implicit operator DoubleDataPoint(double value) 40 | { 41 | return new DoubleDataPoint(value); 42 | } 43 | 44 | /// 45 | /// Implements the operator -. 46 | /// 47 | /// a. 48 | /// The b. 49 | /// 50 | /// The result of the operator. 51 | /// 52 | public static DoubleDataPoint operator -(DoubleDataPoint a, DoubleDataPoint b) 53 | { 54 | return new DoubleDataPoint(a.Value - b.Value); 55 | } 56 | 57 | /// 58 | /// Implements the operator +. 59 | /// 60 | /// a. 61 | /// The b. 62 | /// 63 | /// The result of the operator. 64 | /// 65 | public static DoubleDataPoint operator +(DoubleDataPoint a, DoubleDataPoint b) 66 | { 67 | return new DoubleDataPoint(a.Value + b.Value); 68 | } 69 | 70 | /// 71 | /// Sums the value of this instance with another instance value and returns the result. 72 | /// 73 | /// The other instance. 74 | /// 75 | public override IGraphDataPoint Add(IGraphDataPoint other) 76 | { 77 | return new DoubleDataPoint(this.Value + (other as DoubleDataPoint).Value); 78 | } 79 | 80 | /// 81 | /// Subtract the value of another instance from this instance and returns the result. 82 | /// 83 | /// The other instance. 84 | /// 85 | public override IGraphDataPoint Subtract(IGraphDataPoint other) 86 | { 87 | return new DoubleDataPoint(this.Value - (other as DoubleDataPoint).Value); 88 | } 89 | 90 | /// 91 | /// Multiplies the value of this instance with another instance value and returns the result. 92 | /// 93 | /// The other instance. 94 | /// 95 | public override IGraphDataPoint Multiply(IGraphDataPoint other) 96 | { 97 | return new DoubleDataPoint(this.Value * (other as DoubleDataPoint).Value); 98 | } 99 | 100 | /// 101 | /// Divides the value of this instance with another instance value and returns the result. 102 | /// 103 | /// The other instance. 104 | /// 105 | public override IGraphDataPoint Divide(IGraphDataPoint other) 106 | { 107 | return new DoubleDataPoint(this.Value / (other as DoubleDataPoint).Value); 108 | } 109 | 110 | /// 111 | /// Returns the percentage value of this instance between the specified minimum and maximum values. 112 | /// 113 | /// The minimum. 114 | /// The maximum. 115 | /// 116 | public override double ComputeRelativePosition(IGraphDataPoint min, IGraphDataPoint max) 117 | { 118 | DoubleDataPoint dMin = min as DoubleDataPoint; 119 | DoubleDataPoint dMax = max as DoubleDataPoint; 120 | 121 | var result = ((Value - dMin) * 100) / (dMax - dMin); 122 | 123 | return double.IsNaN(result) || double.IsInfinity(result) ? dMin.Value : result; 124 | } 125 | 126 | /// 127 | /// Returns the absolute value of the specified percentage value between the specified minimum and maximum values. 128 | /// 129 | /// The minimum. 130 | /// The maximum. 131 | /// The percentage. 132 | /// 133 | public override IGraphDataPoint ComputeAbsolutePosition(IGraphDataPoint min, IGraphDataPoint max, double percentage) 134 | { 135 | double minimum = (double)min.GetValue(); 136 | double maximum = (double)max.GetValue(); 137 | 138 | return new DoubleDataPoint(minimum + (maximum - minimum) * percentage); 139 | } 140 | 141 | /// 142 | /// Creates a range of values from the specified minimum and maximum. 143 | /// 144 | /// The minimum. 145 | /// The maximum. 146 | /// The count. 147 | /// 148 | public override IEnumerable CreateRange(IGraphDataPoint min, IGraphDataPoint max, int count) 149 | { 150 | double minimum = (double)min.GetValue(); 151 | double maximum = (double)max.GetValue(); 152 | 153 | return Enumerable.Range(0, count). 154 | Select(i => minimum + (maximum - minimum) * ((double)i / (count - 1))). 155 | Select(x => new DoubleDataPoint(x)); 156 | } 157 | 158 | /// 159 | /// Returns a formated string of this data point. 160 | /// 161 | /// The format. 162 | /// 163 | public override string ToString(string format) 164 | { 165 | return Value.ToString(format); 166 | } 167 | 168 | /// 169 | /// Parses the specified value and returns a new instance of data point. 170 | /// 171 | /// The value. 172 | /// 173 | public override IGraphDataPoint Parse(string value) 174 | { 175 | return new DoubleDataPoint(double.Parse(value)); 176 | } 177 | 178 | /// 179 | /// Return the default margins for this data point type. 180 | /// and . 181 | /// 182 | /// 183 | protected override DoubleDataPoint OnGetDefaultMargins() 184 | { 185 | return new DoubleDataPoint(0.5); 186 | } 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /RealTimeGraphX/EventArguments/RangeChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RealTimeGraphX.EventArguments 8 | { 9 | /// 10 | /// Represents a graph range change event arguments. 11 | /// 12 | /// 13 | public class RangeChangedEventArgs : EventArgs 14 | { 15 | /// 16 | /// Gets or sets the minimum x value. 17 | /// 18 | public GraphDataPoint MinimumX { get; set; } 19 | 20 | /// 21 | /// Gets or sets the maximum x value. 22 | /// 23 | public GraphDataPoint MaximumX { get; set; } 24 | 25 | /// 26 | /// Gets or sets the minimum y value. 27 | /// 28 | public GraphDataPoint MinimumY { get; set; } 29 | 30 | /// 31 | /// Gets or sets the maximum y value. 32 | /// 33 | public GraphDataPoint MaximumY { get; set; } 34 | 35 | /// 36 | /// Initializes a new instance of the class. 37 | /// 38 | public RangeChangedEventArgs() 39 | { 40 | 41 | } 42 | 43 | /// 44 | /// Initializes a new instance of the class. 45 | /// 46 | /// The minimum x value. 47 | /// The maximum x value. 48 | /// The minimum y value. 49 | /// The maximum y value. 50 | public RangeChangedEventArgs(GraphDataPoint minimumX, GraphDataPoint maximumX,GraphDataPoint minimumY,GraphDataPoint maximumY) : this() 51 | { 52 | MinimumX = minimumX; 53 | MaximumX = maximumX; 54 | MinimumY = minimumY; 55 | MaximumY = maximumY; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Windows.Input; 5 | 6 | namespace RealTimeGraphX 7 | { 8 | /// 9 | /// Represents a graph relay command. 10 | /// 11 | /// 12 | public class GraphCommand : ICommand 13 | { 14 | private Action _action; 15 | private Func _canExecute; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// The action. 21 | /// The can execute. 22 | public GraphCommand(Action action, Func canExecute) 23 | { 24 | _action = action; 25 | _canExecute = canExecute; 26 | } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | /// The action. 32 | public GraphCommand(Action action) : this(action, null) 33 | { 34 | 35 | } 36 | 37 | /// 38 | /// Defines the method that determines whether the command can execute in its current state. 39 | /// 40 | /// Data used by the command. If the command does not require data to be passed, this object can be set to null. 41 | /// 42 | /// true if this command can be executed; otherwise, false. 43 | /// 44 | public bool CanExecute(object parameter) 45 | { 46 | if (_canExecute != null) 47 | { 48 | return _canExecute(); 49 | } 50 | 51 | return true; 52 | } 53 | 54 | /// 55 | /// Defines the method to be called when the command is invoked. 56 | /// 57 | /// Data used by the command. If the command does not require data to be passed, this object can be set to null. 58 | public void Execute(object parameter) 59 | { 60 | _action(); 61 | } 62 | 63 | /// 64 | /// Raises the can execute changed event. 65 | /// 66 | public void RaiseCanExecuteChanged() 67 | { 68 | CanExecuteChanged?.Invoke(this, new EventArgs()); 69 | } 70 | 71 | /// 72 | /// Occurs when changes occur that affect whether or not the command should execute. 73 | /// 74 | /// 75 | public event EventHandler CanExecuteChanged; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphDataPointHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RealTimeGraphX 8 | { 9 | /// 10 | /// Represents an helper class. 11 | /// 12 | public static class GraphDataPointHelper 13 | { 14 | /// 15 | /// Returns the absolute value of the specified percentage value between the specified minimum and maximum values. 16 | /// 17 | /// The minimum. 18 | /// The maximum. 19 | /// The percentage. 20 | /// 21 | public static T ComputeAbsolutePosition(T min, T max, double percentage) where T : class, IGraphDataPoint 22 | { 23 | return (Activator.CreateInstance(min.GetType()) as T).ComputeAbsolutePosition(min, max, percentage) as T; 24 | } 25 | 26 | /// 27 | /// Creates a range of values from the specified minimum and maximum. 28 | /// 29 | /// The minimum. 30 | /// The maximum. 31 | /// The count. 32 | /// 33 | public static IEnumerable CreateRange(IGraphDataPoint min, IGraphDataPoint max, int count) where T : class, IGraphDataPoint 34 | { 35 | return (Activator.CreateInstance(min.GetType()) as T).CreateRange(min, max, count) as IEnumerable; 36 | } 37 | 38 | /// 39 | /// Initializes a new instance of the specified type. 40 | /// 41 | /// 42 | /// 43 | public static T Init() where T : class, IGraphDataPoint 44 | { 45 | return Activator.CreateInstance(typeof(T)) as T; 46 | } 47 | 48 | /// 49 | /// Gets the default margins for the specified IGraphDataPoint. 50 | /// 51 | /// 52 | /// 53 | public static T GetDefaultMargins() where T : class, IGraphDataPoint 54 | { 55 | return Init().GetDefaultMargins() as T; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphDataPointTypeConverter.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.DataPoints; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Globalization; 6 | using System.Text; 7 | 8 | namespace RealTimeGraphX 9 | { 10 | /// 11 | /// Represents the type converter. 12 | /// 13 | public class GraphDataPointTypeConverter : TypeConverter 14 | { 15 | private IGraphDataPoint _instance; 16 | 17 | /// 18 | /// Returns whether this converter can convert an object of the given type to the type of this converter, using the specified context. 19 | /// 20 | /// An that provides a format context. 21 | /// A that represents the type you want to convert from. 22 | /// 23 | /// true if this converter can perform the conversion; otherwise, false. 24 | /// 25 | public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 26 | { 27 | return sourceType == typeof(String); 28 | } 29 | 30 | /// 31 | /// Converts the given object to the type of this converter, using the specified context and culture information. 32 | /// 33 | /// An that provides a format context. 34 | /// The to use as the current culture. 35 | /// The to convert. 36 | /// 37 | /// An that represents the converted value. 38 | /// 39 | public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 40 | { 41 | if (value != null && _instance != null) 42 | { 43 | try 44 | { 45 | return _instance.Parse(value.ToString()); 46 | } 47 | catch {} 48 | } 49 | 50 | return _instance; 51 | } 52 | 53 | /// 54 | /// Returns whether this converter can convert the object to the specified type, using the specified context. 55 | /// 56 | /// An that provides a format context. 57 | /// A that represents the type you want to convert to. 58 | /// 59 | /// true if this converter can perform the conversion; otherwise, false. 60 | /// 61 | public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 62 | { 63 | return destinationType == typeof(String); 64 | } 65 | 66 | /// 67 | /// Converts the given value object to the specified type, using the specified context and culture information. 68 | /// 69 | /// An that provides a format context. 70 | /// A . If null is passed, the current culture is assumed. 71 | /// The to convert. 72 | /// The to convert the value parameter to. 73 | /// 74 | /// An that represents the converted value. 75 | /// 76 | public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) 77 | { 78 | _instance = value as IGraphDataPoint; 79 | return value != null ? value.ToString() : null; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphDataQueue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace RealTimeGraphX 10 | { 11 | /// 12 | /// Represents a blocking concurrent queue for graph data consumption. 13 | /// 14 | /// 15 | /// 16 | public class GraphDataQueue : BlockingCollection 17 | { 18 | /// 19 | /// Initializes a new instance of the GraphDataQueue, Use Add and TryAdd for Enqueue and TryEnqueue and Take and TryTake for Dequeue and TryDequeue functionality 20 | /// 21 | public GraphDataQueue() 22 | : base(new ConcurrentQueue()) 23 | { 24 | } 25 | 26 | /// 27 | /// Initializes a new instance of the GraphDataQueue, Use Add and TryAdd for Enqueue and TryEnqueue and Take and TryTake for Dequeue and TryDequeue functionality 28 | /// 29 | /// 30 | public GraphDataQueue(int maxSize) 31 | : base(new ConcurrentQueue(), maxSize) 32 | { 33 | } 34 | 35 | /// 36 | /// Enqueues the specified item. 37 | /// 38 | /// The item. 39 | public void BlockEnqueue(T item) 40 | { 41 | Add(item); 42 | } 43 | 44 | /// 45 | /// Blocks until an item is available for dequeuing. 46 | /// 47 | /// 48 | public T BlockDequeue() 49 | { 50 | return Take(); 51 | } 52 | 53 | /// 54 | /// Blocks until an item is available for dequeuing. 55 | /// 56 | /// The cancellation token. 57 | /// 58 | public T BlockDequeue(CancellationToken cancellationToken) 59 | { 60 | return Take(cancellationToken); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Runtime.CompilerServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | 10 | namespace RealTimeGraphX 11 | { 12 | /// 13 | /// Represents an supported graph object. 14 | /// 15 | /// 16 | public abstract class GraphObject : INotifyPropertyChanged 17 | { 18 | /// 19 | /// Occurs when a property value changes. 20 | /// 21 | [field: NonSerialized] 22 | public event PropertyChangedEventHandler PropertyChanged; 23 | 24 | /// 25 | /// Raises the property changed event. 26 | /// 27 | /// Name of the property. 28 | protected virtual void RaisePropertyChangedAuto([CallerMemberName] string caller = null) 29 | { 30 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller)); 31 | } 32 | 33 | /// 34 | /// Raises the property changed event. 35 | /// 36 | /// Name of the property. 37 | protected virtual void RaisePropertyChanged(String propName) 38 | { 39 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphRange.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace RealTimeGraphX 8 | { 9 | /// 10 | /// Represents a graph x/y data points boundaries. 11 | /// 12 | public interface IGraphRange : IGraphComponent 13 | { 14 | /// 15 | /// Gets or sets the maximum x value. 16 | /// 17 | GraphDataPoint MaximumX { get; set; } 18 | 19 | /// 20 | /// Gets or sets the minimum x value. 21 | /// 22 | GraphDataPoint MinimumY { get; set; } 23 | 24 | /// 25 | /// Gets or sets the maximum y value. 26 | /// 27 | GraphDataPoint MaximumY { get; set; } 28 | 29 | /// 30 | /// Gets or sets a value indicating whether to automatically adjust the graph and according to the current effective data points. 31 | /// 32 | bool AutoY { get; set; } 33 | 34 | /// 35 | /// Gets or sets the fallback mode for when AutoY is set to true and all Y values are equal so to retain a perspective. 36 | /// 37 | GraphRangeAutoYFallBackMode AutoYFallbackMode { get; set; } 38 | 39 | /// 40 | /// Gets or sets the AutoY fallback margins when is set to Margins. 41 | /// 42 | GraphDataPoint AutoYFallBackMargins { get; set; } 43 | } 44 | 45 | /// 46 | /// Represents a graph X/Y range boundaries. 47 | /// 48 | /// Type of x-axis data point. 49 | /// Type of y-axis data point. 50 | /// 51 | public class GraphRange : GraphObject, IGraphRange where XDataPoint : GraphDataPoint where YDataPoint : GraphDataPoint 52 | { 53 | private XDataPoint _maximumX; 54 | /// 55 | /// Gets or sets the maximum x value. 56 | /// 57 | public XDataPoint MaximumX 58 | { 59 | get { return _maximumX; } 60 | set { _maximumX = value; RaisePropertyChangedAuto(); } 61 | } 62 | 63 | private YDataPoint _minimumY; 64 | /// 65 | /// Gets or sets the minimum x value. 66 | /// 67 | public YDataPoint MinimumY 68 | { 69 | get { return _minimumY; } 70 | set { _minimumY = value; RaisePropertyChangedAuto(); } 71 | } 72 | 73 | private YDataPoint _maximumY; 74 | /// 75 | /// Gets or sets the maximum y value. 76 | /// 77 | public YDataPoint MaximumY 78 | { 79 | get { return _maximumY; } 80 | set { _maximumY = value; RaisePropertyChangedAuto(); } 81 | } 82 | 83 | private bool _autoY; 84 | /// 85 | /// Gets or sets a value indicating whether to automatically adjust the graph and according to the current visible data points. 86 | /// 87 | public bool AutoY 88 | { 89 | get { return _autoY; } 90 | set { _autoY = value; RaisePropertyChangedAuto(); } 91 | } 92 | 93 | private GraphRangeAutoYFallBackMode _autoYFallbackMode; 94 | /// 95 | /// Gets or sets the fallback mode for when AutoY is set to true and all Y values are equal so to retain a perspective. 96 | /// 97 | public GraphRangeAutoYFallBackMode AutoYFallbackMode 98 | { 99 | get { return _autoYFallbackMode; } 100 | set { _autoYFallbackMode = value; RaisePropertyChangedAuto(); } 101 | } 102 | 103 | private YDataPoint _autoYFallbackMargins; 104 | /// 105 | /// Gets or sets the margins for when is set to . 106 | /// 107 | public YDataPoint AutoYFallbackMargins 108 | { 109 | get { return _autoYFallbackMargins; } 110 | set { _autoYFallbackMargins = value; RaisePropertyChangedAuto(); } 111 | } 112 | 113 | /// 114 | /// Initializes a new instance of the class. 115 | /// 116 | public GraphRange() 117 | { 118 | MinimumY = GraphDataPointHelper.Init(); 119 | MaximumX = GraphDataPointHelper.Init(); 120 | MaximumY = GraphDataPointHelper.Init(); 121 | AutoYFallbackMode = GraphRangeAutoYFallBackMode.Margins; 122 | AutoYFallbackMargins = GraphDataPointHelper.GetDefaultMargins(); 123 | } 124 | 125 | /// 126 | /// Gets or sets the maximum x value. 127 | /// 128 | GraphDataPoint IGraphRange.MaximumX 129 | { 130 | get 131 | { 132 | return MaximumX; 133 | } 134 | set 135 | { 136 | MaximumX = (XDataPoint)value; 137 | } 138 | } 139 | 140 | /// 141 | /// Gets or sets the minimum x value. 142 | /// 143 | GraphDataPoint IGraphRange.MinimumY 144 | { 145 | get 146 | { 147 | return MinimumY; 148 | } 149 | set 150 | { 151 | MinimumY = (YDataPoint)value; 152 | } 153 | } 154 | 155 | /// 156 | /// Gets or sets the maximum y value. 157 | /// 158 | GraphDataPoint IGraphRange.MaximumY 159 | { 160 | get 161 | { 162 | return MaximumY; 163 | } 164 | set 165 | { 166 | MaximumY = (YDataPoint)value; 167 | } 168 | } 169 | 170 | /// 171 | /// Gets or sets the fallback mode for when AutoY is set to true and all Y values are equal so to retain a perspective. 172 | /// 173 | GraphDataPoint IGraphRange.AutoYFallBackMargins 174 | { 175 | get 176 | { 177 | return AutoYFallbackMargins; 178 | } 179 | set 180 | { 181 | AutoYFallbackMargins = (YDataPoint)value; 182 | } 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphRangeAutoYFallBackMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace RealTimeGraphX 6 | { 7 | /// 8 | /// Represents an AutoY fall-back mode for then all Y values are equal. 9 | /// 10 | public enum GraphRangeAutoYFallBackMode 11 | { 12 | /// 13 | /// Create fake min/max margins of 0.5 from the Y value. 14 | /// 15 | Margins, 16 | /// 17 | /// Fallback to and . 18 | /// 19 | MinMax, 20 | /// 21 | /// Do nothing when all Y values are equal. 22 | /// 23 | None, 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Drawing; 4 | 5 | namespace RealTimeGraphX 6 | { 7 | /// 8 | /// Represents an base class. 9 | /// 10 | /// The type of the data series. 11 | /// 12 | /// 13 | public abstract class GraphRenderer : GraphObject, IGraphRenderer where TDataSeries : IGraphDataSeries 14 | { 15 | /// 16 | /// Converts the specified relative x position to a graph surface absolute position. 17 | /// 18 | /// The target surface. 19 | /// The relative x position. 20 | /// 21 | protected virtual float ConvertXValueToRendererValue(IGraphSurface surface, double x) 22 | { 23 | return (float)(x * surface.GetSize().Width / 100); 24 | } 25 | 26 | /// 27 | /// Converts the specified relative y position to a graph surface absolute position. 28 | /// 29 | /// The surface. 30 | /// The relative y position. 31 | /// 32 | protected virtual float ConvertYValueToRendererValue(IGraphSurface surface, double y) 33 | { 34 | return (float)(surface.GetSize().Height - (y * surface.GetSize().Height / 100)); 35 | } 36 | 37 | /// 38 | /// Arranges the series of data points and returns a series of drawing points. 39 | /// 40 | /// The target graph surface. 41 | /// The instance of the current rendered data series. 42 | /// Instance of graph range. 43 | /// Collection of x coordinates. 44 | /// Collection of y coordinates. 45 | /// The minimum x coordinates value. 46 | /// The maximum x coordinates value. 47 | /// The minimum y coordinates value. 48 | /// The maximum y coordinates value. 49 | /// 50 | public abstract IEnumerable Render(IGraphSurface surface, TDataSeries series, IGraphRange range, List xx, List yy, GraphDataPoint minimumX, GraphDataPoint maximumX, GraphDataPoint minimumY, GraphDataPoint maximumY); 51 | 52 | /// 53 | /// Draws the specified data series points on the target surface. 54 | /// 55 | /// The target graph surface. 56 | /// The instance of the current rendered data series. 57 | /// The collection of the current data series drawing points. 58 | /// The index of the current data series within the collection of data series. 59 | /// The length of the data series collection. 60 | public abstract void Draw(IGraphSurface surface, TDataSeries series, IEnumerable points, int index, int count); 61 | 62 | /// 63 | /// Gets a closed polygon version of the specified drawing points. 64 | /// 65 | /// The target surface. 66 | /// The drawing points. 67 | /// 68 | protected virtual IEnumerable GetFillPoints(IGraphSurface surface, IEnumerable points) 69 | { 70 | List closed = points.ToList(); 71 | closed.Add(new PointF(points.Last().X, surface.GetSize().Width)); 72 | closed.Add(new PointF(0, surface.GetSize().Height)); 73 | return closed.ToArray(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /RealTimeGraphX/GraphTransform.cs: -------------------------------------------------------------------------------- 1 | namespace RealTimeGraphX 2 | { 3 | /// 4 | /// Represents a graph transformation. 5 | /// 6 | public class GraphTransform 7 | { 8 | /// 9 | /// Gets or sets the horizontal scale factor. 10 | /// 11 | public float ScaleX { get; set; } 12 | 13 | /// 14 | /// Gets or sets the vertical scale factor. 15 | /// 16 | public float ScaleY { get; set; } 17 | 18 | /// 19 | /// Gets or sets the horizontal translate transformation. 20 | /// 21 | public float TranslateX { get; set; } 22 | 23 | /// 24 | /// Gets or sets the vertical translate transformation. 25 | /// 26 | public float TranslateY { get; set; } 27 | 28 | /// 29 | /// Initializes a new instance of the class. 30 | /// 31 | public GraphTransform() 32 | { 33 | ScaleX = 1; 34 | ScaleY = 1; 35 | TranslateX = 0; 36 | TranslateY = 0; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /RealTimeGraphX/IGraphComponent.cs: -------------------------------------------------------------------------------- 1 | namespace RealTimeGraphX 2 | { 3 | /// 4 | /// Represents a RealTimeGraphX component. 5 | /// 6 | public interface IGraphComponent 7 | { 8 | 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /RealTimeGraphX/IGraphDataPoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | 5 | namespace RealTimeGraphX 6 | { 7 | /// 8 | /// Represents a graph X or Y data point that can be pushed to a Graph Controller. 9 | /// 10 | /// 11 | [TypeConverter(typeof(GraphDataPointTypeConverter))] 12 | public interface IGraphDataPoint : IComparable 13 | { 14 | /// 15 | /// Sums the value of this instance with another instance value and returns the result. 16 | /// 17 | /// The other instance. 18 | /// 19 | IGraphDataPoint Add(IGraphDataPoint other); 20 | 21 | /// 22 | /// Subtract the value of another instance from this instance and returns the result. 23 | /// 24 | /// The other instance. 25 | /// 26 | IGraphDataPoint Subtract(IGraphDataPoint other); 27 | 28 | /// 29 | /// Multiplies the value of this instance with another instance value and returns the result. 30 | /// 31 | /// The other instance. 32 | /// 33 | IGraphDataPoint Multiply(IGraphDataPoint other); 34 | 35 | /// 36 | /// Divides the value of this instance with another instance value and returns the result. 37 | /// 38 | /// The other instance. 39 | /// 40 | IGraphDataPoint Divide(IGraphDataPoint other); 41 | 42 | /// 43 | /// Creates a range of values from the specified minimum and maximum. 44 | /// 45 | /// The minimum. 46 | /// The maximum. 47 | /// The count. 48 | /// 49 | IEnumerable CreateRange(IGraphDataPoint min, IGraphDataPoint max, int count); 50 | 51 | /// 52 | /// Returns the percentage value of this instance between the specified minimum and maximum values. 53 | /// 54 | /// The minimum. 55 | /// The maximum. 56 | /// 57 | double ComputeRelativePosition(IGraphDataPoint min, IGraphDataPoint max); 58 | 59 | /// 60 | /// Returns the absolute value of the specified percentage value between the specified minimum and maximum values. 61 | /// 62 | /// The minimum. 63 | /// The maximum. 64 | /// The percentage. 65 | /// 66 | IGraphDataPoint ComputeAbsolutePosition(IGraphDataPoint min, IGraphDataPoint max, double percentage); 67 | 68 | /// 69 | /// Gets the encapsulated value. 70 | /// 71 | /// 72 | object GetValue(); 73 | 74 | /// 75 | /// Sets the encapsulated value. 76 | /// 77 | /// The value. 78 | void SetValue(object value); 79 | 80 | /// 81 | /// Returns a formated string of this data point. 82 | /// 83 | /// The format. 84 | /// 85 | String ToString(String format); 86 | 87 | /// 88 | /// Parses the specified value. 89 | /// 90 | /// The value. 91 | /// 92 | IGraphDataPoint Parse(String value); 93 | 94 | /// 95 | /// Gets the default margins for this data point type. 96 | /// and . 97 | /// 98 | /// 99 | IGraphDataPoint GetDefaultMargins(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /RealTimeGraphX/IGraphDataSeries.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace RealTimeGraphX 4 | { 5 | /// 6 | /// Represents a graph data series. 7 | /// 8 | /// 9 | public interface IGraphDataSeries : IGraphComponent 10 | { 11 | /// 12 | /// Gets or sets the series name. 13 | /// 14 | String Name { get; set; } 15 | 16 | /// 17 | /// Gets or sets the stroke thickness. 18 | /// 19 | float StrokeThickness { get; set; } 20 | 21 | /// 22 | /// Gets or sets a value indicating whether to fill the series. 23 | /// 24 | bool UseFill { get; } 25 | 26 | /// 27 | /// Gets or sets a value indicating whether this series should be visible. 28 | /// 29 | bool IsVisible { get; set; } 30 | 31 | /// 32 | /// Gets the current value. 33 | /// 34 | Object CurrentValue { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /RealTimeGraphX/IGraphRenderer.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.EventArguments; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Text; 6 | 7 | namespace RealTimeGraphX 8 | { 9 | /// 10 | /// Represents a graph renderer capable of receiving a series of data points from a controller and transforming them to drawing points. 11 | /// 12 | /// The type of the data series. 13 | /// 14 | public interface IGraphRenderer : IGraphComponent where TDataSeries : IGraphDataSeries 15 | { 16 | /// 17 | /// Arranges the series of data points and returns a series of drawing points. 18 | /// 19 | /// The target graph surface. 20 | /// The instance of the current rendered data series. 21 | /// Instance of graph range. 22 | /// Collection of x coordinates. 23 | /// Collection of y coordinates. 24 | /// The minimum x coordinates value. 25 | /// The maximum x coordinates value. 26 | /// The minimum y coordinates value. 27 | /// The maximum y coordinates value. 28 | /// 29 | IEnumerable Render(IGraphSurface surface, TDataSeries series, IGraphRange range, List xx, List yy, GraphDataPoint minimumX, GraphDataPoint maximumX, GraphDataPoint minimumY, GraphDataPoint maximumY); 30 | 31 | /// 32 | /// Draws the specified data series points on the target surface. 33 | /// 34 | /// The target graph surface. 35 | /// The instance of the current rendered data series. 36 | /// The collection of the current data series drawing points. 37 | /// The index of the current data series within the collection of data series. 38 | /// The length of the data series collection. 39 | void Draw(IGraphSurface surface, TDataSeries series, IEnumerable points, int index, int count); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /RealTimeGraphX/IGraphSurface.cs: -------------------------------------------------------------------------------- 1 | using RealTimeGraphX.EventArguments; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Drawing; 5 | using System.Text; 6 | 7 | namespace RealTimeGraphX 8 | { 9 | /// 10 | /// Represents a graph drawing surface capable of drawing a series of points submitted by a graph renderer. 11 | /// 12 | public interface IGraphSurface : IGraphComponent 13 | { 14 | /// 15 | /// Occurs when the surface size has changed. 16 | /// 17 | event EventHandler SurfaceSizeChanged; 18 | 19 | /// 20 | /// Occurs when the surface zoom rectangle has changed. 21 | /// 22 | event EventHandler ZoomRectChanged; 23 | 24 | /// 25 | /// Returns the actual size of the surface. 26 | /// 27 | /// 28 | SizeF GetSize(); 29 | 30 | /// 31 | /// Returns the current bounds of the zooming rectangle. 32 | /// 33 | /// 34 | RectangleF GetZoomRect(); 35 | } 36 | 37 | /// 38 | /// Represents a graph drawing surface capable of drawing a series of points submitted by a graph renderer. 39 | /// 40 | /// The type of the data series. 41 | /// 42 | public interface IGraphSurface : IGraphSurface where TDataSeries : IGraphDataSeries 43 | { 44 | /// 45 | /// Called before drawing has started. 46 | /// 47 | void BeginDraw(); 48 | 49 | /// 50 | /// Draws the stroke of the specified data series points. 51 | /// 52 | /// The data series. 53 | /// The points. 54 | void DrawSeries(TDataSeries dataSeries, IEnumerable points); 55 | 56 | /// 57 | /// Fills the specified data series points. 58 | /// 59 | /// The data series. 60 | /// The points. 61 | void FillSeries(TDataSeries dataSeries, IEnumerable points); 62 | 63 | /// 64 | /// Applies transformation on the current pass. 65 | /// 66 | /// The transform. 67 | void SetTransform(GraphTransform transform); 68 | 69 | /// 70 | /// Called when drawing has completed. 71 | /// 72 | void EndDraw(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /RealTimeGraphX/RealTimeGraphX.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | false 6 | 1.0.0 7 | RealTimeGraphX is a data type agnostic, high performance plotting library for WPF and UWP. 8 | LICENSE 9 | https://github.com/royben/RealTimeGraphX 10 | icon.png 11 | https://github.com/royben/RealTimeGraphX 12 | Chart;Graph;Plotting;RealTime;WPF;UWP 13 | Roy Ben Shabat 14 | Roy Ben Shabat 15 | Release 16 | 17 | 18 | 19 | C:\DATA\Development\RealTimeGraphX\RealTimeGraphX\bin\Debug\RealTimeGraphX.xml 20 | 21 | 22 | 23 | C:\DATA\Development\RealTimeGraphX\RealTimeGraphX\bin\Release\RealTimeGraphX.xml 24 | 25 | 26 | 27 | 28 | True 29 | 30 | 31 | 32 | True 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /RealTimeGraphX/Renderers/ScrollingLineRenderer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | 6 | namespace RealTimeGraphX.Renderers 7 | { 8 | /// 9 | /// Represents a scrolling style . 10 | /// 11 | /// The type of the data series. 12 | /// 13 | public class ScrollingLineRenderer : GraphRenderer where TDataSeries : IGraphDataSeries 14 | { 15 | /// 16 | /// Arranges the series of data points and returns a series of drawing points. 17 | /// 18 | /// The target graph surface. 19 | /// The instance of the current rendered data series. 20 | /// Instance of graph range. 21 | /// Collection of x coordinates. 22 | /// Collection of y coordinates. 23 | /// The minimum x coordinates value. 24 | /// The maximum x coordinates value. 25 | /// The minimum y coordinates value. 26 | /// The maximum y coordinates value. 27 | /// 28 | public override IEnumerable Render(IGraphSurface surface, TDataSeries series, IGraphRange range, List xx, List yy, GraphDataPoint minimumX, GraphDataPoint maximumX, GraphDataPoint minimumY, GraphDataPoint maximumY) 29 | { 30 | var dxList = xx.Select(x => x.ComputeRelativePosition(minimumX, maximumX)).ToList(); 31 | var dyList = yy.Select(x => x.ComputeRelativePosition(minimumY, maximumY)).ToList(); 32 | 33 | if (maximumX - minimumX > range.MaximumX) 34 | { 35 | var offset = ((maximumX - minimumX) - range.MaximumX) + minimumX; 36 | 37 | for (int i = 0; i < xx.Count; i++) 38 | { 39 | if (xx[i] < offset) 40 | { 41 | xx.RemoveAt(i); 42 | yy.RemoveAt(i); 43 | i--; 44 | } 45 | else 46 | { 47 | break; 48 | } 49 | } 50 | } 51 | 52 | List points = new List(); 53 | 54 | for (int i = 0; i < dxList.Count; i++) 55 | { 56 | float image_x = ConvertXValueToRendererValue(surface,dxList[i]); 57 | float image_y = (float)Math.Min(ConvertYValueToRendererValue(surface, dyList[i]), surface.GetSize().Height - 2); 58 | 59 | PointF point = new PointF(image_x, image_y); 60 | points.Add(point); 61 | } 62 | 63 | return points; 64 | } 65 | 66 | /// 67 | /// Draws the specified data series points on the target surface. 68 | /// 69 | /// The target graph surface. 70 | /// The instance of the current rendered data series. 71 | /// The collection of the current data series drawing points. 72 | /// The index of the current data series within the collection of data series. 73 | /// The length of the data series collection. 74 | public override void Draw(IGraphSurface surface, TDataSeries series, IEnumerable points, int index, int count) 75 | { 76 | if (series.UseFill) 77 | { 78 | surface?.FillSeries(series, GetFillPoints(surface, points)); 79 | } 80 | 81 | surface?.DrawSeries(series, points); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /visuals/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/royben/RealTimeGraphX/d35b95d65ee118450c4dbafd61b90c14a9067bd0/visuals/icon.png --------------------------------------------------------------------------------