Charts, login, manage queue, styling
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.UI.DataVisualization.Charting;
|
||||
using System.Web.UI.WebControls;
|
||||
using log4net;
|
||||
using LeafWeb.Core.Charter;
|
||||
using LeafWeb.Core.Entities;
|
||||
using LeafWeb.Core.Parsers;
|
||||
using LeafWeb.Core.Utility;
|
||||
using LeafWeb.WebCms.Models;
|
||||
using LeafWeb.WebCms.Services;
|
||||
|
||||
namespace LeafWeb.WebCms.Controllers
|
||||
{
|
||||
public class ChartController : BaseController
|
||||
{
|
||||
public ActionResult Index(int? leafInputId)
|
||||
{
|
||||
if (!leafInputId.HasValue)
|
||||
return View("DataError", model: "Must specify LeafInputId");
|
||||
|
||||
var leafOutputFile = DataService.GetLeafOutput_ChartFile(leafInputId.Value);
|
||||
|
||||
if (leafOutputFile == null)
|
||||
throw new ArgumentOutOfRangeException(); // TODO: break
|
||||
|
||||
try
|
||||
{
|
||||
var curveIds = GetCurveIds(leafOutputFile.FileContents.Contents);
|
||||
|
||||
var viewModel = new ChartViewModel
|
||||
{
|
||||
AvailableCurveId = curveIds,
|
||||
LeafInputId = leafInputId.Value,
|
||||
LeafInputIdentifier = leafOutputFile.LeafInput.Identifier
|
||||
};
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
catch (ParseException parseException)
|
||||
{
|
||||
var logger = LogManager.GetLogger(GetType());
|
||||
logger.Warn(parseException);
|
||||
return View("DataError", model: parseException.Message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
var logger = LogManager.GetLogger(GetType());
|
||||
logger.Warn(e);
|
||||
return View("DataError", model: "Error while loading data. Administrators have been notified.");
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult ChartCurve(int leafInputId, string curveId)
|
||||
{
|
||||
var leafOutputFile = DataService.GetLeafOutput_ChartFile(leafInputId);
|
||||
|
||||
if (leafOutputFile == null)
|
||||
throw new ArgumentOutOfRangeException(); // TODO: break
|
||||
|
||||
CurveData curveData;
|
||||
try
|
||||
{
|
||||
curveData = GetCurveData(leafOutputFile.FileContents.Contents, curveId);
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
return new HttpStatusCodeResult(HttpStatusCode.NotFound, e.Message);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return new HttpStatusCodeResult(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
if (curveData == null)
|
||||
return new HttpStatusCodeResult(HttpStatusCode.NotFound);
|
||||
|
||||
var charts = GetChartBitmaps(curveData).ToList();
|
||||
|
||||
var combinedChart = CombineBitmaps(charts);
|
||||
|
||||
foreach (var chart in charts) chart.Dispose(); // cleanup
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
combinedChart.Save(ms, ImageFormat.Png);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
return File(ms.ToArray(), "image/png", curveId.FilterValidFilename() + ".png");
|
||||
}
|
||||
}
|
||||
|
||||
private CurveData GetCurveData(byte[] fileContents, string curveId)
|
||||
{
|
||||
try
|
||||
{
|
||||
LeafGasComparison[] leafGasComparisons;
|
||||
using (var parser = new LeafGasComparisonParser(fileContents))
|
||||
leafGasComparisons = parser.Parse(curveId);
|
||||
return CurveDataConverter.Convert(leafGasComparisons).First();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogManager.GetLogger(GetType()).Warn(e);
|
||||
throw;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string[] GetCurveIds(byte[] fileContents)
|
||||
{
|
||||
using (var parser = new LeafGasComparisonParser(fileContents))
|
||||
return parser.ExtractCurveIds();
|
||||
}
|
||||
|
||||
private IEnumerable<Bitmap> GetChartBitmaps(CurveData curveData)
|
||||
{
|
||||
var charts = LeafGasCharter.ProduceCharts(curveData);
|
||||
|
||||
foreach (var chart in charts)
|
||||
{
|
||||
// http://stackoverflow.com/a/336396/99492
|
||||
var ms = new MemoryStream(); // this gets attached to the bmp, dispose of it later
|
||||
chart.SaveImage(ms, ChartImageFormat.Bmp);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
yield return new Bitmap(ms);
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap CombineBitmaps(IList<Bitmap> bitmaps, int columnCount = 2)
|
||||
{
|
||||
if (!bitmaps.Any())
|
||||
return null;
|
||||
// bitmaps assumed to have same dimensions, use the first one to define that
|
||||
var cellWidth = bitmaps[0].Width;
|
||||
var cellHeight = bitmaps[0].Height;
|
||||
var width = cellWidth * columnCount;
|
||||
var height = cellHeight * bitmaps.Count / columnCount;
|
||||
|
||||
var combinedBitmap = new Bitmap(width, height);
|
||||
using (var g = Graphics.FromImage(combinedBitmap))
|
||||
{
|
||||
var currentCol = 0;
|
||||
var currentRow = 0;
|
||||
foreach (var image in bitmaps)
|
||||
{
|
||||
g.DrawImage(image, currentCol * cellWidth, currentRow * cellHeight);
|
||||
|
||||
currentCol = (currentCol + 1)%columnCount;
|
||||
currentRow += currentCol == 0 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
return combinedBitmap;
|
||||
}
|
||||
|
||||
public ActionResult ChartSample()
|
||||
{
|
||||
var chart = new Chart
|
||||
{
|
||||
BackColor = Color.FromArgb(255, 255, 255),
|
||||
Width = Unit.Pixel(250),
|
||||
Height = Unit.Pixel(2500)
|
||||
};
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
ChartArea = "ca1",
|
||||
ChartType = SeriesChartType.Line
|
||||
};
|
||||
|
||||
//series.Font = new Font("Verdana", 8.25f, FontStyle.Regular);
|
||||
|
||||
var myRandom = new Random();
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
var dp = new DataPoint();
|
||||
dp.AxisLabel = String.Format("{0}-{1}", i, Guid.NewGuid().ToString().Substring(0, 4));
|
||||
dp.YValues = new double[] { myRandom.Next(5, 100) };
|
||||
series.Points.Add(dp);
|
||||
}
|
||||
|
||||
|
||||
chart.Series.Add(series);
|
||||
|
||||
var area = new ChartArea("ca1");
|
||||
area.Area3DStyle.Enable3D = false;
|
||||
area.AxisX.Interval = 1;
|
||||
//area.BackColor = Color.Transparent;
|
||||
//var labelStyle = new LabelStyle();
|
||||
//labelStyle.Enabled = true;
|
||||
//labelStyle.Font = new Font("Arial", 3f);
|
||||
area.AxisX.LabelStyle.Font = new Font("Verdana", 8.25f, FontStyle.Underline);//Why does it recognize the style but not the font!!!???
|
||||
|
||||
chart.ChartAreas.Add(area);
|
||||
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
chart.SaveImage(ms, ChartImageFormat.Png);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return File(ms.ToArray(), "image/png", "mychart.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace LeafWeb.WebCms.Controllers
|
||||
{
|
||||
public JsonResult Autocomplete(string query)
|
||||
{
|
||||
var sites = DataService.GetFluxnetSitesAutocomplete(query).Take(50).ToList();
|
||||
var sites = DataService.GetFluxnetSitesAutocomplete(query).Take(40).ToList();
|
||||
var data = new
|
||||
{
|
||||
suggestions =
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
using LeafWeb.Core.Entities;
|
||||
using LeafWeb.Core.Utility;
|
||||
using LeafWeb.WebCms.Models;
|
||||
|
||||
namespace LeafWeb.WebCms.Controllers
|
||||
{
|
||||
public class QueueController : BaseController
|
||||
{
|
||||
public ActionResult Index()
|
||||
{
|
||||
var viewModel =
|
||||
DataService.GetLeafInputs()
|
||||
.OrderByDescending(f => f.Id)
|
||||
.ToList()
|
||||
.Select(leafInput => new ResultStatusViewModel(leafInput));
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
public ActionResult Details(int id)
|
||||
{
|
||||
var leafInput = DataService.GetLeafInput(id);
|
||||
var viewModel = new LeafInputCreate();
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
public ActionResult DownloadInput(int id)
|
||||
{
|
||||
return GetInputZip(id);
|
||||
}
|
||||
|
||||
public ActionResult DownloadOutputToUser(int id)
|
||||
{
|
||||
return GetOutputZip(id, LeafOutputFileType.ToUser);
|
||||
}
|
||||
|
||||
public ActionResult DownloadOutputNotToUser(int id)
|
||||
{
|
||||
return GetOutputZip(id, LeafOutputFileType.NotToUser);
|
||||
}
|
||||
|
||||
public ActionResult DownloadOutputCleanedInput(int id)
|
||||
{
|
||||
return GetOutputZip(id, LeafOutputFileType.CleanedInput);
|
||||
}
|
||||
|
||||
private ActionResult GetOutputZip(int id, LeafOutputFileType type)
|
||||
{
|
||||
var leafInput = DataService.GetLeafInput(id);
|
||||
|
||||
if (leafInput == null)
|
||||
return View("DownloadNotFound");
|
||||
|
||||
var zip = leafInput.GetOutputFileZip(type);
|
||||
|
||||
var filename = $"{leafInput.Identifier.FilterValidFilename()}_{type}.zip";
|
||||
|
||||
return new FileContentResult(zip, "application/zip") { FileDownloadName = filename };
|
||||
}
|
||||
|
||||
private ActionResult GetInputZip(int id)
|
||||
{
|
||||
var leafInput = DataService.GetLeafInput(id);
|
||||
|
||||
if (leafInput == null)
|
||||
return View("DownloadNotFound");
|
||||
|
||||
var zip = leafInput.GetInputFileZip();
|
||||
|
||||
var filename = $"{leafInput.Identifier.FilterValidFilename()}_Input.zip";
|
||||
|
||||
return new FileContentResult(zip, "application/zip") { FileDownloadName = filename };
|
||||
}
|
||||
|
||||
public ActionResult Delete(int id)
|
||||
{
|
||||
var leafInput = DataService.GetLeafInput(id);
|
||||
var viewModel = new LeafInputCreate();
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
[HttpPost, ActionName("Delete")]
|
||||
[ActionLog]
|
||||
public ActionResult DeleteConfirmed(int id)
|
||||
{
|
||||
// TODO: don't allow currently running LeafInput to be deleted
|
||||
var leafInput = DataService.GetLeafInput(id);
|
||||
DataService.DeleteLeafInput(leafInput);
|
||||
|
||||
SetStatusMessage($"LeafInput '{leafInput.Identifier}' deleted");
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user