change to col-auto everywhere, with some more forcing of width maximums to make the page more consistent, redid defaults to incorporate updated per fortnight lease cost, and updated inflation figure/notes/references. Updated default Living expenses to 84000 to match latest view of data, fixed up compare_to to now work, shows a graph of data to compare with, allows drop-down to be compare_to nothing or a saved set, only 1 hand saved for now. Annotations on graph for large changes in savings now work and are legible - had to allow overlap and do some overly complex left/right up/down offsetting to make them all sensible
This commit is contained in:
26
calc.py
26
calc.py
@@ -1,9 +1,16 @@
|
||||
# calc.py
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
def add_annotation(finance, dt, amt, text):
|
||||
def add_annotation(finance, dt, total, delta, text):
|
||||
# dont add an annotation for small changes (jic)
|
||||
if abs(delta) < 5000:
|
||||
return
|
||||
tm = dt.timestamp() * 1000
|
||||
finance['annotations'].append( { 'label': text, 'x': tm, 'y': amt } )
|
||||
if delta > 0:
|
||||
text += f": ${int(abs(delta))}"
|
||||
else:
|
||||
text += f": -${int(abs(delta))}"
|
||||
finance['annotations'].append( { 'label': text, 'x': tm, 'y': total } )
|
||||
return
|
||||
|
||||
def calculate_savings_depletion(finance):
|
||||
@@ -98,6 +105,7 @@ def calculate_savings_depletion(finance):
|
||||
if D_Num_fortnights_pay == 0 and D_leave_after_tax > 0:
|
||||
print(f"D has resigned {current_date}: get paid out my 9 weeks leave and lose 45% to tax - ${D_leave_after_tax}" )
|
||||
current_savings += D_leave_after_tax
|
||||
add_annotation(finance, current_date, current_savings, D_leave_after_tax, "D quit" )
|
||||
D_leave_after_tax = 0
|
||||
|
||||
if fortnight_income:
|
||||
@@ -125,28 +133,28 @@ def calculate_savings_depletion(finance):
|
||||
|
||||
if current_date.date() == school_fees_date.date():
|
||||
current_savings -= School_Fees
|
||||
add_annotation(finance, current_date, current_savings, f"Pay School Fees: ${School_Fees}")
|
||||
add_annotation(finance, current_date, current_savings, -School_Fees, "School Fees")
|
||||
|
||||
if current_date.date() == car_balloon_date.date():
|
||||
current_savings -= Car_balloon
|
||||
add_annotation(finance, current_date, current_savings, f"car balloon paid: ${Car_balloon}" )
|
||||
add_annotation(finance, current_date, current_savings, -Car_balloon, "car balloon")
|
||||
|
||||
# Anniversary of Car balloon so pay insurance/rego
|
||||
if current_date.year >= car_balloon_date.year and current_date.month == car_balloon_date.month and current_date.day == car_balloon_date.day:
|
||||
current_savings -= post_lease_car_costs
|
||||
add_annotation(finance, current_date, current_savings, f"IONIQ 6 ins/rego: ${post_lease_car_costs}" )
|
||||
add_annotation(finance, current_date, current_savings, -post_lease_car_costs, "IONIQ 6 ins/rego" )
|
||||
|
||||
if current_date.date() == overseas_trip_date.date():
|
||||
current_savings -= Overseas_trip
|
||||
add_annotation(finance, current_date, current_savings, f"Overseas trip: ${Overseas_trip}")
|
||||
add_annotation(finance, current_date, current_savings, -Overseas_trip, "O/S trip")
|
||||
|
||||
if current_date.date() == mich_present_date.date():
|
||||
current_savings -= Mich_present
|
||||
add_annotation(finance, current_date, current_savings, f"Michelle's present: ${Mich_present}")
|
||||
add_annotation(finance, current_date, current_savings, -Mich_present, "Mich's present" )
|
||||
|
||||
if current_date.date() == mark_reno_date.date():
|
||||
current_savings -= Mark_reno
|
||||
add_annotation(finance, current_date, current_savings, f"Mark/reno costs: ${Mark_reno}")
|
||||
add_annotation(finance, current_date, current_savings, -Mark_reno, "Mark/reno" )
|
||||
|
||||
if current_savings < 0:
|
||||
depletion_date = current_date
|
||||
@@ -177,7 +185,7 @@ def calculate_savings_depletion(finance):
|
||||
Sell_shares -= 1
|
||||
|
||||
current_savings += actual_sell
|
||||
add_annotation(finance, current_date, current_savings, f"Selling shares: ${int(actual_sell)}" )
|
||||
add_annotation(finance, current_date, current_savings, actual_sell, "Sell shares" )
|
||||
|
||||
|
||||
current_date += timedelta(days=1)
|
||||
|
||||
44
db.py
44
db.py
@@ -34,7 +34,8 @@ def init_db():
|
||||
CBA_price REAL,
|
||||
Overseas_trip_date STRING,
|
||||
Mark_reno_date STRING,
|
||||
Sell_shares INTEGER
|
||||
Sell_shares INTEGER,
|
||||
compare_to INTEGER
|
||||
)''')
|
||||
|
||||
cur.execute('''CREATE TABLE IF NOT EXISTS comparison_set (
|
||||
@@ -82,14 +83,15 @@ def init_db():
|
||||
# Interest rate
|
||||
# D_leave_owed_in_days
|
||||
# maybe quarterly update Inflation? (this is harder to appreciate, seems much lower officialy than Savings, but which inflation:
|
||||
# I've decided to consider food only or overall, whichever is worse - but only found a rabobank reference - THIS IS A MATERIAL ISSUE WITH PROJECTING OUT)
|
||||
# I've decided to consider food only or overall, whichever is worse - using this: https://tradingeconomics.com/australia/food-inflation
|
||||
# FOR NOW inf=3 THIS IS A MATERIAL ISSUE WITH PROJECTING OUT)
|
||||
###
|
||||
cur.execute('''INSERT INTO finance (D_Salary, D_Num_fortnights_pay, School_Fees, Car_loan_via_pay, Car_loan, Car_balloon, Living_Expenses, Savings, Interest_Rate,
|
||||
Inflation, Mich_present, Overseas_trip, Mark_reno, D_leave_owed_in_days, D_TLS_shares, M_TLS_shares, D_CBA_shares, TLS_price, CBA_price, Overseas_trip_date, Mark_reno_date, Sell_shares)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
|
||||
(4762.29, 6, 22000, 620, 1001.12, 45824.68, 83000, 416670.67, 5.0, 3.9, 10000, 32000, 10000, 93.64, 1000, 750, 1095, 3.94, 158.57, '2025-06-01', '2025-09-01', 6))
|
||||
# NOTE: 1001.12 car-pay -- is 1017.99 (actual rate) - 16.87 (car park)
|
||||
# NOTE: o/s trip. ~ $4kpp flights x3, then ~$3k / week in barcelona accom, $100pp/pd for food ($2k), + spending money
|
||||
Inflation, Mich_present, Overseas_trip, Mark_reno, D_leave_owed_in_days, D_TLS_shares, M_TLS_shares, D_CBA_shares, TLS_price, CBA_price, Overseas_trip_date, Mark_reno_date, Sell_shares, compare_to)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)''',
|
||||
(4762.29, 6, 22000, 620, 1017.99, 45824.68, 84000, 416670.67, 5.0, 3.0, 10000, 32000, 10000, 93.64, 1000, 750, 1095, 3.92, 167.03, '2025-06-01', '2025-09-01', 6, 0))
|
||||
# NOTE: 1017.99 car-lease (NEED TO VERIFY)
|
||||
# NOTE: o/s trip. ~ $4kpp flights x3, then ~$3k / week in barcelona accom, $100pp/pd for food ($2k), + spending money (could be less)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@@ -112,8 +114,8 @@ def get_budget_data(finance_data):
|
||||
return BUDGET
|
||||
|
||||
def update_finance(data):
|
||||
|
||||
conn = connect_db()
|
||||
print(data)
|
||||
conn = connect_db(False)
|
||||
cur = conn.cursor()
|
||||
cur.execute('''UPDATE finance SET
|
||||
D_Salary = ?,
|
||||
@@ -137,14 +139,15 @@ def update_finance(data):
|
||||
CBA_price = ?,
|
||||
Overseas_trip_date = ?,
|
||||
Mark_reno_date = ?,
|
||||
Sell_shares = ?
|
||||
Sell_shares = ?,
|
||||
compare_to = ?
|
||||
WHERE id = 1''', data)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def insert_cset( data ):
|
||||
conn = connect_db()
|
||||
conn = connect_db(False)
|
||||
cur = conn.cursor()
|
||||
cur.execute('''INSERT INTO comparison_set (
|
||||
name, D_Salary, D_Num_fortnights_pay, School_Fees, Car_loan_via_pay,
|
||||
@@ -181,12 +184,12 @@ def get_comp_set_data(cset_id):
|
||||
conn = connect_db(True)
|
||||
cur = conn.cursor()
|
||||
|
||||
# HARDCODED FOR NOW
|
||||
cset_id = 1
|
||||
|
||||
# get saved finance data for this comparison set
|
||||
cur.execute( f"select * from comparison_set where id = {cset_id}" )
|
||||
COMP['vars']= dict(cur.fetchone())
|
||||
res=cur.fetchone()
|
||||
if not res:
|
||||
return None
|
||||
COMP['vars']= dict(res)
|
||||
conn.close()
|
||||
|
||||
# open new connection so we get rows back as basic array
|
||||
@@ -201,3 +204,14 @@ def get_comp_set_data(cset_id):
|
||||
COMP['date'], COMP['amount'] = COMP['savings_data'][-1]
|
||||
return COMP
|
||||
|
||||
|
||||
def get_comp_set_options(finance):
|
||||
finance['COMP_SETS']=[ ( 0, 'Nothing' ) ]
|
||||
# get comp data from DB (as object so dict conversion works below)
|
||||
conn = connect_db(False)
|
||||
cur = conn.cursor()
|
||||
|
||||
# get saved finance data for this comparison set
|
||||
cur.execute( f"select id, name from comparison_set order by id" )
|
||||
finance['COMP_SETS'].extend( cur.fetchall() )
|
||||
return
|
||||
|
||||
2
disp.py
2
disp.py
@@ -22,7 +22,7 @@ class FP_VAR(FP):
|
||||
dot-notation of fields
|
||||
"""
|
||||
|
||||
def __init__(self, label, varname, display='', cl='col-2', datevarname=''):
|
||||
def __init__(self, label, varname, display='', cl='col-auto', datevarname=''):
|
||||
### Var Attributes -- note, simple class, no methods ###
|
||||
self.label=label
|
||||
self.varname=varname
|
||||
|
||||
22
main.py
22
main.py
@@ -1,7 +1,7 @@
|
||||
# main.py
|
||||
from flask import Flask, render_template, request, redirect, url_for, Response
|
||||
from calc import calculate_savings_depletion
|
||||
from db import init_db, get_finance_data, update_finance, get_budget_data, get_comp_set_data
|
||||
from db import init_db, get_finance_data, update_finance, get_budget_data, get_comp_set_data, get_comp_set_options
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
import csv
|
||||
@@ -16,18 +16,15 @@ init_db()
|
||||
@app.route('/')
|
||||
def index():
|
||||
finance_data = get_finance_data()
|
||||
get_comp_set_options(finance_data)
|
||||
depletion_date, savings_per_fortnight, final_savings = calculate_savings_depletion(finance_data)
|
||||
BUDGET=get_budget_data(finance_data)
|
||||
|
||||
if depletion_date:
|
||||
depletion_date=depletion_date.date(); # just show date
|
||||
|
||||
#HARDCODE HACK:
|
||||
finance_data['comp_set']=1
|
||||
|
||||
# we are comparing...
|
||||
if finance_data['comp_set'] >= 1:
|
||||
COMP=get_comp_set_data(finance_data['comp_set'])
|
||||
# if we are comparing...(compare_to will be 0 / None to start with, and then COMP will be None
|
||||
COMP=get_comp_set_data(finance_data['compare_to'])
|
||||
|
||||
DISP=[]
|
||||
# Row 1
|
||||
@@ -36,7 +33,7 @@ def index():
|
||||
r.append( FP_VAR( 'Savings', 'Savings' ) )
|
||||
r.append( FP_VAR( 'Car Loan via Pay', 'Car_loan_via_pay', 'readonly' ) )
|
||||
r.append( FP_VAR( 'Living Expenses', 'Living_Expenses' ) )
|
||||
r.append( FP_VAR( 'Overseas Trip', 'Overseas_trip', 'date', 'col-4', 'Overseas_trip_date' ) )
|
||||
r.append( FP_VAR( 'Overseas Trip', 'Overseas_trip', 'date', 'col-auto', 'Overseas_trip_date' ) )
|
||||
DISP.append(r)
|
||||
|
||||
# Row 2
|
||||
@@ -45,12 +42,12 @@ def index():
|
||||
r.append( FP_VAR( 'Interest Rate', 'Interest_Rate' ) )
|
||||
r.append( FP_VAR( 'Car Loan', 'Car_loan', 'readonly' ) )
|
||||
r.append( FP_VAR( 'Inflation', 'Inflation' ) )
|
||||
r.append( FP_VAR( 'Reno Costs', 'Mark_reno', 'date', 'col-4', 'Mark_reno_date' ) )
|
||||
r.append( FP_VAR( 'Reno Costs', 'Mark_reno', 'date', 'col-auto', 'Mark_reno_date' ) )
|
||||
DISP.append(r)
|
||||
|
||||
# Row 2
|
||||
r=[]
|
||||
r.append( FP_VAR( 'D leave owed (in days)', 'D_leave_owed_in_days' ) )
|
||||
r.append( FP_VAR( 'D # days leave', 'D_leave_owed_in_days' ) )
|
||||
r.append( FP_VAR( 'M TLS amount', 'M_TLS_shares' ) )
|
||||
r.append( FP_VAR( 'Car Balloon', 'Car_balloon', 'readonly' ) )
|
||||
DISP.append(r)
|
||||
@@ -60,7 +57,7 @@ def index():
|
||||
r.append( FP_VAR( 'D CBA amount', 'D_CBA_shares' ) )
|
||||
r.append( FP_VAR( 'D TLS amount', 'D_TLS_shares' ) )
|
||||
r.append( FP_VAR( 'Mich Present', 'Mich_present', 'readonly' ) )
|
||||
r.append( FP_VAR( 'Sell Shares for:', 'Sell_shares', 'select', 'offset-2 col-2' ) )
|
||||
r.append( FP_VAR( 'Sell Shares for:', 'Sell_shares', 'select', 'col-auto' ) )
|
||||
DISP.append(r)
|
||||
|
||||
# Row 4
|
||||
@@ -100,6 +97,7 @@ def update():
|
||||
request.form['Overseas_trip_date'],
|
||||
request.form['Mark_reno_date'],
|
||||
request.form['Sell_shares'],
|
||||
request.form['compare_to']
|
||||
)
|
||||
|
||||
update_finance(finance_data)
|
||||
@@ -110,7 +108,7 @@ def update():
|
||||
def download_csv():
|
||||
|
||||
finance_data = get_finance_data()
|
||||
depletion_date, savings_per_fortnight, final_savings, TLS, CBA = calculate_savings_depletion(finance_data)
|
||||
depletion_date, savings_per_fortnight, final_savings = calculate_savings_depletion(finance_data)
|
||||
BUDGET=get_budget_data(finance_data)
|
||||
|
||||
# Group data by year
|
||||
|
||||
@@ -8,38 +8,34 @@
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
|
||||
<script src="https://code.highcharts.com/highcharts.js"></script>
|
||||
<script src="https://code.highcharts.com/modules/annotations.js"></script>
|
||||
<script src="https://code.highcharts.com/modules/accessibility.js"></script>
|
||||
<style>
|
||||
.col-form-label {
|
||||
width:170px;
|
||||
}
|
||||
.col-form-label { width:140px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="containerfluid">
|
||||
<h3 align="center">Finance Tracker</h3>
|
||||
|
||||
<form id="vals_form" class="mt-3" action="/update" method="POST">
|
||||
<form id="vals_form" class="ms-3 mt-3" action="/update" method="POST">
|
||||
{% for r in DISP %}
|
||||
<div class="row align-items-center">
|
||||
{% for el in r %}
|
||||
<div class="{{el.cl}}">
|
||||
<div class="input-group">
|
||||
{% if el.display=="select" %}
|
||||
<label for="{{el.varname}}" class="input-group-text">{{el.label}}</label>
|
||||
<select class="form-select border border-primary text-primary" id="{{el.varname}}" name="{{el.varname}}" onchange="this.form.submit()">
|
||||
<label for="{{el.varname}}" class="col-form-label me-2 text-end float-end">{{el.label}}</label>
|
||||
<select class="form-select border border-primary text-primary" id="{{el.varname}}" name="{{el.varname}}" style="width: 120px;" onchange="this.form.submit()">
|
||||
<option value="0">Never</option>
|
||||
<option value="1">1 years</option>
|
||||
<option value="2">2 years</option>
|
||||
<option value="3">3 years</option>
|
||||
<option value="4">4 years</option>
|
||||
<option value="5">5 years</option>
|
||||
<option value="6">6 years</option>
|
||||
{% for el in range( 1,7 ) %}
|
||||
<option value="{{el}}">{{el}} years</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% elif el.display=="date" %}
|
||||
<label for="{{el.varname}}" class="col-form-label me-2 text-end float-end">{{el.label}}</label>
|
||||
<input type="number" step="any" class="form-control text-end float-end border border-primary" onchange="this.form.submit()"
|
||||
<input type="number" step="any" class="form-control text-end float-end border border-primary" onchange="this.form.submit()" style="max-width: 120px;"
|
||||
id="{{el.varname}}" name="{{el.varname}}" value="{{ finance[el.varname] }}" {{el.display}}>
|
||||
<input type="date" class="form-control text-end float-end border border-primary" id="{{el.datevarname}}"
|
||||
<input type="date" class="form-control text-end float-end border border-primary" id="{{el.datevarname}}" style="max-width: 150px;"
|
||||
name="{{el.datevarname}}" value="{{ finance[el.datevarname] }}" onchange="this.form.submit()">
|
||||
{% else %}
|
||||
<label for="{{el.varname}}" class="col-form-label me-2 text-end float-end">{{el.label}}</label>
|
||||
@@ -50,7 +46,7 @@
|
||||
{% set bg="" %}
|
||||
{% set bd="border-1 border-primary" %}
|
||||
{% endif %}
|
||||
<input type="number" step="any" class="{{bg}} form-control text-end float-end {{bd}}" onchange="this.form.submit()"
|
||||
<input type="number" step="any" class="{{bg}} form-control text-end float-end {{bd}}" onchange="this.form.submit()" style="max-width: 120px;"
|
||||
id="{{el.varname}}" name="{{el.varname}}" value="{{ finance[el.varname] }}" {{el.display}}>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -58,23 +54,22 @@
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</form>
|
||||
|
||||
|
||||
<h5 align="center" class="mt-4">Fortnighthly Savings data:
|
||||
{% if COMP %}
|
||||
<font color="blue"> Note: value in blue below is value we should have been at when comparing to saved values</font>
|
||||
{% endif %}
|
||||
</h5>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-auto"> <div class="pt-1 pb-1 mb-0 alert text-center" style="background:lemonchiffon">2025</div>
|
||||
|
||||
{# get comparison date so we can use it below in loop to know when to print it out #}
|
||||
{% set comp_yr=COMP['date'][:4] %}
|
||||
{% set comp_mon=COMP['date'][5:7] %}
|
||||
{% set comp_day=COMP['date'][8:10 ] %}
|
||||
{% set comp_done=namespace( val=0 ) %}
|
||||
{% else %}
|
||||
{# we dont need to do a comparison, so consider it done before we begin #}
|
||||
{% set comp_done=namespace( val=1 ) %}
|
||||
{% endif %}
|
||||
</h5>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-auto"> <div class="pt-1 pb-1 mb-0 alert text-center" style="background:lemonchiffon">2025</div>
|
||||
|
||||
{% set first_yr=2025 %}
|
||||
{% for date, dollars in savings %}
|
||||
@@ -103,6 +98,9 @@
|
||||
{% else %}
|
||||
<div class="alert alert-success">Super kicks in!!!</div>
|
||||
{% endif %}
|
||||
{% if COMP %}
|
||||
<div class="alert alert-info">Note: value in blue<br>above is value we<br>should have been<br>at when comparing<br> to saved values</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="alert alert-warning">
|
||||
@@ -115,18 +113,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-primary" onClick="$('#vals_form').submit()">Update</button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="input-group">
|
||||
<button type="submit" class="disabled btn btn-primary" onClick="$('#vals_form').submit() disabled">Compare with:</button>
|
||||
<select class="form-select border border-primary text-primary" id="comp_set" name="comp_set" onchange="">
|
||||
<option value="0">None</option>
|
||||
<option value="1">something</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-primary" onClick="alert('not yet'); return false">Save</button>
|
||||
<button type="button" class="btn btn-primary" onClick="
|
||||
$.ajax( { type: 'GET', url: '/download_csv', xhrFields: { responseType: 'blob' },
|
||||
success: function(res){
|
||||
@@ -142,24 +129,42 @@
|
||||
console.log('done') } })
|
||||
"> Export to CSV </button>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="input-group">
|
||||
<button type="submit" class="disabled btn btn-primary" onClick="$('#vals_form').submit() disabled">Compare to:</button>
|
||||
<select class="form-select border border-primary text-primary" id="compare_to" name="compare_to" onchange="$('#vals_form').submit()">
|
||||
{% for el in finance['COMP_SETS'] %}
|
||||
<option value="{{el[0]}}">{{el[1]}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="row mt-4" id="container" style="width:100%; height:400px;"></div>
|
||||
<script type="text/javascript">
|
||||
window.onload = function() {
|
||||
document.getElementById("Sell_shares").value = {{finance['Sell_shares']}};
|
||||
$('#Sell_shares').val( {{finance['Sell_shares']}} )
|
||||
$('#compare_to').val( {{finance['compare_to']}} )
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Parse the savings_data from Flask
|
||||
const savingsData = JSON.parse('{{ COMP['savings_data'] | tojson }}');
|
||||
const savingsData = JSON.parse('{{ savings | tojson }}');
|
||||
const chartData = savingsData.map(entry => [new Date(entry[0]).getTime(), parseFloat(entry[1])]);
|
||||
{% if COMP %}
|
||||
const compSavingsData = JSON.parse('{{ COMP['savings_data'] | tojson }}');
|
||||
const compChartData = compSavingsData.map(entry => [new Date(entry[0]).getTime(), parseFloat(entry[1])]);
|
||||
{% endif %}
|
||||
|
||||
|
||||
// Get the legend name and vars for the tooltip
|
||||
const legendName = '{{ COMP["vars"]["name"] }}';
|
||||
const vars = JSON.parse('{{ COMP["vars"] | tojson }}');
|
||||
const legendName = 'Savings';
|
||||
const vars = JSON.parse('{{ finance | tojson }}');
|
||||
|
||||
// Tooltip content from vars
|
||||
const tooltipContent = Object.entries(vars).map(([key, value]) => `${key}: ${value}`).join('<br>');
|
||||
console.log(tooltipContent)
|
||||
|
||||
// Calculate plot bands for each year with alternating background colors
|
||||
const plotBands = [];
|
||||
@@ -188,63 +193,58 @@
|
||||
color: year % 2 === 0 ? 'white' : 'lemonchiffon'
|
||||
});
|
||||
|
||||
// Add annotations for changes greater than 5000
|
||||
const annotations = [];
|
||||
var offset=13
|
||||
var al='left'
|
||||
var x=-130
|
||||
var done=0
|
||||
{% if not COMP %}
|
||||
// Add annotations for changes greater than 5000
|
||||
{% for a in finance['annotations'] %}
|
||||
console.log( "{{a['x']}}" )
|
||||
console.log( "{{a['y']}}" )
|
||||
console.log( "{{a['label']}}" )
|
||||
annotations.push({
|
||||
labels: [{
|
||||
point: {
|
||||
x: {{a['x']}},
|
||||
y: {{a['y']}},
|
||||
crop: true,
|
||||
xAxis: 0,
|
||||
yAxis: 0
|
||||
},
|
||||
x: x,
|
||||
y: offset,
|
||||
align: al,
|
||||
text: '{{a['label']}}'
|
||||
}]
|
||||
}], labelOptions: { allowOverlap: true }
|
||||
});
|
||||
if( offset == 150 ) { offset=100 } else { offset=150 }
|
||||
if( done == 2 ) {
|
||||
if( al=='right' ) { console.log('change to left'); al='left'; x=-130 } else { console.log('change to right'); al='right'; x=130 }
|
||||
done=0
|
||||
}
|
||||
done++
|
||||
{% endfor %}
|
||||
document.keep = annotations
|
||||
{% endif %}
|
||||
|
||||
// Highcharts configuration
|
||||
Highcharts.chart('container', {
|
||||
chart: {
|
||||
type: 'line'
|
||||
},
|
||||
title: {
|
||||
text: 'Savings Over Time'
|
||||
},
|
||||
chart: { type: 'line' },
|
||||
title: { text: 'Savings Over Time' },
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
title: {
|
||||
text: 'Date'
|
||||
},
|
||||
title: { text: 'Date' },
|
||||
plotBands: plotBands // Alternating background for years
|
||||
},
|
||||
yAxis: {
|
||||
title: {
|
||||
text: 'Amount ($)'
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
labelFormatter: function () {
|
||||
return `<span title="${tooltipContent}">${legendName}</span>`;
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
pointFormat: '{point.x:%Y-%m-%d}: <b>{point.y:.2f}</b>'
|
||||
},
|
||||
yAxis: { title: { text: 'Amount ($)' } },
|
||||
legend: { labelFormatter: function () { return `<span title="${tooltipContent}">${legendName}</span>`; } },
|
||||
tooltip: { pointFormat: '{point.x:%Y-%m-%d}: <b>{point.y:.2f}</b>' },
|
||||
annotations: annotations, // Add annotations
|
||||
series: [{
|
||||
name: legendName,
|
||||
data: chartData,
|
||||
marker: {
|
||||
radius: 2, // Smaller points (default is 4)
|
||||
lineWidth: 0, // Optional: thinner border
|
||||
symbol: 'circle' // Optional: shape of the points (default is 'circle')
|
||||
}
|
||||
}]
|
||||
series: [
|
||||
{ name: legendName, data: chartData, marker: { radius: 2 } }
|
||||
{% if COMP %}
|
||||
,{ name: "TEST", data: compChartData, marker: { radius: 2 } }
|
||||
{% endif %}
|
||||
]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user