Custom invert function for D3 for scaleband - javascript

Ive been trying to make persistent tooltip by drawing a layer over the graph and track the tooltip based on mouse position. Unfortunately I kept getting an error on line xScaleFunc.invert(d3.mouse(this)[0]). Then i came across this custom invert code for scaleband scales. From here : https://bl.ocks.org/shimizu/808e0f5cadb6a63f28bb00082dc8fe3f .
The question is i'm not understanding whats going on here.I'm kinda new to D3 , any help would be much appreciated.
xScaleFunc.invert = (function(){
var domain = xScaleFunc.domain()
var range = xScaleFunc.range()
var scale = d3.scaleQuantize().domain(range).range(domain)
return function(x){
return scale(x)
}
})()

Related

Blazor chart vertical line

I'm trying hard to make dashboard with Blazor. But I'm new to js and css so feel some hard.
Currently I'm implementing chart components and I'd like to add vertical line which is moved automatically like below image.
I searched a lot of pages, however I didn't even know what to do.
I'm not asking you to write code, but it would be nice to tell me about sites, methods or libraries that I can refer to.
Situation
I'm using Blazorise Chart .net core 5.0
My tries
Create a data set to be expressed like a vertical line, set a timer, and move the vertical line data once per second.(The StateHasChange() function should be continues to be called.
Draw vertical line using css(But I couldn't know how to move it)
Thank you for reading.
Since Blazorise uses ChartJs internally to draw the charts, you might be able to use the ChartJs annotation plugin. You might need to leverage a JavaScript Interop method to inject the plugin options.
Alternatively you can simply draw the line yourself, as the Chart renders in a <canvas /> element:
Heres a piece of code i use (Personally I use ChartJs.Blazor, and my chart is a Bar chart, so you will need to adapt the code to fit your own needs and library)
annotationConfig: function (canvasID, indexToDrawAt) {
var originalLineDraw = Chart.controllers.bar.prototype.draw;
Chart.helpers.extend(Chart.controllers.bar.prototype, {
draw: function () {
originalLineDraw.apply(this, arguments);
var chart = this.chart;
var ctx = chart.chart.ctx;
var index = chart.config.options.lineAtIndex;
if (index) {
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-0'];
var x1 = xaxis.left;
var y1 = yaxis.getPixelForValue(index);
var x2 = xaxis.right;
var y2 = yaxis.getPixelForValue(index);
ctx.save();
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.strokeStyle = '#3C3E4F';
ctx.lineTo(x2, y2);
ctx.stroke();
ctx.restore();
}
}
});
let chart = window.ChartJsInterop.BlazorCharts.get(canvasID);
chart.options.lineAtIndex = indexToDrawAt;
chart.update();
}
This code adds a option to the chart called lineAtIndex, which when set, draws a line across the canvas at the provided index.
I use the method as such:
if (ShowAvgLine)
{
if (currentAverage != 0.0)
{
jSRuntime.InvokeVoidAsync("generalInterop.annotationConfig", _config.CanvasId, currentAverage);
}
}
If you get the above to work with your library, you might try your previous solution of making timed calls to the interop method to move it.
I don´t know Blazorise Chart, maybe there is also a built in solution.
If you want to solve it in a pretty hacky way, you could just create a <div> which has the same height as your chart. Then you can use the top and left CSS properties to set the div at the leftmost position over the chart (you may have to give the div a z-index and a position: absolute so that it appears over the chart). The positions should be saved in a C# variable. Now you can implement a function which gets called every second which increments the left value and calls the StateHasChanged() method.
This is a really hacky solution but it should work as expected. But you have to beware, that on different devices the chart can be displayed in a other way, so maybe the div won´t align anymore.

Cytoscape.js zigzag like edges

I am trying to create a zigzag like edges in cytoscape.js. I have found zigzag edges on github but I guess it's not yet implemented or it's abandoned, so I am trying to calculate the points but I am having some trouble.
My graph looks like this:
I assume that there are 3 cases here. One when the source is on the left of the target, other when the source and target have same x value and the third case when the source is on the right of the target.
The second case is basic and I have calculated it (just a straight line from source to the target) but I am having trouble calculating the other two cases.
I am trying to make the edges look like this:
I am using the following function to try to calculate them:
cy.elements('edge').css({'segment-distances':
function(ele){
var target = ele.target();
var source = ele.source();
var source_id = source.data().id;
var target_id = target.data().id;
var sou_pos_x = (cy.$('#' + source_id).position('x'));
var tar_pos_x = (cy.$('#' + target_id).position('x'));
var sou_pos_y = (cy.$('#' + source_id).position('y'));
var tar_pos_y = (cy.$('#' + target_id).position('y'));
var sou_tar_distance_x = (sou_pos_x - tar_pos_x);
var sou_tar_distance_y = (sou_pos_y - tar_pos_y);
// source on the left of the target
if (sou_pos_x < tar_pos_x){
return 0;
}
// source on same position as target
else if (sou_pos_x == tar_pos_x){
return 0;
}
// source on the right of the target
else{
return 0;
}
}
});
From what I have read from the documentation on segments-edges, I should have 2 points.
The calculation would have been a lot easier if you could specify coordinates for each segment point. With the way that is right now it's hard to calculate the values perpendicular to the line formed from the source to the target because those values might vary depending how far apart is the source from the target node
Can anyone help me with this issue or at least give me a guidance on how to achieve what I am looking for? I have been stuck with this problem for quite some time.
EDIT
I have added:
'source-endpoint': '180deg',
'target-endpoint': '0deg'
so now the all the edges start and end from same position, which would simplify the calculation.
EDIT 2:
This has been implemented by taxi edges like this

Change default node shape in dagre-d3

I'm using dagre-d3 to display directed graphs in a Javascript application, and its default node shape is a rectangle. I'd prefer ellipses, but it's not at all obvious to me if there's a programmatic way of changing the default (I'd rather not hack up NODE_DEFAULT_ATTRS in render.js, for example). Any suggestions? Thanks for your attention.
I did a little experimenting, and came up with an approach that doesn't seem too clumsy. Basically, I walked the graph's nodes and set their shapes before handing the graph off to dagreD3.render.
var g = graphlibDot.read(treeData);
g.nodes().forEach(function(v) {
var node = g.node(v);
node.shape = "ellipse";
});
var render = new dagreD3.render();
var svg = document.querySelector('#graphContainer');
render(d3.select("svg g"), g);
You can set the shape when you create the node:
g.setNode(id, { shape: 'ellipse' });

HighCharts: How to draw a straight line in multiple axes like plotLines with fixed X-axis with different values

I'm using highcharts for my project. I've used multiple axes for drawing the chart. What I want is there should be a straight line on fixed x-axis even though with different values.
I want to have something like plotLines which will be straight and fixed on the x-axis but still shows different values I put it.
I would create separate series to achieve that. I think it's simpler solution than playing around with renderer. Demo: http://jsfiddle.net/6wo5mzo4/
(function(H) {
var seriesTypes = H.seriesTypes;
seriesTypes.fakeLine = Highcharts.extendClass(seriesTypes.line);
seriesTypes.fakeLine.prototype.translate = function() {
var s = this;
seriesTypes.line.prototype.translate.call(s);
H.each(s.points, function(point) {
point.plotY = s.chart.plotWidth / 2; // display in the middle - note: plotWidth, not plotHeight, because chart is inverted
});
}
})(Highcharts);
However, I still have doubts how useful such chart will be. I would also suggest to review the requirements.

Dynamic overiding of measure axes in dimple.js causing floating droplines

eI am creating charts in dimple.js using a dynamic data set. To do this I am using addMeasureAxis for both x and y.
My problem is that I want to change the range of these axes since having the axis cross at the origin often leave my points all in the corner of the graph. To solve this I try set the x/y axis minima to the lowest value of my data by axis.overrideMin.
This gives me a graph scaled better to my data but the axes minima are still not what I had set, instead are slightly lower. As such when I mouseover the drop-lines do not reach the axis, rather they stop at my overrideMin value. Am I overriding incorrectly or can I extend where the drop-lines go to.
$scope.svg = new dimple.newSvg("dimple-chart", 800, 600);
$scope.chart = new dimple.chart($scope.svg, $scope.chartData);
$scope.chart.data = $scope.chartData;
$scope.chart.setBounds(60, 30, 500, 330);
var x,y,dataSeries;
x = $scope.chart.addMeasureAxis("x", xStatProperty);
y = $scope.chart.addMeasureAxis("y", yStatProperty);
$scope.chartData = _.sortBy($scope.chartData, xStatProperty); \\Sorts data
x.overrideMin = $scope.chartData[0][xStatProperty]; \\Overides to min value
$scope.chartData = _.sortBy($scope.chartData, yStatProperty);
y.overrideMin = $scope.chartData[0][yStatProperty];
dataSeries = $scope.chart.addSeries("Team", dimple.plot.bubble);
$scope.chart.draw();
There is nothing wrong with the approach you are using to override, it sounds like you might be using an old version of the library. Updating to version 2.1 should fix this problem.
Edit:
Following your comment below I've done some more investigation and this is caused by axis value rounding. Here is an example of the problem:
http://jsbin.com/ricud/2/edit?js,output
In order to ensure that the axes finish on a labelled point, dimple will round the axes to the next ticked value, this probably shouldn't be the case for overridden axes so please create an issue in Git Hub for that.
It's tricky to work around in a flexible way because you need to know the granularity of the axis. The example above could be fixed by using a floor calculation:
http://jsbin.com/ricud/3/edit?js,output
But that wouldn't work if the axis looked like this:
http://jsbin.com/ricud/4/edit?js,output
The only workaround I can think of relies on some internal API knowledge so is pretty hacky but I think this will work for all cases:
chart.draw();
if (x.overrideMin > 0) {
x._origin = chart._xPixels();
}
if (y.overrideMin > 0) {
y._origin = chart._yPixels() + chart._heightPixels();
}
http://jsbin.com/ricud/7/edit?js,output

Categories

Resources