tooltips and zero-lines

This commit is contained in:
HojouFotytu 2024-01-30 18:38:19 +09:00
parent f54109a3b3
commit aff5ec85fa
7 changed files with 183 additions and 128 deletions

View File

@ -162,7 +162,7 @@ else
<th>Name</th>
<th class="text-right">Markets</th>
<th class="text-right">Timeframe</th>
<th class="text-right">Threshold <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Pairs exceeding this threshold are excluded from the trend average."></i></th>
<th class="text-right">Threshold <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Pairs exceeding this threshold are considered outliers that are excluded from the trend average."></i></th>
<th class="text-right">Change</th>
</tr>
</thead>
@ -390,15 +390,51 @@ else
@if (!Model.TrendChartDataJSON.Equals("")) {
<text>
nv.addGraph(function () {
var lineChart = nv.models.lineChart();
lineChart = nv.models.lineChart();
var height = 300;
var chartData = @Html.Raw(Model.TrendChartDataJSON);
lineChart.useInteractiveGuideline(true);
lineChart.xAxis.tickFormat(function (d) { return d3.time.format('%H:%M')(new Date(d)); });
lineChart.yAxis.axisLabel('Trend %').tickFormat(d3.format(',.2f'));
d3.select('.trend-chart svg').attr('perserveAspectRatio', 'xMinYMid').datum(chartData).transition().duration(500).call(lineChart);
//nv.utils.windowResize(lineChart.update); v1.3.0 => Removed this line to prevent memory leak
lineChart.dispatch.on('renderEnd', function() {
// Get the chart's container
var container = d3.select('.trend-chart .nv-wrap.nv-lineChart .nv-linesWrap');
// Get the x-values of the first and last data points
var xRange = lineChart.xAxis.scale().range();
var xMin = xRange[0];
var xMax = xRange[1];
// Add a line at y=0
container.insert('line', ':first-child')
.attr('x1', xMin) // x position of the first end of the line
.attr('y1', lineChart.yAxis.scale()(0)) // y position of the first end of the line
.attr('x2', xMax) // x position of the second end of the line
.attr('y2', lineChart.yAxis.scale()(0)) // y position of the second end of the line
.attr('stroke', 'gray') // color of the line
.attr('stroke-width', 2); // width of the line
});
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.trend-chart').on('mouseleave', function() {
d3.select('.nvtooltip').remove();
});
d3.select('.trend-chart').on('mousemove', function() {
var chartBounds = d3.select('.trend-chart')[0][0].getBoundingClientRect();
var mouseX = d3.event.clientX;
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').remove();
}
});
return lineChart;
});
</text>

View File

@ -396,7 +396,7 @@
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.sales-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
d3.select('.nvtooltip').remove();
});
d3.select('body').on('mousemove', function() {
@ -405,7 +405,7 @@
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
d3.select('.nvtooltip').remove();
}
});
nv.utils.windowResize(salesChart.update);
@ -444,7 +444,7 @@
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.cumulative-profit-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
d3.select('.nvtooltip').remove();
});
d3.select('body').on('mousemove', function() {
@ -453,7 +453,7 @@
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
d3.select('.nvtooltip').remove();
}
});
nv.utils.windowResize(cumulativeProfitChart.update);
@ -492,7 +492,7 @@
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.TCV-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
d3.select('.nvtooltip').remove();
});
d3.select('body').on('mousemove', function() {
@ -501,7 +501,7 @@
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
d3.select('.nvtooltip').remove();
}
});
nv.utils.windowResize(TCVChart.update);
@ -538,9 +538,32 @@
.transition().duration(0)
.call(profitChart);
profitChart.dispatch.on('renderEnd', function() {
// Get the chart's container
var container = d3.select('.profit-chart .nv-wrap.nv-lineChart .nv-linesWrap');
// Check if profitData[0].values is not empty
if (profitData[0].values.length > 0) {
// Get the x-values of the first and last data points
var xMin = profitChart.xAxis.scale()(profitData[0].values[0].x);
var xMax = profitChart.xAxis.scale()(profitData[0].values[profitData[0].values.length - 1].x);
// Add a line at y=0
container.insert('line', ':first-child')
.attr('x1', xMin) // x position of the first end of the line
.attr('y1', profitChart.yAxis.scale()(0)) // y position of the first end of the line
.attr('x2', xMax) // x position of the second end of the line
.attr('y2', profitChart.yAxis.scale()(0)) // y position of the second end of the line
.attr('stroke', 'gray') // color of the line
.attr('stroke-width', 2); // width of the line
}
});
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.profit-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
d3.select('.nvtooltip').remove();
});
d3.select('body').on('mousemove', function() {
@ -549,7 +572,7 @@
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
d3.select('.nvtooltip').remove();
}
});
nv.utils.windowResize(profitChart.update);

View File

@ -48,18 +48,12 @@ namespace Monitor.Pages
// Read the new settings
PTMagicConfiguration.GeneralSettings.Application.IsEnabled = HttpContext.Request.Form["Application_IsEnabled"].Equals("on");
PTMagicConfiguration.GeneralSettings.Application.TestMode = HttpContext.Request.Form["Application_TestMode"].Equals("on");
//PTMagicConfiguration.GeneralSettings.Application.StartBalance = SystemHelper.TextToDouble(HttpContext.Request.Form["Application_StartBalance"], PTMagicConfiguration.GeneralSettings.Application.StartBalance, "en-US");
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerDefaultSettingName = HttpContext.Request.Form["Application_ProfitTrailerDefaultSettingName"];
PTMagicConfiguration.GeneralSettings.Application.Exchange = HttpContext.Request.Form["Application_Exchange"];
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerMonitorURL = HttpContext.Request.Form["Application_ProfitTrailerMonitorURL"];
PTMagicConfiguration.GeneralSettings.Application.ProfitTrailerServerAPIToken = HttpContext.Request.Form["Application_ProfitTrailerServerAPIToken"];
//PTMagicConfiguration.GeneralSettings.Application.TimezoneOffset = HttpContext.Request.Form["Application_TimezoneOffset"];
//PTMagicConfiguration.GeneralSettings.Application.MainFiatCurrency = HttpContext.Request.Form["Application_MainFiatCurrency"];
PTMagicConfiguration.GeneralSettings.Application.FloodProtectionMinutes = SystemHelper.TextToInteger(HttpContext.Request.Form["Application_FloodProtectionMinutes"], PTMagicConfiguration.GeneralSettings.Application.FloodProtectionMinutes);
PTMagicConfiguration.GeneralSettings.Application.InstanceName = HttpContext.Request.Form["Application_InstanceName"];
PTMagicConfiguration.GeneralSettings.Application.CoinMarketCapAPIKey = HttpContext.Request.Form["Application_CoinMarketCapAPIKey"];
//PTMagicConfiguration.GeneralSettings.Application.FreeCurrencyConverterAPIKey = HttpContext.Request.Form["Application_FreeCurrencyConverterAPIKey"];
PTMagicConfiguration.GeneralSettings.Monitor.IsPasswordProtected = HttpContext.Request.Form["Monitor_IsPasswordProtected"].Equals("on");
PTMagicConfiguration.GeneralSettings.Monitor.OpenBrowserOnStart = HttpContext.Request.Form["Monitor_OpenBrowserOnStart"].Equals("on");
PTMagicConfiguration.GeneralSettings.Monitor.AnalyzerChart = HttpContext.Request.Form["Monitor_AnalyzerChart"];

View File

@ -21,7 +21,7 @@
totalCurrentValueString = Math.Round(Model.totalCurrentValue, 2).ToString("#,#0.00", new System.Globalization.CultureInfo("en-US"));
}
}
<div id="AssetDistribution" class="container" style="height: 100%; width: 100%;">
<div class="asset-distribution container" style="height: 100%; width: 100%;">
<div class="text-center">
<span data-toggle="tooltip" data-placement="top" title="Total current account value">TCV: <text class="text-autocolor">@totalCurrentValueString @Model.Summary.MainMarket </text> </span>
</div>
@ -96,7 +96,7 @@
<th>Name</th>
<th class="text-right">Markets</th>
<th class="text-right">Timeframe</th>
<th class="text-right">Threshold&nbsp;&nbsp;<i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Pairs exceeding this threshold are excluded from the trend average."></i>
<th class="text-right">Threshold&nbsp;&nbsp;<i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Pairs exceeding this threshold are considered outliers that are excluded from the trend average."></i>
</th>
<th class="text-right">Change</th>
</tr>
@ -324,28 +324,13 @@
assetDistributionData = @Html.Raw(Model.AssetDistributionData);
d3.select("#AssetDistribution svg")
d3.select(".asset-distribution svg") // Change this line
.style('height', '90%')
.style('width', '100%')
.datum(assetDistributionData)
.transition().duration(0)
.call(assetDistributionChart);
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.profit-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
});
d3.select('body').on('mousemove', function() {
var chartBounds = d3.select('.profit-chart')[0][0].getBoundingClientRect();
var mouseX = d3.event.clientX;
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
}
});
nv.utils.windowResize(assetDistributionChart.update);
return assetDistributionChart;
});
@ -375,24 +360,34 @@
trendData = @Html.Raw(Model.TrendChartDataJSON);
d3.select('.trend-chart svg')
var svg = d3.select('.trend-chart svg').node();
d3.select(svg)
.datum(trendData)
.transition().duration(0)
.call(trendChart);
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.profit-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
trendChart.dispatch.on('renderEnd', function() {
// Get the chart's container
var container = d3.select('.trend-chart .nv-wrap.nv-lineChart .nv-linesWrap');
// Get the x-values of the first and last data points
var xRange = trendChart.xAxis.scale().range();
var xMin = xRange[0];
var xMax = xRange[1];
// Add a line at y=0
container.insert('line', ':first-child')
.attr('x1', xMin) // x position of the first end of the line
.attr('y1', trendChart.yAxis.scale()(0)) // y position of the first end of the line
.attr('x2', xMax) // x position of the second end of the line
.attr('y2', trendChart.yAxis.scale()(0)) // y position of the second end of the line
.attr('stroke', 'gray') // color of the line
.attr('stroke-width', 2); // width of the line
});
d3.select('body').on('mousemove', function() {
var chartBounds = d3.select('.profit-chart')[0][0].getBoundingClientRect();
var mouseX = d3.event.clientX;
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
}
});
nv.utils.windowResize(trendChart.update);
return trendChart;
});
@ -427,20 +422,27 @@
.transition().duration(0)
.call(profitChart);
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.profit-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
});
profitChart.dispatch.on('renderEnd', function() {
// Get the chart's container
var container = d3.select('.profit-chart .nv-wrap.nv-lineChart .nv-linesWrap');
d3.select('body').on('mousemove', function() {
var chartBounds = d3.select('.profit-chart')[0][0].getBoundingClientRect();
var mouseX = d3.event.clientX;
var mouseY = d3.event.clientY;
// Check if profitData[0].values is not empty
if (profitData[0].values.length > 0) {
// Get the x-values of the first and last data points
var xMin = profitChart.xAxis.scale()(profitData[0].values[0].x);
var xMax = profitChart.xAxis.scale()(profitData[0].values[profitData[0].values.length - 1].x);
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
// Add a line at y=0
container.insert('line', ':first-child')
.attr('x1', xMin) // x position of the first end of the line
.attr('y1', profitChart.yAxis.scale()(0)) // y position of the first end of the line
.attr('x2', xMax) // x position of the second end of the line
.attr('y2', profitChart.yAxis.scale()(0)) // y position of the second end of the line
.attr('stroke', 'gray') // color of the line
.attr('stroke-width', 2); // width of the line
}
});
nv.utils.windowResize(profitChart.update);
return profitChart;
});
@ -451,31 +453,10 @@
<script type="text/javascript">
$(document).ready(function(){
var originalLeave = $.fn.tooltip.Constructor.prototype.leave;
$.fn.tooltip.Constructor.prototype.leave = function(obj){
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type);
var container, timeout;
originalLeave.call(this, obj);
if(obj.currentTarget) {
container = $(obj.currentTarget).siblings('.tooltip');
timeout = self.timeout;
container.one('mouseenter', function(){
//We entered the actual tooltip call off the dogs
clearTimeout(timeout);
//Let's monitor tooltip content instead
container.one('mouseleave', function(){
$.fn.tooltip.Constructor.prototype.leave.call(self, self);
});
});
}
};
$('[data-toggle="tooltip"]').tooltip();
});
</script>
<script type="text/javascript">
(function ($) {
'use strict';
@ -502,20 +483,7 @@
.transition().duration(0)
.call(TCVLiveChart);
// Add mouseleave, and mousemove event listeners to hide tooltip
d3.select('.TCVLive-chart').on('mouseleave', function() {
d3.select('.nvtooltip').style('opacity', 0);
});
d3.select('body').on('mousemove', function() {
var chartBounds = d3.select('.TCVLive-chart')[0][0].getBoundingClientRect();
var mouseX = d3.event.clientX;
var mouseY = d3.event.clientY;
if (mouseX < chartBounds.left || mouseX > chartBounds.right || mouseY < chartBounds.top || mouseY > chartBounds.bottom) {
d3.select('.nvtooltip').style('opacity', 0);
}
});
nv.utils.windowResize(TCVLiveChart.update);
return TCVLiveChart;
});
@ -523,3 +491,35 @@
}
})(jQuery);
</script>
<script type="text/javascript">
function attachTooltipRemoval(chartClass) {
d3.selectAll(chartClass).on('mouseleave', function() {
var tooltip = d3.select(this).select('.nvtooltip');
if (!tooltip.empty()) {
tooltip.style('opacity', 0);
}
});
d3.selectAll(chartClass).on('mouseenter', function() {
var tooltip = d3.select(this).select('.nvtooltip');
if (!tooltip.empty()) {
tooltip.style('opacity', 1);
}
});
}
$(document).ready(function () {
// Hide all tooltips when the page is loaded
d3.selectAll('.nvtooltip').style('opacity', 0);
// Call the function for each chart
attachTooltipRemoval('.asset-distribution svg');
attachTooltipRemoval('.trend-chart svg');
attachTooltipRemoval('.profit-chart svg');
attachTooltipRemoval('.TCVLive-chart svg');
// Add other charts as needed
});
</script>

View File

@ -78,7 +78,7 @@
</div>
<div class="form-group row">
<label class="col-md-4 col-form-label">Trend Threshold <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Exclude coins above/below this value when calculing market trend average."></i></label>
<label class="col-md-4 col-form-label">Trend Threshold <i class="fa fa-info-circle text-muted" data-toggle="tooltip" data-placement="top" title="Exclude coins above/below this value as outliers, when calculing market trend average."></i></label>
<div class="col-md-8">
<input type="text" class="form-control" name="MarketAnalyzer_MarketTrend_@(Model.MarketTrendName)|TrendThreshold" value="@Model.MarketTrend.TrendThreshold.ToString()">
<span class="help-block"><small>Leave empty to exclude none</small></span>

View File

@ -22,7 +22,8 @@
"TrendCurrency": "Market", // Trend Currency to build the trend against. If set to "Fiat", the trend will
// take the USD value of your main currency into account to build the trend.
// "Market" will build a trend against your base currency, such as BTC or USDT.
"TrendThreshold": 15, // Any coin that is above 15% or below -15% for this timeframe will not be used when calculating the market average.
"TrendThreshold": 15, // Any coin that is above 15% or below -15% for this timeframe will be considered an outlier,
// and not used when calculating the market average.
"DisplayGraph": false, // Use this trend in the graph on the PTM Monitor dashboard and market analyzer
"DisplayOnMarketAnalyzerList": false // Disply this trend for all coins on the PTM Monitor market analyzer
},

View File

@ -22,7 +22,8 @@
"TrendCurrency": "Market", // Trend Currency to build the trend against. If set to "Fiat", the trend will
// take the USD value of your main currency into account to build the trend.
// "Market" will build a trend against your base currency, such as BTC or USDT.
"TrendThreshold": 15, // Any coin that is above 15% or below -15% for this timeframe will not be used when calculating the market average.
"TrendThreshold": 15, // Any coin that is above 15% or below -15% for this timeframe will be considered an outlier,
// and not used when calculating the market average.
"DisplayGraph": false, // Use this trend in the graph on the PTM Monitor dashboard and market analyzer
"DisplayOnMarketAnalyzerList": false // Disply this trend for all coins on the PTM Monitor market analyzer
},