I use highchart for show my income in month so i use this code:
public Highcharts ActivityMonthlyChart(string username,string year)
{
//some code to get data
Highcharts charts = new Highcharts("ActivityChart")
.SetTitle(new Title
{
Text = ""
})
.SetXAxis(new XAxis
{
Categories =
new[]
{
"فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی"
,
"بهمن", "اسفند"
}
})
.SetTooltip(new Tooltip
{
Formatter = #"function() {
return '<center><b>'+ this.series.name +'</b><br/>'+
this.x +': '+ this.y +'تومان<center>';
}",
Crosshairs = new Crosshairs(true),
})
.SetYAxis(new YAxis
{
Title = new YAxisTitle {Text = "قیمت - تومان"},
PlotLines = new[]
{
new YAxisPlotLines
{
Value = 0,
Width = 10000,
}
},
}
)
.SetSeries(new Series
{
Data = new Data(myObject)
});
return charts;
}
As you can see my local language is persian so my chart should be changed .i mean the y and x axis should be changed to the right how can i do that ?
Best regards .
Add Opposite value to
.SetYAxis(new YAxis
{
Opposite = true;
and Reversed for xAxis
.SetXAxis(new XAxis
{
Reversed = true;
Related
I am using Chart.Js (version 4.1) in Blazor and have managed to get a simple line graph up and running.
Now I need to add the currency symbol to the y Axis (which displays sales total), at the moment it simple displays a number as 4,222
My current Options and DataSets anonymous types are below, these are sent to Chart.JS via JS Interops. Below is what I have tried so far which fails to include the symbol in the tool tip and y axis.
var config = new
{
Type = Type.ToString().ToLower(),
Options = new
{
Responsive = true,
Scales = new
{
y = new
{
ticks = new
{
color = "white"
},
grid = new
{
color = "white",
borderColor = "white",
drawOnChartArea = false
},
scaleLabel = new
{
display = true,
labelString = "Sales Total £",
fontColor = "white"
}
},
x = new
{
ticks = new
{
color = "white"
},
grid = new
{
color = "white",
borderColor = "white",
drawOnChartArea = false
}
}
},
Tooltips = new
{
Callbacks = new
{
Label = "function(tooltipItem, data) { return '$' + tooltipItem.value; }"
}
}
},
Data = ChartData
};
What do I need to modify above to include the currency symbol in the tooltip and yAxis?
Since v3 the tooltip is located under plugins in options: here
This is how it looks in javaScript:
options:{
...
plugins: {
tooltip: {
callbacks: {
label: function (context) {
if (context.parsed.y !== null) {
return context.dataset.label + ": " +
new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(context.parsed.y);
}
return "";
}
}
}
}
...
}
For the y-axis you also can use a callback:
options:{
...
scales: {
y: {
ticks: {
callback: function (value, index, ticks) {
return new Intl.NumberFormat('de-DE', {
style: 'currency',
currency: 'EUR'
}).format(value);
}
}
}
}
...
}
Attention, note that it is called "tooltip," not "tooltips"!
I am new to C#. I have been trying to write a xUnit Test for the method below ("ExecuteExportCsvCommand()"). However, it has some UI control as you can see below.
Therefore, I don't know how to test the function. If anyone can explain, I would be really thankful.
public void ExecuteExportCsvCommand()
{
ExecuteCancelPopOutWindowCommand();
var previousState = View.IsEnabled;
View.IsEnabled = false;
try
{
var exportDialog = new ExportPrintDataDialog();
var result = exportDialog.ShowDialog();
if (result.GetValueOrDefault())
{
var projectData = _projectService.GetProject3dObject(Project.Id);
IEnumerable<object> orderedList;
orderedList = projectData.Select((x, i) => new ExportData {
Index = i,
Time = x.Time,
LayerNumber = x.LayerNumber,
X = x.X,
Y = x.Y,
Z = x.Z,
ArcVoltage = x.ArcVoltage,
Current = x.Current,
WireFeedSpeed = x.WireFeedSpeed,
WireFeedSpeedB = x.WireFeedSpeedB,
RatioWireFeedSpeed = (x.WireFeedSpeed == 0) ? 0 : x.WireFeedSpeedB / x.WireFeedSpeed,
BuildHeight = x.WallHeight,
LeadTemperature = x.LeadTemperature,
TrailTemperature = x.TrailTemperature,
OxygenLevel = x.OxygenLevel,
GasFlowA = x.GasFlow.First(),
GasFlowB = x.GasFlow.Last(),
TempChannels = x.TempChannels //preferably last as array of 8 values
}).ToList();
//Define Column headers
var heightHeader = _options.CorriOptions.Value.UseWallHeight ? "Wall Height" : "Layer Height";
var wfsHeader = Project.ProcessEnum == EnumProjectProcess.CW_MIG
? new []{ "Hot Wire Feed Speed", "Cold Wire Feed Speed" }
: new[] { "Wire Feed Speed 1", "Wire Feed Speed 2" };
var headers = new Dictionary<string, string>()
{
{ "Index" , "Ordinal Number" },
{ "Time" , "Time" },
{ "LayerNumber" , "Layer Number" },
{ "X" , "Pos X" },
{ "Y" , "Pos Y" },
{ "Z" , "Pos Z" },
{ "ArcVoltage" , "Arc Voltage" },
{ "Current" , "Current" },
{ "WireFeedSpeed" , wfsHeader.First() },
{ "WireFeedSpeedB" , wfsHeader.Last() },
{"RatioWireFeedSpeed", "R-Ratio"},
{ "BuildHeight" , heightHeader },
{ "LeadTemperature" , "Lead Temperature" },
{ "TrailTemperature" , "Trail Temperature" },
{ "OxygenLevel" , "Oxygen Level" },
{ "GasFlowA" , "GasFlow Channel A" },
{ "GasFlowB" , "GasFlow Channel B" },
{ "TempChannels" , "End Effector Temperature (Channels 1 - 8)" }
};
var saveFileDialog = new SaveFileDialog
{
Filter = "csv files (*.csv)|*.csv|All files (*.*)|*.*",
FilterIndex = 1,
RestoreDirectory = true,
FileName = string.Concat(DateTime.Now.ToString("yyyy-MM-ddTHHmm"), "_log"),
};
if (saveFileDialog.ShowDialog().GetValueOrDefault())
{
using var writer = new StreamWriter(saveFileDialog.FileName);
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
csv.Context.RegisterClassMap(new ExportDataMapper(headers));
csv.WriteRecords(orderedList);
}
}
}
finally
{
View.IsEnabled = previousState;
ExportDataBtnChecked = false;
}
}
The test environment was set up already as you can see below. I just have to write the test for the method mentioned. If you need further details, please let me know. thanks.
public class ProjectPrintViewModelTests
{
private readonly ProjectPrintViewModel _sut;
private readonly IHost _host;
private readonly Mock<IPermissionChecker> _permissionChecker = new Mock<IPermissionChecker>();
private readonly Mock<ILogService> _logService = new Mock<ILogService>();
private readonly Mock<IAuditService> _auditService = new Mock<IAuditService>();
private readonly Mock<IProjectService> _projectService = new Mock<IProjectService>();
public ProjectPrintViewModelTests()
{
var colorList = new List<string> {
"DefaultMinColor",
"DefaultLowColor",
"DefaultNormColor",
"DefaultHighColor",
"DefaultMaxColor"
};
var app = new Application();
colorList.ForEach(x => app.Resources.Add(x, Color.FromRgb(255, 255, 255)));
_host = MockEnvironment.BuildHost();
IoCContainer.SetServiceProvider(_host.Services);
var options = _host.Services.GetRequiredService<OptionsContainer>();
var valueService = _host.Services.GetRequiredService<IValuePointService>();
var project = new ProjectViewModel(options);
_sut = new ProjectPrintViewModel(
options,
project,
_logService.Object,
_permissionChecker.Object,
_auditService.Object,
_projectService.Object,
valueService,
false);
}
/// Write Tests Below Here
[Fact]
public void ExecuteCsvFileCommand_WhenValueAreValid()
{
//Assemble
//Act
_sut.ExecuteExportCsvCommand();
//Assert
This is one of the many disadvantages of having poor design and non-clean architecture.. Separating UI code from business logic helps you in testing your business logic well.
Keep in mind that unit tests should run/return as fast as possible. Apparently, showing a SaveFileDialog will stop the test until a user selects the path, this is wrong!
You should pull all UI-related code out to a separate component that delivers UI services, For example:
public interface IUiServices
{
void CancelPopOutWindow();
void SaveViewState();
void RestoreViewState();
bool ShowExportDialog();
string ShowSaveFileDialog();
}
The most important part is, when testing, you'd mock the UIServices to not do any real UI work (Ex. opinging SaveFileDialog, it will just return a valid test path to save files in there).. So ExecuteExportCsvCommand can be look like this..
public void ExecuteExportCsvCommand()
{
_uiServices.CancelPopOutWindow();
_uiServices.SaveViewState();
try
{
var b = _uiServices.ShowExportDialog();
if (b)
{
var projectData = _projectService.GetProject3dObject(Project.Id);
IEnumerable<object> orderedList;
orderedList = projectData.Select((x, i) => new ExportData {
Index = i,
Time = x.Time,
LayerNumber = x.LayerNumber,
X = x.X,
Y = x.Y,
Z = x.Z,
ArcVoltage = x.ArcVoltage,
Current = x.Current,
WireFeedSpeed = x.WireFeedSpeed,
WireFeedSpeedB = x.WireFeedSpeedB,
RatioWireFeedSpeed = (x.WireFeedSpeed == 0) ? 0 : x.WireFeedSpeedB / x.WireFeedSpeed,
BuildHeight = x.WallHeight,
LeadTemperature = x.LeadTemperature,
TrailTemperature = x.TrailTemperature,
OxygenLevel = x.OxygenLevel,
GasFlowA = x.GasFlow.First(),
GasFlowB = x.GasFlow.Last(),
TempChannels = x.TempChannels //preferably last as array of 8 values
}).ToList();
//Define Column headers
var heightHeader = _options.CorriOptions.Value.UseWallHeight ? "Wall Height" : "Layer Height";
var wfsHeader = Project.ProcessEnum == EnumProjectProcess.CW_MIG
? new []{ "Hot Wire Feed Speed", "Cold Wire Feed Speed" }
: new[] { "Wire Feed Speed 1", "Wire Feed Speed 2" };
var headers = new Dictionary<string, string>()
{
{ "Index" , "Ordinal Number" },
{ "Time" , "Time" },
{ "LayerNumber" , "Layer Number" },
{ "X" , "Pos X" },
{ "Y" , "Pos Y" },
{ "Z" , "Pos Z" },
{ "ArcVoltage" , "Arc Voltage" },
{ "Current" , "Current" },
{ "WireFeedSpeed" , wfsHeader.First() },
{ "WireFeedSpeedB" , wfsHeader.Last() },
{"RatioWireFeedSpeed", "R-Ratio"},
{ "BuildHeight" , heightHeader },
{ "LeadTemperature" , "Lead Temperature" },
{ "TrailTemperature" , "Trail Temperature" },
{ "OxygenLevel" , "Oxygen Level" },
{ "GasFlowA" , "GasFlow Channel A" },
{ "GasFlowB" , "GasFlow Channel B" },
{ "TempChannels" , "End Effector Temperature (Channels 1 - 8)" }
};
string path = _uiServices.ShowSaveFileDialog();
if (!string.IsNullOrEmpty(path))
{
using var writer = new StreamWriter(path);
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
csv.Context.RegisterClassMap(new ExportDataMapper(headers));
csv.WriteRecords(orderedList);
}
}
}
finally
{
_uiServices.RestoreViewState();
ExportDataBtnChecked = false;
}
}
I need to change the text colour of some cells while preserving the rest of the formatting using Sheets API v4.
I followed a sample to the ForeColor for a cell range in how-to-read/write-google-sheets-with-c#.
if (foreColor != System.Drawing.Color.Empty)
{
var spreadsheet = await service.Spreadsheets.Get(_spreadsheetId).ExecuteAsync();
var sheet = spreadsheet.Sheets.First(s => s.Properties.Title == worksheetTitle);
int sheetId = sheet.Properties.SheetId ?? 0;
var cellFormat = new CellFormat
{
TextFormat = new TextFormat
{
ForegroundColor = new Color
{
Alpha = foreColor.A / 255f,
Red = foreColor.R / 255f,
Green = foreColor.G / 255f,
Blue = foreColor.B / 255f,
}
}
};
CellData getFormatted() => new CellData { UserEnteredFormat = cellFormat };
var request = new Request
{
UpdateCells = new UpdateCellsRequest
{
Start = new GridCoordinate
{
SheetId = _sheetId,
ColumnIndex = startColumnIndex,
RowIndex = rowNumber - 1,
},
Fields = "*",
Rows = new List<RowData> { new RowData {
Values = new List<CellData>
{
getFormatted(), // details
getFormatted(), // system type
getFormatted(), // price
getFormatted(), // primary cost
getFormatted(), // secondary cost
getFormatted(), // accepted
}
} },
},
};
var requests = new BatchUpdateSpreadsheetRequest
{
ResponseIncludeGridData = true,
Requests = new List<Request> { request },
};
var response = await service.Spreadsheets.BatchUpdate(requests, spreadsheet.SpreadsheetId).ExecuteAsync();
}
The problem with the code above is that while it does change the text colour, it also clears all cell values and existing formatting - (like borders, text-align, etc.).
Is there a way to only update cell text colour?
First look at it, Fields = "*", will replace all fields. Since you only wish to update foregroundColor, try using this instead:
Fields = "userEnteredFormat.textFormat.foregroundColor"
Sample request body:
"requests": [
{
"repeatCell": {
// A:B
"range": {
"sheetId": 0,
"startColumnIndex": 0,
"endColumnIndex": 2
},
// change font color to blue
"cell": {
"userEnteredFormat": {
"textFormat": {
"foregroundColor": {
"blue": 1
}
// included bold for fields demonstration
"bold": true
}
}
},
"fields": "userEnteredFormat.textFormat.foregroundColor"
}
}
]
Notice that I included bold below the foregroundColor. Since we just specified userEnteredFormat.textFormat.foregroundColor in the fields, it will just update that foregroundColor in the request (neglecting the bold)
Issue on yours is that, you used *, thus replacing all formats and values, removing the cell values and formats entirely since you don't have values for the other fields in your request.
Sample:
Output:
Sample references you can check:
https://stackoverflow.com/a/42926565/14606045
https://stackoverflow.com/a/66981838/14606045
https://stackoverflow.com/a/63442303/14606045
I am new with Google pie charts. I want to change the style of label like line color of label match with the color of slice if slice is blue then line color should be blue.
And some slice are not showing its label like the yellow and purple slice.
var data3 = google.visualization.arrayToDataTable(ClaimSubmissionStatus);
var options = {
legend: { textStyle: { color: 'black', fontSize: 14 }, position: 'labeled', alignemnt: 'center' },
//is3D: true,
// legend: { position: 'labeled' },
chartArea: { backgroundColor: '#FFFFFF', left: '5%', top: '15', width: '85%' }
};
var charta = new google.visualization.PieChart(document.getElementById('divClaimSubmission'));
charta.draw(data3, options);
google.visualization.events.addListener(charta, 'select', function () {
debugger;
var selectedItem = charta.getSelection()[0];
if (selectedItem) {
var status = data3.getValue(selectedItem.row, 0);
CLAIMSUBMISSIONSTATUSPIECHARTDetail(status);
}
});
there is no documented option for changing the color of the legend marker line,
but you can change manually on the chart's 'ready' event
also, the only solution for ensuring a line exists for each slice is to increase the height of the chart
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['Billed', 19],
['Paid Up', 9],
['Not Billed', 2],
['Ready for Review', 15],
['Not Paid Up', 1]
]);
var options = {
chartArea: {
left: 12,
top: 12,
width: '85%'
},
colors: ['#3366cc', '#dc3912', '#ff9900', '#109618', '#990099', '#f44336', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3', '#03a9f4', '#00bcd4', '#009688', '#4caf50', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107', '#ff9800', '#ff5722', '#795548', '#9e9e9e', '#607d8b', '#000000', '#ffffff'],
legend: {
position: 'labeled'
}
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.PieChart(container);
var drawCount = 0;
var drawMax = 100;
google.visualization.events.addListener(chart, 'ready', function () {
var observer = new MutationObserver(function () {
var svg = container.getElementsByTagName('svg');
if (svg.length > 0) {
var legend = getLegend(svg[0]);
// check number of markers
if (legend.length !== data.getNumberOfRows()) {
// increase height & redraw chart
options.height = parseFloat(svg[0].getAttribute('height')) + 32;
drawCount++;
if (drawCount < drawMax) {
chart.draw(data, options);
}
} else {
// change legend marker colors
var colorIndex = 0;
legend.forEach(function (legendMarker) {
legendMarker.path.setAttribute('stroke', options.colors[colorIndex]);
if (legendMarker.hasOwnProperty('circle')) {
legendMarker.circle.setAttribute('fill', options.colors[colorIndex]);
}
colorIndex++;
if (colorIndex > options.colors.length) {
colorIndex = 0;
}
});
}
}
});
observer.observe(container, {
childList: true,
subtree: true
});
});
// get array of legend markers -- {path: pathElement, circle: circleElement}
function getLegend(svg) {
var legend = [];
Array.prototype.forEach.call(svg.childNodes, function(child) {
var group = child.getElementsByTagName('g');
Array.prototype.forEach.call(group, function(subGroup) {
var path = subGroup.getElementsByTagName('path');
if (path.length > 0) {
if (path[0].getAttribute('fill') === 'none') {
var legendMarker = {
path: path[0]
};
var circle = subGroup.getElementsByTagName('circle');
if (circle.length > 0) {
legendMarker.circle = circle[0];
}
legend.push(legendMarker);
}
}
});
});
return legend;
}
chart.draw(data, options);
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
notes:
1) need to use custom colors in order to keep the slice and line color in sync
2) a MutationObserver is required, the chart will revert on interactions, such as hover or select
3) manual changes will not be reflected when using chart method getImageURI
.SetXAxis(new XAxis
{
Categories = xyzList.ToArray(),
Labels = new XAxisLabels
{
// Formatter = "function() { return this.labels; }",
Style = "color: 'Black',fontSize: '10px',fontFamily: 'Arial'",
UseHTML = true,
//formatter with image is
Formatter = "function() { return '<div class=\"ImageDiv\" style=\"height:25px; background-image:url(../../Themes/Images/'+ this.value+'.jpg)\"/>';}",
// Formatter = "function() { return this.y;}",
}
})
i want to display YAxis value in to xAsix but it shows undefined.
How can i access YAxis value on the XAXis?
The answer depends on data format you are using. Possible solution: http://jsfiddle.net/3bQne/1036/
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
xAxis: {
categories: ['01/02/2012', '01/03/2012', '01/04/2012', '01/05/2012', '01/06/2012', '01/07/2012'],
labels: {
formatter: function () {
var index = this.axis.categories.indexOf(this.value);
var points = this.axis.series[0].options.data;
return points[index];
}
}
},
series: [{
data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0]
}]
});