From 3da50d3a1dbeefb3a6b56bfdd422ddee846d924e Mon Sep 17 00:00:00 2001 From: Hannah Cushman Garland Date: Tue, 1 Oct 2024 11:44:40 -0500 Subject: [PATCH 01/10] Revise contribution/expenditure chart as a true area chart --- .pre-commit-config.yaml | 15 - camp_fin/models.py | 126 +---- camp_fin/static/js/chart_helper.js | 821 +++++++++++++++-------------- 3 files changed, 462 insertions(+), 500 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d231b91..6671882 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,21 +25,6 @@ repos: files: .*/templates/.*\.html$ args: [--tabwidth=2] # tabs should be 2 spaces in Django templates - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.5.1 - hooks: - - id: prettier - files: \.(js|ts|jsx|tsx|css|less|json|markdown|md|yaml|yml)$ - - - repo: https://github.com/pre-commit/mirrors-eslint - rev: "1f7d592" - hooks: - - id: eslint - additional_dependencies: - - eslint@8.19.0 - - eslint-plugin-react@7.30.1 - - eslint-config-prettier@8.5.0 - - repo: https://github.com/pycqa/isort rev: 5.13.2 hooks: diff --git a/camp_fin/models.py b/camp_fin/models.py index 92b346d..510c1de 100644 --- a/camp_fin/models.py +++ b/camp_fin/models.py @@ -1,7 +1,6 @@ from collections import namedtuple from datetime import datetime -from dateutil.rrule import MONTHLY, rrule from django.db import connection, models from django.utils import timezone from django.utils.translation import gettext as _ @@ -944,52 +943,6 @@ def trends(self, since="2010"): Generate a dict of filing trends for use in contribution/expenditure charts for this Entity. """ - - def stack_trends(trend): - """ - Private helper method for compiling trends. - """ - stacked_trend = [] - for begin, end, rate in trend: - if not stacked_trend: - stacked_trend.append((rate, begin)) - stacked_trend.append((rate, end)) - - elif begin == stacked_trend[-1][1]: - stacked_trend.append((rate, begin)) - stacked_trend.append((rate, end)) - - elif begin > stacked_trend[-1][1]: - previous_rate, previous_end = stacked_trend[-1] - stacked_trend.append((previous_rate, begin)) - stacked_trend.append((rate, begin)) - stacked_trend.append((rate, end)) - - elif begin < stacked_trend[-1][1]: - previous_rate, previous_end = stacked_trend.pop() - stacked_trend.append((previous_rate, begin)) - stacked_trend.append((rate + previous_rate, begin)) - - if end < previous_end: - stacked_trend.append((rate + previous_rate, end)) - stacked_trend.append((previous_rate, end)) - stacked_trend.append((previous_rate, previous_end)) - - elif end > previous_end: - stacked_trend.append((rate + previous_rate, previous_end)) - stacked_trend.append((rate, previous_end)) - stacked_trend.append((rate, end)) - else: - stacked_trend.append((rate + previous_rate, end)) - - flattened_trend = [] - - for i, point in enumerate(stacked_trend): - rate, date = point - flattened_trend.append([rate, *date]) - - return flattened_trend - # Balances and debts summed_filings = """ SELECT @@ -1065,68 +1018,43 @@ def stack_trends(trend): # Donations and expenditures monthly_query = """ SELECT - {table}.amount AS amount, - {table}.month AS month - FROM {table}_by_month AS {table} - WHERE {table}.entity_id = %s - AND {table}.month >= '{year}-01-01'::date - ORDER BY month + months.year, + months.month, + {table}.amount + FROM ( + SELECT + DISTINCT DATE_PART('year', month) AS year, + GENERATE_SERIES(1, 12) AS month + FROM {table}_by_month + ORDER BY year, month + ) months + LEFT JOIN ( + SELECT + {table}.amount AS amount, + DATE_PART('month', {table}.month) AS month, + DATE_PART('year', {table}.month) AS year + FROM {table}_by_month AS {table} + WHERE {table}.entity_id = %s + AND {table}.month >= '{year}-01-01'::date + ) {table} + USING (year, month) """ contributions_query = monthly_query.format(table="contributions", year=since) - expenditures_query = monthly_query.format(table="expenditures", year=since) cursor.execute(contributions_query, [self.id]) - columns = [c[0] for c in cursor.description] - amount_tuple = namedtuple("Amount", columns) + donation_trend = [ + [amount or 0, year, month, 1] for year, month, amount in cursor + ] - contributions = [amount_tuple(*r) for r in cursor] + expenditures_query = monthly_query.format(table="expenditures", year=since) cursor.execute(expenditures_query, [self.id]) - columns = [c[0] for c in cursor.description] - amount_tuple = namedtuple("Amount", columns) - - expenditures = [amount_tuple(*r) for r in cursor] - - donation_trend, expend_trend = [], [] - - if contributions or expenditures: - contributions_lookup = {r.month.date(): r.amount for r in contributions} - expenditures_lookup = {r.month.date(): r.amount for r in expenditures} - - start_month = datetime(int(since), 1, 1) - - end_month = ( - self.filing_set.order_by("-filed_date").first().filed_date.date() - ) - - for month in rrule(freq=MONTHLY, dtstart=start_month, until=end_month): - replacements = {"month": month.month - 1} - - if replacements["month"] < 1: - replacements["month"] = 12 - replacements["year"] = month.year - 1 - - begin_date = month.replace(**replacements) - - begin_date_array = [begin_date.year, begin_date.month, begin_date.day] - - end_date_array = [month.year, month.month, month.day] - - contribution_amount = contributions_lookup.get(month.date(), 0) - expenditure_amount = expenditures_lookup.get(month.date(), 0) - - donation_trend.append( - [begin_date_array, end_date_array, contribution_amount] - ) - expend_trend.append( - [begin_date_array, end_date_array, (-1 * expenditure_amount)] - ) - - donation_trend = stack_trends(donation_trend) - expend_trend = stack_trends(expend_trend) + expend_trend = [ + [(amount or 0) * -1, year, month, 1] for year, month, amount in cursor + ] output_trends["donation_trend"] = donation_trend output_trends["expend_trend"] = expend_trend diff --git a/camp_fin/static/js/chart_helper.js b/camp_fin/static/js/chart_helper.js index 7212ae7..cd81a4b 100644 --- a/camp_fin/static/js/chart_helper.js +++ b/camp_fin/static/js/chart_helper.js @@ -1,5 +1,12 @@ var ChartHelper = {}; -ChartHelper.donations = function(el, title, sourceTxt, yaxisLabel, data, pointInterval) { +ChartHelper.donations = function ( + el, + title, + sourceTxt, + yaxisLabel, + data, + pointInterval +) { // console.log("rendering to: #chart_" + iteration); // console.log("title: " + title); // console.log("sourceTxt: " + sourceTxt); @@ -14,434 +21,476 @@ ChartHelper.donations = function(el, title, sourceTxt, yaxisLabel, data, pointIn // var selected = data.indexOf(Date.parse(start_date)); // console.log(selected); - var color = '#007F00'; + var color = "#007F00"; - var seriesData = [{ + var seriesData = [ + { color: color, data: data, name: title, showInLegend: false, - lineWidth: 2 - }]; + lineWidth: 2, + }, + ]; //$("#charts").append("
") return new Highcharts.Chart({ - chart: { - renderTo: el, - type: "column", - marginRight: 10, - marginBottom: 25 - }, - legend: { - backgroundColor: "#ffffff", - borderColor: "#cccccc", - floating: true, - verticalAlign: "top" - }, - credits: { - enabled: false - }, - title: null, - xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime" - }, - yAxis: { - title: yaxisLabel, - min: 0 - }, - plotOptions: { - line: { - animation: false - }, - series: { - point: { - events: { - click: function() { - var date = moment.utc(new Date(this.x)).format('YYYY-MM-DD'); - window.location.href = '/donations?date=' + date; - } - } - }, - marker: { - fillColor: color, - radius: 0, - states: { - hover: { - enabled: true, - radius: 5 - } - } + chart: { + renderTo: el, + type: "column", + marginRight: 10, + marginBottom: 25, + }, + legend: { + backgroundColor: "#ffffff", + borderColor: "#cccccc", + floating: true, + verticalAlign: "top", + }, + credits: { + enabled: false, + }, + title: null, + xAxis: { + dateTimeLabelFormats: { year: "%Y" }, + type: "datetime", + }, + yAxis: { + title: yaxisLabel, + min: 0, + }, + plotOptions: { + line: { + animation: false, + }, + series: { + point: { + events: { + click: function () { + var date = moment.utc(new Date(this.x)).format("YYYY-MM-DD"); + window.location.href = "/donations?date=" + date; + }, }, - shadow: false, + }, + marker: { + fillColor: color, + radius: 0, states: { - hover: { - lineWidth: 2 - } - } - } - }, - tooltip: { - crosshairs: true, - formatter: function() { - var s = "" + ChartHelper.toolTipDateFormat(pointInterval, this.x) + ""; - $.each(this.points, function(i, point) { - s += "
" + point.series.name + ": $" + Highcharts.numberFormat(point.y, 0, '.', ','); - }); - return s; + hover: { + enabled: true, + radius: 5, + }, }, - shared: true + }, + shadow: false, + states: { + hover: { + lineWidth: 2, + }, + }, }, - series: seriesData - }); - } + }, + tooltip: { + crosshairs: true, + formatter: function () { + var s = + "" + + ChartHelper.toolTipDateFormat(pointInterval, this.x) + + ""; + $.each(this.points, function (i, point) { + s += + "
" + + point.series.name + + ": $" + + Highcharts.numberFormat(point.y, 0, ".", ","); + }); + return s; + }, + shared: true, + }, + series: seriesData, + }); +}; -ChartHelper.netfunds = function(el, title, sourceTxt, yaxisLabel, data) { - var color = '#007E85'; +ChartHelper.netfunds = function (el, title, sourceTxt, yaxisLabel, data) { + var color = "#007E85"; - var seriesData = [{ - color: color, - data: data[0], - name: "Funds available" - },{ - color: "#DD0000", - data: data[1], - name: "Debts" - } - ] + var seriesData = [ + { + color: color, + data: data[0], + name: "Funds available", + }, + { + color: "#DD0000", + data: data[1], + name: "Debts", + }, + ]; //$("#charts").append("
") return new Highcharts.Chart({ - chart: { - renderTo: el, - type: "area", - marginRight: 10, - marginBottom: 25 - }, - legend: { - backgroundColor: "#ffffff", - borderColor: "#cccccc", - floating: true, - verticalAlign: "top" - }, - credits: { - enabled: false - }, + chart: { + renderTo: el, + type: "area", + marginRight: 10, + marginBottom: 25, + }, + legend: { + backgroundColor: "#ffffff", + borderColor: "#cccccc", + floating: true, + verticalAlign: "top", + }, + credits: { + enabled: false, + }, + title: null, + xAxis: { + dateTimeLabelFormats: { year: "%Y" }, + type: "datetime", + }, + yAxis: { title: null, - xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime" - }, - yAxis: { - title: null - }, - plotOptions: { - line: { - animation: false - }, - series: { - marker: { - fillColor: color, - radius: 0, - states: { - hover: { - enabled: true, - radius: 5 - } - } - }, - shadow: false - } - }, - tooltip: { - crosshairs: true, - formatter: function() { - var s = "" + ChartHelper.toolTipDateFormat("day", this.x) + ""; - $.each(this.points, function(i, point) { - s += "
" + point.series.name + ": $" + Highcharts.numberFormat(point.y, 0, '.', ','); - }); - return s; + }, + plotOptions: { + line: { + animation: false, + }, + series: { + marker: { + fillColor: color, + radius: 0, + states: { + hover: { + enabled: true, + radius: 5, + }, }, - shared: true - }, - series: seriesData - }); - } + }, + shadow: false, + }, + }, + tooltip: { + crosshairs: true, + formatter: function () { + var s = + "" + + ChartHelper.toolTipDateFormat("day", this.x) + + ""; + $.each(this.points, function (i, point) { + s += + "
" + + point.series.name + + ": $" + + Highcharts.numberFormat(point.y, 0, ".", ","); + }); + return s; + }, + shared: true, + }, + series: seriesData, + }); +}; -ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, data) { - var color = '#007E85'; +ChartHelper.donation_expenditure = function ( + el, + title, + sourceTxt, + yaxisLabel, + data +) { + var color = "#007E85"; - var seriesData = [{ - color: color, - data: data[0], - name: "Donations and loans" - },{ - color: "#DD0000", - data: data[1], - name: "Expenditures" - } - ] + var seriesData = [ + { + color: color, + data: data[0], + name: "Donations and loans", + }, + { + color: "#DD0000", + data: data[1], + name: "Expenditures", + }, + ]; //$("#charts").append("
") return new Highcharts.Chart({ - chart: { - renderTo: el, - type: "area", - marginRight: 10, - marginBottom: 25 - }, - legend: { - backgroundColor: "#ffffff", - borderColor: "#cccccc", - floating: true, - verticalAlign: "top" - }, - credits: { - enabled: false - }, + chart: { + renderTo: el, + type: "area", + marginRight: 10, + marginBottom: 25, + }, + legend: { + backgroundColor: "#ffffff", + borderColor: "#cccccc", + floating: true, + verticalAlign: "top", + }, + credits: { + enabled: false, + }, + title: null, + xAxis: { + dateTimeLabelFormats: { year: "%Y" }, + type: "datetime", + }, + yAxis: { title: null, - xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime" - }, - yAxis: { - title: null - }, - plotOptions: { - line: { - animation: false - }, - series: { - marker: { - fillColor: color, - radius: 0, - states: { - hover: { - enabled: true, - radius: 5 - } - } - }, - shadow: false - } - }, - tooltip: { - crosshairs: true, - formatter: function() { - var s = "" + ChartHelper.toolTipDateFormat("day", this.x) + ""; - $.each(this.points, function(i, point) { - s += "
" + point.series.name + ": $" + Highcharts.numberFormat(point.y, 0, '.', ','); - }); - return s; + }, + plotOptions: { + line: { + animation: false, + }, + series: { + marker: { + fillColor: color, + radius: 0, + states: { + hover: { + enabled: true, + radius: 5, + }, }, - shared: true - }, - series: seriesData - }); - } + }, + shadow: false, + }, + }, + tooltip: { + crosshairs: true, + formatter: function () { + var s = + "" + + ChartHelper.toolTipDateFormat("month", this.x) + + ""; + $.each(this.points, function (i, point) { + s += + "
" + + point.series.name + + ": $" + + Highcharts.numberFormat(point.y, 0, ".", ","); + }); + return s; + }, + shared: true, + }, + series: seriesData, + }); +}; -ChartHelper.smallDonationExpend = function(el, min_max, data) { +ChartHelper.smallDonationExpend = function (el, min_max, data) { var min = min_max[0]; var max = min_max[1]; - var color = '#007E85'; + var color = "#007E85"; - var seriesData = [{ - color: color, - data: data[0], - name: "Donations" - },{ - color: "#DD0000", - data: data[1], - name: "Expenditures" - } - ] + var seriesData = [ + { + color: color, + data: data[0], + name: "Donations", + }, + { + color: "#DD0000", + data: data[1], + name: "Expenditures", + }, + ]; return new Highcharts.Chart({ - chart: { - renderTo: el, - type: "area", - marginRight: 10, - marginBottom: 25, - backgroundColor: null, - height: 100, - }, - legend: { - enabled: false - }, - credits: { - enabled: false - }, + chart: { + renderTo: el, + type: "area", + marginRight: 10, + marginBottom: 25, + backgroundColor: null, + height: 100, + }, + legend: { + enabled: false, + }, + credits: { + enabled: false, + }, + title: null, + xAxis: { + dateTimeLabelFormats: { year: "%Y" }, + type: "datetime", + }, + yAxis: { title: null, - xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime" - }, - yAxis: { - title: null, - max: max, - min: min - }, - plotOptions: { - line: { - animation: false - }, - series: { - marker: { - fillColor: color, - radius: 0, - states: { - hover: { - enabled: true, - radius: 5 - } - } - }, - shadow: false - } - }, - tooltip: { - crosshairs: true, - formatter: function() { - var s = "" + ChartHelper.toolTipDateFormat("day", this.x) + ""; - $.each(this.points, function(i, point) { - s += "
" + point.series.name + ": $" + Highcharts.numberFormat(point.y, 0, '.', ','); - }); - return s; + max: max, + min: min, + }, + plotOptions: { + line: { + animation: false, + }, + series: { + marker: { + fillColor: color, + radius: 0, + states: { + hover: { + enabled: true, + radius: 5, + }, }, - shared: true - }, - series: seriesData + }, + shadow: false, + }, + }, + tooltip: { + crosshairs: true, + formatter: function () { + var s = + "" + + ChartHelper.toolTipDateFormat("day", this.x) + + ""; + $.each(this.points, function (i, point) { + s += + "
" + + point.series.name + + ": $" + + Highcharts.numberFormat(point.y, 0, ".", ","); + }); + return s; + }, + shared: true, + }, + series: seriesData, }); -} +}; -ChartHelper.initQualityChart = function(el) { - $('#' + el).highcharts({ - chart: { - type: 'bar' - }, - credits: { - enabled: false - }, - title: { - text: null - }, - xAxis: { - title: null, - labels: { - enabled: false - } - }, - yAxis:{ - title: null, - min: 1989, - max: 2015, - labels: { - formatter: function() { return parseInt(this.value); } - } - }, - plotOptions: { - series: { - stacking: 'true', - events: { - legendItemClick: function () { - return false; - } - } - } - }, - tooltip: { - borderColor: "#ccc", - formatter: function() { - return this.series.name; - } +ChartHelper.initQualityChart = function (el) { + $("#" + el).highcharts({ + chart: { + type: "bar", + }, + credits: { + enabled: false, + }, + title: { + text: null, + }, + xAxis: { + title: null, + labels: { + enabled: false, }, - legend: { reversed: true }, - series: [ - { - name: '2000 on: Electronic filings', - data: [ 15 ], - color: "#43ac6a", - }, - { - name: '1999: Incomplete', - data: [ 1 ], - color: "#d9edf7" + }, + yAxis: { + title: null, + min: 1989, + max: 2015, + labels: { + formatter: function () { + return parseInt(this.value); }, - { - name: '1994 - 1999: Manually entered', - data: [ 5 ], - color: "#43ac6a" + }, + }, + plotOptions: { + series: { + stacking: "true", + events: { + legendItemClick: function () { + return false; + }, }, - { - name: '1989 - 1994: Bad entries', - data: [ 1994 ], - color: "#d9edf7" - } - ] + }, + }, + tooltip: { + borderColor: "#ccc", + formatter: function () { + return this.series.name; + }, + }, + legend: { reversed: true }, + series: [ + { + name: "2000 on: Electronic filings", + data: [15], + color: "#43ac6a", + }, + { + name: "1999: Incomplete", + data: [1], + color: "#d9edf7", + }, + { + name: "1994 - 1999: Manually entered", + data: [5], + color: "#43ac6a", + }, + { + name: "1989 - 1994: Bad entries", + data: [1994], + color: "#d9edf7", + }, + ], }); -} +}; -ChartHelper.pointInterval = function(interval) { - if (interval == "year") - return 365 * 24 * 3600 * 1000; - if (interval == "quarter") - return 3 * 30.4 * 24 * 3600 * 1000; - if (interval == "month") //this is very hacky. months have different day counts, so our point interval is the average - 30.4 +ChartHelper.pointInterval = function (interval) { + if (interval == "year") return 365 * 24 * 3600 * 1000; + if (interval == "quarter") return 3 * 30.4 * 24 * 3600 * 1000; + if (interval == "month") + //this is very hacky. months have different day counts, so our point interval is the average - 30.4 return 30.4 * 24 * 3600 * 1000; - if (interval == "week") - return 7 * 24 * 3600 * 1000; - if (interval == "day") - return 24 * 3600 * 1000; - if (interval == "hour") - return 3600 * 1000; - else - return 1; -} + if (interval == "week") return 7 * 24 * 3600 * 1000; + if (interval == "day") return 24 * 3600 * 1000; + if (interval == "hour") return 3600 * 1000; + else return 1; +}; -ChartHelper.toolTipDateFormat = function(interval, x) { - if (interval == "year") - return Highcharts.dateFormat("%Y", x); - if (interval == "quarter") - return Highcharts.dateFormat("%B %Y", x); - if (interval == "month") - return Highcharts.dateFormat("%B %Y", x); - if (interval == "week") - return Highcharts.dateFormat("%e %b %Y", x); - if (interval == "day") - return Highcharts.dateFormat("%e %b %Y", x); - if (interval == "hour") - return Highcharts.dateFormat("%H:00", x); - else - return 1; -} +ChartHelper.toolTipDateFormat = function (interval, x) { + if (interval == "year") return Highcharts.dateFormat("%Y", x); + if (interval == "quarter") return Highcharts.dateFormat("%B %Y", x); + if (interval == "month") return Highcharts.dateFormat("%B %Y", x); + if (interval == "week") return Highcharts.dateFormat("%e %b %Y", x); + if (interval == "day") return Highcharts.dateFormat("%e %b %Y", x); + if (interval == "hour") return Highcharts.dateFormat("%H:00", x); + else return 1; +}; // x is difference between beginning and end of reporting period in weeks (can be a float) // y amount contributed within period / x -ChartHelper.generateSeriesData = function(listOfData) { - var sumX = 0.0; - for (var i = 0; i < listOfData.length; i++) { - sumX += listOfData[i].x; - } - var gap = sumX / listOfData.length * 0.2; - var allSeries = [] - var x = 0.0; - for (var i = 0; i < listOfData.length; i++) { - var data = listOfData[i]; - allSeries[i] = { - name: data.name, - data: [ - [x, 0], [x, data.y], - { - x: x + data.x / 2.0, - y: data.y - // dataLabels: { enabled: true, format: data.x + ' x {y}' } - }, - [x + data.x, data.y], [x + data.x, 0] - ], - w: data.x, - h: data.y - }; - x += data.x + gap; - } - return allSeries; -} +ChartHelper.generateSeriesData = function (listOfData) { + var sumX = 0.0; + for (var i = 0; i < listOfData.length; i++) { + sumX += listOfData[i].x; + } + var gap = (sumX / listOfData.length) * 0.2; + var allSeries = []; + var x = 0.0; + for (var i = 0; i < listOfData.length; i++) { + var data = listOfData[i]; + allSeries[i] = { + name: data.name, + data: [ + [x, 0], + [x, data.y], + { + x: x + data.x / 2.0, + y: data.y, + // dataLabels: { enabled: true, format: data.x + ' x {y}' } + }, + [x + data.x, data.y], + [x + data.x, 0], + ], + w: data.x, + h: data.y, + }; + x += data.x + gap; + } + return allSeries; +}; From e5796ecdf7ee7cc032a9890fcbdacd043adaa475 Mon Sep 17 00:00:00 2001 From: Hannah Cushman Garland Date: Tue, 1 Oct 2024 12:07:46 -0500 Subject: [PATCH 02/10] Revert JavaScript formatting --- camp_fin/static/js/chart_helper.js | 821 ++++++++++++++--------------- 1 file changed, 386 insertions(+), 435 deletions(-) diff --git a/camp_fin/static/js/chart_helper.js b/camp_fin/static/js/chart_helper.js index cd81a4b..f3da620 100644 --- a/camp_fin/static/js/chart_helper.js +++ b/camp_fin/static/js/chart_helper.js @@ -1,12 +1,5 @@ var ChartHelper = {}; -ChartHelper.donations = function ( - el, - title, - sourceTxt, - yaxisLabel, - data, - pointInterval -) { +ChartHelper.donations = function(el, title, sourceTxt, yaxisLabel, data, pointInterval) { // console.log("rendering to: #chart_" + iteration); // console.log("title: " + title); // console.log("sourceTxt: " + sourceTxt); @@ -21,476 +14,434 @@ ChartHelper.donations = function ( // var selected = data.indexOf(Date.parse(start_date)); // console.log(selected); - var color = "#007F00"; + var color = '#007F00'; - var seriesData = [ - { + var seriesData = [{ color: color, data: data, name: title, showInLegend: false, - lineWidth: 2, - }, - ]; + lineWidth: 2 + }]; //$("#charts").append("
") return new Highcharts.Chart({ - chart: { - renderTo: el, - type: "column", - marginRight: 10, - marginBottom: 25, - }, - legend: { - backgroundColor: "#ffffff", - borderColor: "#cccccc", - floating: true, - verticalAlign: "top", - }, - credits: { - enabled: false, - }, - title: null, - xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime", - }, - yAxis: { - title: yaxisLabel, - min: 0, - }, - plotOptions: { - line: { - animation: false, - }, - series: { - point: { - events: { - click: function () { - var date = moment.utc(new Date(this.x)).format("YYYY-MM-DD"); - window.location.href = "/donations?date=" + date; - }, - }, + chart: { + renderTo: el, + type: "column", + marginRight: 10, + marginBottom: 25 + }, + legend: { + backgroundColor: "#ffffff", + borderColor: "#cccccc", + floating: true, + verticalAlign: "top" + }, + credits: { + enabled: false + }, + title: null, + xAxis: { + dateTimeLabelFormats: { year: "%Y" }, + type: "datetime" + }, + yAxis: { + title: yaxisLabel, + min: 0 + }, + plotOptions: { + line: { + animation: false }, - marker: { - fillColor: color, - radius: 0, - states: { - hover: { - enabled: true, - radius: 5, - }, + series: { + point: { + events: { + click: function() { + var date = moment.utc(new Date(this.x)).format('YYYY-MM-DD'); + window.location.href = '/donations?date=' + date; + } + } }, - }, - shadow: false, - states: { - hover: { - lineWidth: 2, + marker: { + fillColor: color, + radius: 0, + states: { + hover: { + enabled: true, + radius: 5 + } + } }, - }, + shadow: false, + states: { + hover: { + lineWidth: 2 + } + } + } }, - }, - tooltip: { - crosshairs: true, - formatter: function () { - var s = - "" + - ChartHelper.toolTipDateFormat(pointInterval, this.x) + - ""; - $.each(this.points, function (i, point) { - s += - "
" + - point.series.name + - ": $" + - Highcharts.numberFormat(point.y, 0, ".", ","); - }); - return s; - }, - shared: true, - }, - series: seriesData, - }); -}; + tooltip: { + crosshairs: true, + formatter: function() { + var s = "" + ChartHelper.toolTipDateFormat(pointInterval, this.x) + ""; + $.each(this.points, function(i, point) { + s += "
" + point.series.name + ": $" + Highcharts.numberFormat(point.y, 0, '.', ','); + }); + return s; + }, + shared: true + }, + series: seriesData + }); + } -ChartHelper.netfunds = function (el, title, sourceTxt, yaxisLabel, data) { - var color = "#007E85"; +ChartHelper.netfunds = function(el, title, sourceTxt, yaxisLabel, data) { + var color = '#007E85'; - var seriesData = [ - { - color: color, - data: data[0], - name: "Funds available", - }, - { - color: "#DD0000", - data: data[1], - name: "Debts", - }, - ]; + var seriesData = [{ + color: color, + data: data[0], + name: "Funds available" + },{ + color: "#DD0000", + data: data[1], + name: "Debts" + } + ] //$("#charts").append("
") return new Highcharts.Chart({ - chart: { - renderTo: el, - type: "area", - marginRight: 10, - marginBottom: 25, - }, - legend: { - backgroundColor: "#ffffff", - borderColor: "#cccccc", - floating: true, - verticalAlign: "top", - }, - credits: { - enabled: false, - }, - title: null, - xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime", - }, - yAxis: { + chart: { + renderTo: el, + type: "area", + marginRight: 10, + marginBottom: 25 + }, + legend: { + backgroundColor: "#ffffff", + borderColor: "#cccccc", + floating: true, + verticalAlign: "top" + }, + credits: { + enabled: false + }, title: null, - }, - plotOptions: { - line: { - animation: false, - }, - series: { - marker: { - fillColor: color, - radius: 0, - states: { - hover: { - enabled: true, - radius: 5, - }, - }, + xAxis: { + dateTimeLabelFormats: { year: "%Y" }, + type: "datetime" + }, + yAxis: { + title: null + }, + plotOptions: { + line: { + animation: false }, - shadow: false, - }, - }, - tooltip: { - crosshairs: true, - formatter: function () { - var s = - "" + - ChartHelper.toolTipDateFormat("day", this.x) + - ""; - $.each(this.points, function (i, point) { - s += - "
" + - point.series.name + - ": $" + - Highcharts.numberFormat(point.y, 0, ".", ","); - }); - return s; - }, - shared: true, - }, - series: seriesData, - }); -}; + series: { + marker: { + fillColor: color, + radius: 0, + states: { + hover: { + enabled: true, + radius: 5 + } + } + }, + shadow: false + } + }, + tooltip: { + crosshairs: true, + formatter: function() { + var s = "" + ChartHelper.toolTipDateFormat("day", this.x) + ""; + $.each(this.points, function(i, point) { + s += "
" + point.series.name + ": $" + Highcharts.numberFormat(point.y, 0, '.', ','); + }); + return s; + }, + shared: true + }, + series: seriesData + }); + } -ChartHelper.donation_expenditure = function ( - el, - title, - sourceTxt, - yaxisLabel, - data -) { - var color = "#007E85"; +ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, data) { + var color = '#007E85'; - var seriesData = [ - { - color: color, - data: data[0], - name: "Donations and loans", - }, - { - color: "#DD0000", - data: data[1], - name: "Expenditures", - }, - ]; + var seriesData = [{ + color: color, + data: data[0], + name: "Donations and loans" + },{ + color: "#DD0000", + data: data[1], + name: "Expenditures" + } + ] //$("#charts").append("
") return new Highcharts.Chart({ - chart: { - renderTo: el, - type: "area", - marginRight: 10, - marginBottom: 25, - }, - legend: { - backgroundColor: "#ffffff", - borderColor: "#cccccc", - floating: true, - verticalAlign: "top", - }, - credits: { - enabled: false, - }, - title: null, - xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime", - }, - yAxis: { + chart: { + renderTo: el, + type: "area", + marginRight: 10, + marginBottom: 25 + }, + legend: { + backgroundColor: "#ffffff", + borderColor: "#cccccc", + floating: true, + verticalAlign: "top" + }, + credits: { + enabled: false + }, title: null, - }, - plotOptions: { - line: { - animation: false, - }, - series: { - marker: { - fillColor: color, - radius: 0, - states: { - hover: { - enabled: true, - radius: 5, - }, - }, + xAxis: { + dateTimeLabelFormats: { year: "%Y" }, + type: "datetime" + }, + yAxis: { + title: null + }, + plotOptions: { + line: { + animation: false }, - shadow: false, - }, - }, - tooltip: { - crosshairs: true, - formatter: function () { - var s = - "" + - ChartHelper.toolTipDateFormat("month", this.x) + - ""; - $.each(this.points, function (i, point) { - s += - "
" + - point.series.name + - ": $" + - Highcharts.numberFormat(point.y, 0, ".", ","); - }); - return s; - }, - shared: true, - }, - series: seriesData, - }); -}; + series: { + marker: { + fillColor: color, + radius: 0, + states: { + hover: { + enabled: true, + radius: 5 + } + } + }, + shadow: false + } + }, + tooltip: { + crosshairs: true, + formatter: function() { + var s = "" + ChartHelper.toolTipDateFormat("month", this.x) + ""; + $.each(this.points, function(i, point) { + s += "
" + point.series.name + ": $" + Highcharts.numberFormat(point.y, 0, '.', ','); + }); + return s; + }, + shared: true + }, + series: seriesData + }); + } -ChartHelper.smallDonationExpend = function (el, min_max, data) { +ChartHelper.smallDonationExpend = function(el, min_max, data) { var min = min_max[0]; var max = min_max[1]; - var color = "#007E85"; + var color = '#007E85'; - var seriesData = [ - { - color: color, - data: data[0], - name: "Donations", - }, - { - color: "#DD0000", - data: data[1], - name: "Expenditures", - }, - ]; + var seriesData = [{ + color: color, + data: data[0], + name: "Donations" + },{ + color: "#DD0000", + data: data[1], + name: "Expenditures" + } + ] return new Highcharts.Chart({ - chart: { - renderTo: el, - type: "area", - marginRight: 10, - marginBottom: 25, - backgroundColor: null, - height: 100, - }, - legend: { - enabled: false, - }, - credits: { - enabled: false, - }, - title: null, - xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime", - }, - yAxis: { + chart: { + renderTo: el, + type: "area", + marginRight: 10, + marginBottom: 25, + backgroundColor: null, + height: 100, + }, + legend: { + enabled: false + }, + credits: { + enabled: false + }, title: null, - max: max, - min: min, - }, - plotOptions: { - line: { - animation: false, - }, - series: { - marker: { - fillColor: color, - radius: 0, - states: { - hover: { - enabled: true, - radius: 5, - }, - }, + xAxis: { + dateTimeLabelFormats: { year: "%Y" }, + type: "datetime" + }, + yAxis: { + title: null, + max: max, + min: min + }, + plotOptions: { + line: { + animation: false }, - shadow: false, - }, - }, - tooltip: { - crosshairs: true, - formatter: function () { - var s = - "" + - ChartHelper.toolTipDateFormat("day", this.x) + - ""; - $.each(this.points, function (i, point) { - s += - "
" + - point.series.name + - ": $" + - Highcharts.numberFormat(point.y, 0, ".", ","); - }); - return s; - }, - shared: true, - }, - series: seriesData, + series: { + marker: { + fillColor: color, + radius: 0, + states: { + hover: { + enabled: true, + radius: 5 + } + } + }, + shadow: false + } + }, + tooltip: { + crosshairs: true, + formatter: function() { + var s = "" + ChartHelper.toolTipDateFormat("day", this.x) + ""; + $.each(this.points, function(i, point) { + s += "
" + point.series.name + ": $" + Highcharts.numberFormat(point.y, 0, '.', ','); + }); + return s; + }, + shared: true + }, + series: seriesData }); -}; +} -ChartHelper.initQualityChart = function (el) { - $("#" + el).highcharts({ - chart: { - type: "bar", - }, - credits: { - enabled: false, - }, - title: { - text: null, - }, - xAxis: { - title: null, - labels: { - enabled: false, +ChartHelper.initQualityChart = function(el) { + $('#' + el).highcharts({ + chart: { + type: 'bar' }, - }, - yAxis: { - title: null, - min: 1989, - max: 2015, - labels: { - formatter: function () { - return parseInt(this.value); - }, + credits: { + enabled: false }, - }, - plotOptions: { - series: { - stacking: "true", - events: { - legendItemClick: function () { - return false; - }, - }, + title: { + text: null + }, + xAxis: { + title: null, + labels: { + enabled: false + } + }, + yAxis:{ + title: null, + min: 1989, + max: 2015, + labels: { + formatter: function() { return parseInt(this.value); } + } + }, + plotOptions: { + series: { + stacking: 'true', + events: { + legendItemClick: function () { + return false; + } + } + } }, - }, - tooltip: { - borderColor: "#ccc", - formatter: function () { - return this.series.name; - }, - }, - legend: { reversed: true }, - series: [ - { - name: "2000 on: Electronic filings", - data: [15], - color: "#43ac6a", - }, - { - name: "1999: Incomplete", - data: [1], - color: "#d9edf7", - }, - { - name: "1994 - 1999: Manually entered", - data: [5], - color: "#43ac6a", - }, - { - name: "1989 - 1994: Bad entries", - data: [1994], - color: "#d9edf7", - }, - ], + tooltip: { + borderColor: "#ccc", + formatter: function() { + return this.series.name; + } + }, + legend: { reversed: true }, + series: [ + { + name: '2000 on: Electronic filings', + data: [ 15 ], + color: "#43ac6a", + }, + { + name: '1999: Incomplete', + data: [ 1 ], + color: "#d9edf7" + }, + { + name: '1994 - 1999: Manually entered', + data: [ 5 ], + color: "#43ac6a" + }, + { + name: '1989 - 1994: Bad entries', + data: [ 1994 ], + color: "#d9edf7" + } + ] }); -}; +} -ChartHelper.pointInterval = function (interval) { - if (interval == "year") return 365 * 24 * 3600 * 1000; - if (interval == "quarter") return 3 * 30.4 * 24 * 3600 * 1000; - if (interval == "month") - //this is very hacky. months have different day counts, so our point interval is the average - 30.4 +ChartHelper.pointInterval = function(interval) { + if (interval == "year") + return 365 * 24 * 3600 * 1000; + if (interval == "quarter") + return 3 * 30.4 * 24 * 3600 * 1000; + if (interval == "month") //this is very hacky. months have different day counts, so our point interval is the average - 30.4 return 30.4 * 24 * 3600 * 1000; - if (interval == "week") return 7 * 24 * 3600 * 1000; - if (interval == "day") return 24 * 3600 * 1000; - if (interval == "hour") return 3600 * 1000; - else return 1; -}; + if (interval == "week") + return 7 * 24 * 3600 * 1000; + if (interval == "day") + return 24 * 3600 * 1000; + if (interval == "hour") + return 3600 * 1000; + else + return 1; +} -ChartHelper.toolTipDateFormat = function (interval, x) { - if (interval == "year") return Highcharts.dateFormat("%Y", x); - if (interval == "quarter") return Highcharts.dateFormat("%B %Y", x); - if (interval == "month") return Highcharts.dateFormat("%B %Y", x); - if (interval == "week") return Highcharts.dateFormat("%e %b %Y", x); - if (interval == "day") return Highcharts.dateFormat("%e %b %Y", x); - if (interval == "hour") return Highcharts.dateFormat("%H:00", x); - else return 1; -}; +ChartHelper.toolTipDateFormat = function(interval, x) { + if (interval == "year") + return Highcharts.dateFormat("%Y", x); + if (interval == "quarter") + return Highcharts.dateFormat("%B %Y", x); + if (interval == "month") + return Highcharts.dateFormat("%B %Y", x); + if (interval == "week") + return Highcharts.dateFormat("%e %b %Y", x); + if (interval == "day") + return Highcharts.dateFormat("%e %b %Y", x); + if (interval == "hour") + return Highcharts.dateFormat("%H:00", x); + else + return 1; +} // x is difference between beginning and end of reporting period in weeks (can be a float) // y amount contributed within period / x -ChartHelper.generateSeriesData = function (listOfData) { - var sumX = 0.0; - for (var i = 0; i < listOfData.length; i++) { - sumX += listOfData[i].x; - } - var gap = (sumX / listOfData.length) * 0.2; - var allSeries = []; - var x = 0.0; - for (var i = 0; i < listOfData.length; i++) { - var data = listOfData[i]; - allSeries[i] = { - name: data.name, - data: [ - [x, 0], - [x, data.y], - { - x: x + data.x / 2.0, - y: data.y, - // dataLabels: { enabled: true, format: data.x + ' x {y}' } - }, - [x + data.x, data.y], - [x + data.x, 0], - ], - w: data.x, - h: data.y, - }; - x += data.x + gap; - } - return allSeries; -}; +ChartHelper.generateSeriesData = function(listOfData) { + var sumX = 0.0; + for (var i = 0; i < listOfData.length; i++) { + sumX += listOfData[i].x; + } + var gap = sumX / listOfData.length * 0.2; + var allSeries = [] + var x = 0.0; + for (var i = 0; i < listOfData.length; i++) { + var data = listOfData[i]; + allSeries[i] = { + name: data.name, + data: [ + [x, 0], [x, data.y], + { + x: x + data.x / 2.0, + y: data.y + // dataLabels: { enabled: true, format: data.x + ' x {y}' } + }, + [x + data.x, data.y], [x + data.x, 0] + ], + w: data.x, + h: data.y + }; + x += data.x + gap; + } + return allSeries; +} From 8c7b59aefc7cab75b9ead6849153c5a09bde8f63 Mon Sep 17 00:00:00 2001 From: Hannah Cushman Garland Date: Tue, 1 Oct 2024 14:02:26 -0500 Subject: [PATCH 03/10] Convert area chart to step chart --- camp_fin/static/js/chart_helper.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/camp_fin/static/js/chart_helper.js b/camp_fin/static/js/chart_helper.js index f3da620..f6cbbf2 100644 --- a/camp_fin/static/js/chart_helper.js +++ b/camp_fin/static/js/chart_helper.js @@ -186,7 +186,7 @@ ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, da return new Highcharts.Chart({ chart: { renderTo: el, - type: "area", + type: "line", marginRight: 10, marginBottom: 25 }, @@ -208,10 +208,9 @@ ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, da title: null }, plotOptions: { - line: { - animation: false - }, series: { + step: true, + shade: true, marker: { fillColor: color, radius: 0, @@ -234,7 +233,7 @@ ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, da }); return s; }, - shared: true + shared: true, }, series: seriesData }); From 26d670dd7d85a03b374c012954db271fc5924602 Mon Sep 17 00:00:00 2001 From: Hannah Cushman Garland Date: Tue, 1 Oct 2024 14:07:16 -0500 Subject: [PATCH 04/10] Remove unneeded option --- camp_fin/static/js/chart_helper.js | 1 - 1 file changed, 1 deletion(-) diff --git a/camp_fin/static/js/chart_helper.js b/camp_fin/static/js/chart_helper.js index f6cbbf2..8afc0d3 100644 --- a/camp_fin/static/js/chart_helper.js +++ b/camp_fin/static/js/chart_helper.js @@ -210,7 +210,6 @@ ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, da plotOptions: { series: { step: true, - shade: true, marker: { fillColor: color, radius: 0, From 8a95238daf98314524e1e57799900fff10351a46 Mon Sep 17 00:00:00 2001 From: Hannah Cushman Garland Date: Wed, 2 Oct 2024 11:42:06 -0500 Subject: [PATCH 05/10] Convert funds by filing into line chart --- camp_fin/models.py | 68 ++++--------------- camp_fin/static/css/custom.css | 2 +- camp_fin/static/js/chart_helper.js | 57 +++++++++++----- camp_fin/templates/base-detail.html | 4 +- .../templates/camp_fin/candidate-detail.html | 4 +- 5 files changed, 60 insertions(+), 75 deletions(-) diff --git a/camp_fin/models.py b/camp_fin/models.py index 510c1de..6470e71 100644 --- a/camp_fin/models.py +++ b/camp_fin/models.py @@ -1,5 +1,4 @@ from collections import namedtuple -from datetime import datetime from django.db import connection, models from django.utils import timezone @@ -946,16 +945,9 @@ def trends(self, since="2010"): # Balances and debts summed_filings = """ SELECT - SUM(f.total_contributions) + \ - SUM(COALESCE(f.total_supplemental_contributions, 0)) AS total_contributions, - SUM(f.total_expenditures) AS total_expenditures, - SUM(COALESCE(f.total_loans, 0)) AS total_loans, SUM(COALESCE(f.total_unpaid_debts, 0)) AS total_unpaid_debts, SUM(f.closing_balance) AS closing_balance, - SUM(f.opening_balance) AS opening_balance, - SUM(f.total_debt_carried_forward) AS debt_carried_forward, - f.filed_date, - MIN(fp.initial_date) AS initial_date + f.filed_date FROM camp_fin_filing AS f JOIN camp_fin_filingperiod AS fp ON f.filing_period_id = fp.id @@ -973,45 +965,16 @@ def trends(self, since="2010"): cursor.execute(summed_filings, [self.id]) - columns = [c[0] for c in cursor.description] - filing_tuple = namedtuple("Filings", columns) - - summed_filings = [filing_tuple(*r) for r in cursor] - balance_trend, debt_trend = [], [] - if summed_filings: - for filing in summed_filings: - filing_date = filing.filed_date - date_array = [filing_date.year, filing_date.month, filing_date.day] - debts = -1 * filing.total_unpaid_debts - if filing.closing_balance: - balance_trend.append([filing.closing_balance, *date_array]) - debt_trend.append([debts, *date_array]) - - if summed_filings[0].opening_balance: - first_opening_balance = summed_filings[0].opening_balance - else: - first_opening_balance = 0 - - if summed_filings[0].debt_carried_forward: - first_debt = summed_filings[0].debt_carried_forward - else: - first_debt = 0 - - init_date = summed_filings[0].initial_date - - first_initial_date = [int(since), 1, 1] - - # If the first available filing date is on or before the start date - # passed into this method, use that as the first date in the trendline - if init_date: - init_date_parts = [init_date.year, init_date.month, init_date.day] - if datetime(*init_date_parts) <= datetime(*first_initial_date): - first_initial_date = init_date_parts - - debt_trend.insert(0, [first_debt, *first_initial_date]) - balance_trend.insert(0, [first_opening_balance, *first_initial_date]) + for ( + total_unpaid_debts, + closing_balance, + filed_date, + ) in cursor: + filing_date = (filed_date.year, filed_date.month, filed_date.day) + balance_trend.append([closing_balance, *filing_date]) + debt_trend.append([total_unpaid_debts * -1, *filing_date]) output_trends = {"balance_trend": balance_trend, "debt_trend": debt_trend} @@ -1020,7 +983,7 @@ def trends(self, since="2010"): SELECT months.year, months.month, - {table}.amount + COALESCE({table}.amount, 0) AS amount FROM ( SELECT DISTINCT DATE_PART('year', month) AS year, @@ -1028,7 +991,7 @@ def trends(self, since="2010"): FROM {table}_by_month ORDER BY year, month ) months - LEFT JOIN ( + JOIN ( SELECT {table}.amount AS amount, DATE_PART('month', {table}.month) AS month, @@ -1038,23 +1001,20 @@ def trends(self, since="2010"): AND {table}.month >= '{year}-01-01'::date ) {table} USING (year, month) + ORDER BY year, month """ contributions_query = monthly_query.format(table="contributions", year=since) cursor.execute(contributions_query, [self.id]) - donation_trend = [ - [amount or 0, year, month, 1] for year, month, amount in cursor - ] + donation_trend = [[amount, year, month, 1] for year, month, amount in cursor] expenditures_query = monthly_query.format(table="expenditures", year=since) cursor.execute(expenditures_query, [self.id]) - expend_trend = [ - [(amount or 0) * -1, year, month, 1] for year, month, amount in cursor - ] + expend_trend = [[amount * -1, year, month, 1] for year, month, amount in cursor] output_trends["donation_trend"] = donation_trend output_trends["expend_trend"] = expend_trend diff --git a/camp_fin/static/css/custom.css b/camp_fin/static/css/custom.css index 615cf29..61282d5 100644 --- a/camp_fin/static/css/custom.css +++ b/camp_fin/static/css/custom.css @@ -210,7 +210,7 @@ a.collapsed .show-less { background-color: #5b0007; } -#net-funds-chart { height: 200px; } +/*#net-funds-chart { height: 200px; }*/ #date-search .form-control { width: 48%; } diff --git a/camp_fin/static/js/chart_helper.js b/camp_fin/static/js/chart_helper.js index 8afc0d3..ded701c 100644 --- a/camp_fin/static/js/chart_helper.js +++ b/camp_fin/static/js/chart_helper.js @@ -96,7 +96,7 @@ ChartHelper.donations = function(el, title, sourceTxt, yaxisLabel, data, pointIn }); } -ChartHelper.netfunds = function(el, title, sourceTxt, yaxisLabel, data) { +ChartHelper.netfunds = function(el, title, sourceTxt, yaxisLabel, data, startYear, endYear) { var color = '#007E85'; var seriesData = [{ @@ -114,9 +114,7 @@ ChartHelper.netfunds = function(el, title, sourceTxt, yaxisLabel, data) { return new Highcharts.Chart({ chart: { renderTo: el, - type: "area", - marginRight: 10, - marginBottom: 25 + type: "line", }, legend: { backgroundColor: "#ffffff", @@ -130,18 +128,28 @@ ChartHelper.netfunds = function(el, title, sourceTxt, yaxisLabel, data) { title: null, xAxis: { dateTimeLabelFormats: { year: "%Y" }, - type: "datetime" + type: "datetime", + title: { + enabled: true, + text: "Filing date" + }, + tickPixelInterval: 50, + min: Date.UTC(startYear, 1, 1), + max: Date.UTC(endYear+1, 1, 1), + startOnTick: true, }, yAxis: { - title: null + title: { + text: yaxisLabel + } }, plotOptions: { line: { animation: false }, series: { + step: true, marker: { - fillColor: color, radius: 0, states: { hover: { @@ -150,7 +158,12 @@ ChartHelper.netfunds = function(el, title, sourceTxt, yaxisLabel, data) { } } }, - shadow: false + shadow: false, + states: { + hover: { + lineWidthPlus: 0 + } + } } }, tooltip: { @@ -168,7 +181,7 @@ ChartHelper.netfunds = function(el, title, sourceTxt, yaxisLabel, data) { }); } -ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, data) { +ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, data, startYear, endYear) { var color = '#007E85'; var seriesData = [{ @@ -187,8 +200,6 @@ ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, da chart: { renderTo: el, type: "line", - marginRight: 10, - marginBottom: 25 }, legend: { backgroundColor: "#ffffff", @@ -201,17 +212,26 @@ ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, da }, title: null, xAxis: { - dateTimeLabelFormats: { year: "%Y" }, - type: "datetime" + dateTimeLabelFormats: { year: "%b '%y" }, + type: "datetime", + title: { + enabled: true, + text: "Month", + }, + tickPixelInterval: 50, + min: Date.UTC(startYear, 1, 1), + max: Date.UTC(endYear+1, 1, 1), + startOnTick: true, }, yAxis: { - title: null + title: { + text: yaxisLabel + } }, plotOptions: { series: { step: true, marker: { - fillColor: color, radius: 0, states: { hover: { @@ -220,7 +240,12 @@ ChartHelper.donation_expenditure = function(el, title, sourceTxt, yaxisLabel, da } } }, - shadow: false + shadow: false, + states: { + hover: { + lineWidthPlus: 0 + } + } } }, tooltip: { diff --git a/camp_fin/templates/base-detail.html b/camp_fin/templates/base-detail.html index 0c6dc9c..a07bb0e 100644 --- a/camp_fin/templates/base-detail.html +++ b/camp_fin/templates/base-detail.html @@ -260,7 +260,7 @@

debt_trend_f.push([Date.UTC(debt_trend[i][1],debt_trend[i][2]-1,debt_trend[i][3]), debt_trend[i][0]]); } - ChartHelper.netfunds('net-funds-chart', 'Net funds over time', '', 'Funds', [balance_trend_f, debt_trend_f]); + ChartHelper.netfunds('net-funds-chart', 'Funds available and debts by filing date', '', 'Funds available / Debts', [balance_trend_f, debt_trend_f], balance_trend[0][1], balance_trend[balance_trend.length - 1][1]); //render donation/expenditure chart @@ -280,7 +280,7 @@

expend_trend_f.push([Date.UTC(expend_trend[i][1],expend_trend[i][2]-1,expend_trend[i][3]), expend_trend[i][0]]); } - ChartHelper.donation_expenditure('expend-chart', 'Donations and expenditures over time', '', 'Money', [donation_trend_f, expend_trend_f]); + ChartHelper.donation_expenditure('expend-chart', 'Contributions and expenditures by month', '', 'Contributions / Expenditures', [donation_trend_f, expend_trend_f], donation_trend[0][1], donation_trend[donation_trend.length - 1][1]);