swimlane / ngx-charts

:bar_chart: Declarative Charting Framework for Angular
https://swimlane.github.io/ngx-charts/
MIT License
4.29k stars 1.15k forks source link

Question: Is there a way to add vertical lines to line graph? Kind of like reference lines, but solid and vertical. #1460

Open wayneSt0ck opened 4 years ago

wayneSt0ck commented 4 years ago

Is your feature request related to a problem? Please describe. No problem, new feature.

Describe the solution you'd like Add an array to be allowed to specify a vertical line at location x that spans the entire plot view. Possibly allow a hover option to see what vertical lines mean. Ex) If I am grabbing temperature and humidity data over a period of time, I can add a vertical reference line that specifies when I might have changed the thermostat.

Describe alternatives you've considered I tried the combo graph to be able to do something similar with the bar graphs instead of lines. After following the guide to do this, I noticed I lost my timeline.

Additional context Add any other context or screenshots about the feature request here. image

wayneStock

heyteacher commented 4 years ago

I submitted pull request https://github.com/swimlane/ngx-charts/pull/1421 adding customize grid line based on x and y axis tick value.

stackblitz DEMO

There's a ngx-charts fork on npm with this PR (used in stackblitz DEMO)

npm i @heyteacher/ngx-charts
wayneSt0ck commented 4 years ago

Thanks heyteacher for the quick reply. Does this interfere with the timeline feature at all? Also, does this feature have a hover tip with the vertical line?

heyteacher commented 4 years ago

this PR only apply an ngStyle expression to vertical/horizontal line based on x/y tick value. It's only CSS so no hover tip. Furthermore, if you have a lot of values in x or y axis, ngx-charts show only some tick values and lines, and your line with a specific ngStyle could disappear.

You can customize tooltip overriding the tooltip template (https://stackblitz.com/edit/swimlane-line-chart-log-scale?file=app%2Fapp.component.html)

Or you can customize tick value using yAxisTickFormatting and xAxisTickFormatting decorators

wayneSt0ck commented 4 years ago

Ohh, I misunderstood your first post. The lines are corresponding to existing tick marks, making the line darker. I am more looking for something that would add a line regardless of tick intervals and could be seen even with 100s of data points.

ben-coble-sp commented 3 years ago

I achieved this capability by extending the chart (bar chart in my case) and then adding my own svg's for vertical lines. Then you can add your own tooltips or reuse the ngx-charts tooltips on your vertical lines. You'll have to do your own calculations to translate some input array of points to match locations on the chart.

mtpultz commented 3 years ago

@ben-coble-sp do you have an example of extending a chart? Trying to add vertical lines to an area chart as day boundaries, and having some issues figuring it out.

ben-coble-sp commented 3 years ago

Sorry I don't have time for a full gist. Here's a quick summary of what I did @mtpultz:

  1. Extend the ngx-charts component export class MyAreaChartComponent extends AreaChartComponent.
  2. Copy the ngx-charts' component template into your component https://github.com/swimlane/ngx-charts/blob/master/projects/swimlane/ngx-charts/src/lib/area-chart/area-chart.component.ts
  3. Add your custom SVG to the extended template with an id.
  4. Add a method to calculate the SVG coordinates. I recommend reading the source code for the area chart and the base chart to figure out what data is available to you when trying to draw your lines. If the chart does not have the information you need, you can always add another input. If the x-axis is in days, then getXDomain() might be a starting point. Ultimately, you'll need to map the x-axis values to a pixel value for the svg.
drawVerticalLine(xAxisPercentage: number) {
        const color = '#000';

                const y1 = 0;
        const y2 = 180; // I know my container height is hardcoded, you can do this in other ways if your height is responsive

        // My math is specifically for a single line that is at a percentage location on the x-axis
        // You will need some other way to map the days to a pixel value.
                 const yAxisLabelSize = 33.25;
        const margins = this.margin[1] * 2 + 3;
        const displayWidth = this.width - yAxisLabelSize - margins;
        const x = (xAxisPercentage / 100) * displayWidth;

        // update line
        select('#divider-line')
            .attr('x1', x)
            .attr('y1', y1)
            .attr('x2', x)
            .attr('y2', y2)
            .attr('stroke-width', 5)
            .attr('stroke', color);
        }
    }
mtpultz commented 3 years ago

Thanks @ben-coble-sp, I figured out how to calculate where the day boundaries and current time should be located by identifying between which dates they exist and doing a bit of a calculation. I got an example working in Ng2Charts fairly quick since we needed it out and then I'll switch it over NgxCharts since all our charts except this tidal chart use NgxCharts, but I had a few follow up questions.

I need to have x days worth of lines to indicate day boundaries so it seems like I have to generate them using an *ngFor, but can't seem to figure out how to get access to them using ViewChildren to get at the nativeElement to add attributes.

  1. Wondering if I should be using select, and how are providing it to the controller?, and
  2. When adding a line to the template are you simply adding <line x1="20" y1="0" x2="20" y2="100" stroke="black" /> or more specifically <line *ngFor="let day of days" [attr.id]="day.name" />? In Ng2Charts I was able to get a reference to the canvas and the API to add vertical lines, but I can't figure out how I should be doing this in NgxCharts. Don't know if you have any suggestions.
ben-coble-sp commented 3 years ago

I'm using a blank <line id="divider-line"></line> in the template and then import d3's select import { select } from 'd3-selection'; with the other component imports. Your *ngFor seems fine and I think you should be able to get references to them via select. You would need to loop over the days so that you can construct the ids properly if day.name is a date range and not just "Monday", "Tuesday", etc.

I think there should be a way to use ViewChildren if you really want to, but maybe there's something in the angular documentation that indicates problems when trying to grab svgs with it; I'm not sure.

jkoorts commented 2 years ago

I'm switching to ng2-charts for this feature. I'll come back if this is supported.

engineerbaraazakariya commented 6 months ago

I'm using a blank <line id="divider-line"></line> in the template and then import d3's select import { select } from 'd3-selection'; with the other component imports. Your *ngFor seems fine and I think you should be able to get references to them via select. You would need to loop over the days so that you can construct the ids properly if day.name is a date range and not just "Monday", "Tuesday", etc.

I think there should be a way to use ViewChildren if you really want to, but maybe there's something in the angular documentation that indicates problems when trying to grab svgs with it; I'm not sure.

Any Blitz for this? does it work in 2024? anyone was able to add such lines in ngx-charts? Can we add some event square/circle instead of Vertical line also like in this screenshot for example: Screen Shot 2024-03-13 at 14 35 32