Anystock comparisonMode same value in tooltip - tooltip

When using a stock chart, I am using the comparisonMode with a date. The value displayed by the crosshair is correct, but the value in the tooltip is the real value (not compared). How could I display the compared value instead?
As you can see on the picture, the compared value is 107.1 but the tooltip is displaying the actual value 893.5. I am using anychart 8.0.0

I'm glad to inform you that in the new version of AnyStock 8.1.0 the calculated change value is available right from the point information. It may be used in tooltips and legends. I guess this is exactly what you were looking for.
The example of using this feature you may find on this link.
Now the context of every point includes valueChange and valuePercentChange properties.

This feature requires a few additional lines of JS code, I prepared an example below to show how it works. Now compared value is shown in cross-hair label, in the tooltip, and in legend.
anychart.onDocumentReady(function() {
var dataTable = anychart.data.table();
dataTable.addData(get_dji_daily_short_data());
var firstMapping = dataTable.mapAs({'value': 1});
var secondMapping = dataTable.mapAs({'value': 3});
chart = anychart.stock();
var plot = chart.plot();
var series0 = plot.line(firstMapping);
var series1 = plot.line(secondMapping);
var yScale = plot.yScale();
// Set comparison mode.
yScale.comparisonMode("value");
var xScale = chart.xScale();
chart.container("container");
chart.draw();
//reference points of both series
var firstVisibleValue0 = null;
var firstVisibleValue1 = null;
//after chart rendering format tooltip and legend
getVisibleValues();
tooltipLegendFormat(firstVisibleValue0, firstVisibleValue1);
//after every scroll change recalculate reference points
//and reformat tooltip and legend
chart.scroller().listen('scrollerchange', function() {
getVisibleValues();
tooltipLegendFormat(firstVisibleValue0, firstVisibleValue1);
});
function getVisibleValues() {
// Gets scale minimum.
var minimum = xScale.getMinimum();
//select data from mappings
var selectable0 = firstMapping.createSelectable();
var selectable1 = secondMapping.createSelectable();
// Sets value for search.
var select0 = selectable0.search(minimum, "nearest");
var select1 = selectable1.search(minimum, "nearest");
// get values in first visible points
firstVisibleValue0 = select0.get('value');
firstVisibleValue1 = select1.get('value');
}
function tooltipLegendFormat(firstVisibleValue0, firstVisibleValue1) {
//format tooltips and legends of both series
series0.tooltip().format(function () {
return 'Series 0: ' + Math.round(this.value - firstVisibleValue0);
});
series0.legendItem().format(function(){
return 'Series 0: ' + Math.round(this.value - firstVisibleValue0);
});
series1.tooltip().format(function () {
return 'Series 1: ' + Math.round(this.value - firstVisibleValue1);
});
series1.legendItem().format(function(){
return 'Series 1: ' + Math.round(this.value - firstVisibleValue1);
});
}
});
html, body, #container {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
<script src="https://cdn.anychart.com/releases/8.0.1/js/anychart-base.min.js"></script>
<script src="https://cdn.anychart.com/releases/8.0.1/js/anychart-stock.min.js"></script>
<script src="https://cdn.anychart.com/releases/8.0.1/js/anychart-exports.min.js"></script>
<script src="https://cdn.anychart.com/releases/8.0.1/js/anychart-ui.min.js"></script>
<script src="https://cdn.anychart.com/csv-data/dji-daily-short.js"></script>
<link rel="stylesheet" href="https://cdn.anychart.com/releases/8.0.1/css/anychart-ui.min.css" />
<div id="container"></div>

Related

Add markers and polylines to a Leaflet map from destinations in a Google Sheet

I'm trying to create a Leaflet map, that automatically adds markers and polylines between destinations from a Google sheet.
I've managed to set up a map from other examples which is linked to my Google Sheet. You see the example here:
<!DOCTYPE html>
<html>
<head>
<script src='//cdn.jsdelivr.net/npm/tabletop#1.5.2/src/tabletop.min.js'></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css" />
<script src="//unpkg.com/leaflet#1.3.4/dist/leaflet.js"></script>
<style>
#map-div {
position: absolute;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="map-div"></div>
</body>
</html>
var map = L.map('map-div').setView([60.1682653, 24.9422078], 5);
var basemap = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Basemap (c) OpenStreetMap',
minZoom: 5,
maxZoom: 100
});
basemap.addTo(map);
function addPoints(data, tabletop) {
for (var row in data) {
var marker = L.marker([
data[row].Latitude,
data[row].Longitude
]).addTo(map);
marker.bindPopup('<strong>' + data[row].Info + '</strong>');
}
}
function init() {
Tabletop.init({
key: 'https://docs.google.com/spreadsheets/d/1Rs6xPlJ8pU4UFfmokjATaf4dArMWxQxZcyS-xRIIFuY/edit?usp=sharing',
callback: addPoints,
simpleSheet: true
})
}
init()
https://jsfiddle.net/Enounce/kwvn5e6z/12/
But unfortunately, I don't have the skills to make the map do what I want:
Draw lines between markers Draw lines between markers in leaflet
Zoom to fit all markers Zoom to Fit All Markers on LeafletJS Map
If possible, add an overview of all destinations, much like the directions panel in Google Maps. I haven't been able to find examples of this though.
I'm unsure if this is at all possible with the destinations being in an external source. Any help is appreciated!
Draw Line between markers:
You need to create a L.Polyline and add the latlngs to it:
function addPoints(data, tabletop) {
var line = L.polyline([]).addTo(map);
for (var row in data) {
var marker = L.marker([
data[row].Latitude,
data[row].Longitude
]).addTo(map);
line.addLatLng(marker.getLatLng());
marker.bindPopup('<strong>' + data[row].Info + '</strong>');
}
}
Zoom to fit all markers:
Add the markers to a L.FeatureGroup() and then you can fit the map bounds to the group bounds with map.fitBounds(fg.getBounds());
var fg = L.featureGroup().addTo(map);
function addPoints(data, tabletop) {
var line = L.polyline([]).addTo(map);
for (var row in data) {
var marker = L.marker([
data[row].Latitude,
data[row].Longitude
]).addTo(fg);
line.addLatLng(marker.getLatLng());
marker.bindPopup('<strong>' + data[row].Info + '</strong>');
}
map.fitBounds(fg.getBounds());
}
BUT you need to remove minZoom: 5 from the TileLayer.
Destinations
Store the destinations in an array and then create a html element in the loop and add a click listener:
var destinationHTML = document.getElementById("destinations-body");
var fg = L.featureGroup().addTo(map);
var destinations = [];
function addPoints(data, tabletop) {
var line = L.polyline([]).addTo(map);
for (var row in data) {
var marker = L.marker([
data[row].Latitude,
data[row].Longitude
]).addTo(fg);
line.addLatLng(marker.getLatLng());
marker.bindPopup('<strong>' + data[row].Info + '</strong>');
destinations.push({
marker,
data: data[row],
id: row
});
destinationHTML.innerHTML += "<div class='destination-elm' onclick='destinationClick(\""+row+"\")'><span>"+data[row].Info+"</span></div>"
}
map.fitBounds(fg.getBounds());
}
function destinationClick(id){
console.log(id)
destinations.forEach(function(obj){
if(obj.id == id){
map.panTo(obj.marker.getLatLng());
}
})
}
Example: https://jsfiddle.net/falkedesign/k3b4nups/

Adding data labels (annotations?) to Google Charts (Visualizations API) drawn from a query

I'm creating a line chart by querying data entered into a Google Sheet, and I need to add data labels, i.e. the little numbers next to the points on the chart. I found plenty of documentation on how to do this with charts drawn from a manually entered data-table, but not from a query to a Google Sheet. Please help.
google.charts.load('current', {'packages':['corechart', 'line']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var query = new google.visualization.Query(
'URL'
);
query.setQuery('SELECT A, B OFFSET 0'); //select specific cells from the table
query.send(handleQueryResponse);
}
function handleQueryResponse(response) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var data = response.getDataTable();
var options = {
title: '',
height : 250,
width : '100%',
}
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
correct, you want to add annotations.
this can be done using an annotation column role.
the annotation column role, should directly follow the series column it represents in the data table.
in this case, since you are getting the data from a query,
we can use a DataView to add the annotation using a calculated column.
first, we create the data view.
var view = new google.visualization.DataView(data);
then we use the setColumns method,
to add the column indexes from the query,
and our calculated column for the annotation.
view.setColumns([0, 1, {
calc: 'stringify',
sourceColumn: 1,
type: 'string',
role: 'annotation'
}]);
finally, we need to use the view to draw the chart.
chart.draw(view, options);
see following snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(drawChart);
function drawChart() {
var query = new google.visualization.Query(
'URL'
);
query.setQuery('SELECT A, B OFFSET 0'); //select specific cells from the table
query.send(handleQueryResponse);
}
function handleQueryResponse(response) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var data = response.getDataTable();
var options = {
title: '',
height : 250,
width : '100%',
};
// create data view with calculated annotation column
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: 'stringify',
sourceColumn: 1,
type: 'string',
role: 'annotation'
}]);
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(view, options); // <-- use view to draw the chart
}
Note: when using google.visualization.LineChart, you only need the 'corechart' package.
the 'line' package is for their material line chart --> google.charts.Line

Textarea functions don't work with contenteditable elements that are not textareas

I'm trying to make a scrollbar stay down with this function (Tampermonkey, on the website: 'https://dictation.io/speech'):
setInterval(function() {
document.getElementsByClassName('ql-editor').scrollTop = document.getElementsByClassName('ql-editor').scrollHeight;
}, 500);
It worked before on another website.
I've fixed the height of the text box, so this scrollbar appears when there is enough of text:
div.notepad {
height : 771px;
}
I've tried doing this:
setInterval(function() {
document.getElementById("speech").scrollTop = document.getElementById("speech").scrollHeight;
}, 500);
and this (to make it read only, but it also doesn't work):
document.getElementById("speech").readOnly = true;
document.getElementsByClassName("ql-editor").readOnly = true;
I'm simply trying to keep the scrollbar always down. And I tried all possible ids and classnames. It worked very well on another website (the textbox was such: <textarea class="-metrika-nokeys" name="docel" id="docel" style="width: 100%;" cols="80" rows="20" spellcheck="true"></textarea>). But nothing has any effect on the text box on this website.
Thank you for any help in advance!
P.S. The problem is universal. This code (and when it's ".ql-editor" instead of '#speech') also doesn't work:
var input = document.querySelector('#speech');
var textarea = document.querySelector('#speech');
var reset = function(e) {
var context = this;
setTimeout(function() {
var len = context.value.length;
context.setSelectionRange(len, len);
}, 100);
};
input.addEventListener('copy', reset, false);
textarea.addEventListener('copy', reset, false);
I was able to solve it (probably not the best solution) by creating a textarea, copying text there from the div, and applying all those functions to that textarea.
Here is the code:
Creating a textarea:
var div = document.getElementById("speech");
var input = document.createElement("textarea");
input.setAttribute("id", "normaltext");
input.name = "post";
input.cols = "80";
input.rows = "2";
div.appendChild(input); //appendChild
Copying everything from the div to the textarea:
setInterval(function copyText() {
$("#normaltext").val($(".ql-editor").text());
}, 100);
Applying functions:
var input1 = document.querySelector('#normaltext');
var textarea1 = document.querySelector('#normaltext');
var reset = function(e) {
var context = this;
setTimeout(function() {
var len = context.value.length;
context.setSelectionRange(len, len);
}, 100);
};
input1.addEventListener('copy', reset, false);
textarea1.addEventListener('copy', reset, false);
setInterval(function() {
document.getElementById("normaltext").scrollTop = document.getElementById("normaltext").scrollHeight;
}, 500);
That works for me, but maybe someone will come up with a better solution.

Highcharts - sync crosshair of charts with different width

I try to get a synced crosshair for multiple highcharts each with a different width.
For know the crosshair is syncing on the position of the cursor and not on the position of the point / the xAxis value (which would be prefered). Can anyone give me a hint how to achieve this?
I have changed the synced charts example in the following fiddle:
https://jsfiddle.net/3mn4x8uy/
The chart creation:
$.each(activity.datasets, function (i, dataset) {
// Add X values
dataset.data = Highcharts.map(dataset.data, function (val, j) {
return [activity.xData[j], val];
});
$('<div class="chart">')
.appendTo('#container')
.highcharts({
chart: {
marginLeft: 40+i*100, // make different width for each chart
spacingTop: 20,
spacingBottom: 20
},
sync code
$('#container').bind('mousemove touchmove touchstart', function (e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
// Find coordinates within the chart
event = chart.pointer.normalize(e.originalEvent);
// Get the hovered point
point = chart.series[0].searchPoint(event, true);
if (point) {
point.highlight(e);
}
}
});
Thanks
Here you can find an example how to synchronize multiple charts based on xAxis value: http://jsfiddle.net/BlackLabel/udtkgs9m/
The code to sync a Plotline over multiple Charts:
function syncronizeCrossHairs(chart) {
var container = jQuery(chart.container),
offset = container.offset(),
x, y;
container.mousemove(function(evt) {
x = evt.clientX - chart.plotLeft - offset.left;
y = evt.clientY - chart.plotTop - offset.top;
var val = chart.xAxis[0].translate(x, true);
Highcharts.each(Highcharts.charts, function (act_chart) {
var xAxis = act_chart.xAxis[0];
xAxis.removePlotLine("myPlotLineId");
xAxis.addPlotLine({
value: val,
width: 1,
color: 'red',
//dashStyle: 'dash',
id: "myPlotLineId"
});
});
});
}

Allow setting of jquery ui slider to above max value or below the min value

I have a jquery ui slider that is linked to a numerical textbox. The slider has a max and min value.
See ui slider with text box input or
Using knockout js with jquery ui sliders for a knockout js implementation.
My question is: is it possible to set the value of the slider to above the max or below the min?
If value is outside the range it is set to the max or min of the range:
$(element).slider("value", value);
So for example, say the slider represents the percentage of your monthly salary between 50 and 100. Monthly salary is set to 10000. If you slide the slider it will vary from 5000 to 10000, but I still want users to be able to input values outside of the range. So if the user inputs 12000 the slider will slide to max, and if the user inputs 2000 the slider will slide to the min.
You can accomplish this by overriding the _trimAlignValue function that I noted in my comment:
$.ui.slider.prototype._trimAlignValue = function (val) {
var step = (this.options.step > 0) ? this.options.step : 1,
valModStep = val % step,
alignValue = val - valModStep;
if (Math.abs(valModStep) * 2 >= step) {
alignValue += (valModStep > 0) ? step : (-step);
}
return parseFloat(alignValue.toFixed(5));
};
This will effect every slider on the page--if this isn't the desired effect you should wrap this functionality in your own plugin (I can provide an example that does that too, if need be).
This combined with your existing KnockoutJS custom binding seems to work well.
Example: http://jsfiddle.net/Aa5nK/7/
Adapted from the answer in Using knockout js with jquery ui sliders
<h2>Slider Demo</h2>
Savings:
<input data-bind="value: savings, valueUpdate: 'afterkeydown'"
/>
<div style="margin: 10px" data-bind="slider: savings, sliderOptions: {min: 0, max: 100, range: 'min', step: 1}"></div>
And here's the custom binding:
ko.bindingHandlers.slider = {
init: function (element, valueAccessor, allBindingsAccessor) {
var options = allBindingsAccessor().sliderOptions || {};
$(element).slider(options);
ko.utils.registerEventHandler(element, "slidechange", function (event, ui) {
var value = valueAccessor();
if(!(value < $(element).slider('option', 'min') || value > $(element).slider('option', 'max')))
{
valueAccessor(ui.value);
}
});
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$(element).slider("destroy");
});
ko.utils.registerEventHandler(element, "slide", function (event, ui) {
var observable = valueAccessor();
observable(ui.value);
});
},
update: function (element, valueAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor());
if (isNaN(value)) value = 0;
if (value < $(element).slider('option', 'min')) {
value = $(element).slider("option", "min");
} else if (value > $(element).slider('option', 'max')) {
value = $(element).slider("option", "max");
}
$(element).slider("value", value);
}
};
var ViewModel = function () {
var self = this;
self.savings = ko.observable(10);
self.spent = ko.observable(5);
self.net = ko.computed(function () {
return self.savings() - self.spent();
});
};
ko.applyBindings(new ViewModel());
I adapted the jsFiddle from that answer too.

Resources