Skip to content

Commit

Permalink
Add test spark line
Browse files Browse the repository at this point in the history
  • Loading branch information
vkoves committed Aug 21, 2024
1 parent 530d507 commit 57f552f
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 6 deletions.
9 changes: 3 additions & 6 deletions src/components/BarGraph.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
v-html="graphTitle"
/>

<svg><!-- D3 inserts here --></svg>
<svg id="bar-graph"><!-- D3 inserts here --></svg>
</div>
</template>

Expand All @@ -21,10 +21,7 @@ export interface IGraphPoint {
/**
* A component that can graph an arbitrary array of numeric data
*/
@Component({
components: {
},
})
@Component({})
export default class BarGraph extends Vue {
@Prop({required: true}) graphTitle!: string;
Expand All @@ -48,7 +45,7 @@ export default class BarGraph extends Vue {
const outerHeight = this.height + this.graphMargins.top + this.graphMargins.bottom;
this.svg = d3
.select("svg")
.select("svg#bar-graph")
.attr("width", outerWidth)
.attr("height", outerHeight)
.attr("viewBox", `0 0 ${outerWidth} ${outerHeight}`)
Expand Down
129 changes: 129 additions & 0 deletions src/components/SparkLine.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<template>
<div class="bar-graph-cont">
<div
class="label"
v-html="graphTitle"

Check warning

Code scanning / ESLint

disallow use of v-html to prevent XSS attack Warning

'v-html' directive can lead to XSS attack.
/>

<svg :id="'spark' + randomId"><!-- D3 inserts here --></svg>
</div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import * as d3 from 'd3';
export interface IGraphPoint {
x: number | string;
y: number;
}
/**
* A component that can graph an arbitrary array of numeric data as a spark line, a simple line
* graph (like might be used in a news chevron for a stock)
*/
@Component({})
export default class BarGraph extends Vue {
@Prop({required: true}) graphTitle!: string;
@Prop({required: true}) graphData!: Array<IGraphPoint>;
@Watch('graphData')
onDataChanged(): void {
this.renderGraph();
}
readonly width = 800;
readonly height = 400;
readonly graphMargins = { top: 30, right: 30, bottom: 50, left: 60 };
readonly barMargin = 0.2;
randomId = Math.round(Math.random() * 1000);
svg!: d3.Selection<SVGGElement, unknown, HTMLElement, any>;

Check warning

Code scanning / ESLint

Disallow the `any` type Warning

Unexpected any. Specify a different type.
mounted(): void {
const outerWidth = this.width + this.graphMargins.left + this.graphMargins.right;
const outerHeight = this.height + this.graphMargins.top + this.graphMargins.bottom;
this.svg = d3
.select("svg#spark" + this.randomId)
.attr("width", outerWidth)
.attr("height", outerHeight)
.attr("viewBox", `0 0 ${outerWidth} ${outerHeight}`)
.attr("preserveAspectRatio", "xMidYMid meet")
.append("g")
.attr("transform", `translate(${this.graphMargins.left},${this.graphMargins.top})`);
this.renderGraph();
}
renderGraph(): void {
// Empty the SVG
this.svg.html(null);
const xVals: Array<string> = this.graphData.map((d) => d.x.toString());
const yVals: Array<number> = this.graphData.map((d) => d.y);
const x = d3
.scaleBand()
.range([0, this.width])
.domain(xVals)
.padding(this.barMargin);
const y = d3
.scaleLinear()
.domain([ d3.min(yVals) as number, d3.max(yVals) as number])
.rangeRound([this.height, 0]);
// Render X axis
this.svg.append("g")
.attr("transform", `translate(0, ${this.height})`)
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Render Y axis
this.svg.append("g")
.call(d3.axisLeft(y));
// Add the line
this.svg.append("path")
.datum(this.graphData)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 10)
.attr("d", (d3.line() as any)

Check warning

Code scanning / ESLint

Disallow the `any` type Warning

Unexpected any. Specify a different type.
.x((d: IGraphPoint) => { return x(d.x.toString()) })

Check failure

Code scanning / ESLint

Require or disallow semicolons instead of ASI Error

Missing semicolon.
.y((d: IGraphPoint) => { return y(d.y) })

Check failure

Code scanning / ESLint

Require or disallow semicolons instead of ASI Error

Missing semicolon.
)

Check failure

Code scanning / ESLint

Require or disallow trailing commas Error

Missing trailing comma.
}

Check failure

Code scanning / ESLint

Require or disallow semicolons instead of ASI Error

Missing semicolon.
}
</script>

<style lang="scss">
.bar-graph-cont {
margin: 1rem 0;
.label {
font-weight: bold;
font-size: 1.25rem;
margin-bottom: 0.5rem;
}
svg {
width: 100%;
border: solid $border-thin $grey-light;
aspect-ratio: 2;
height: auto;
max-width: 50rem;
}
.tick {
font-weight: bold;
font-size: 1rem;
}
}
</style>
7 changes: 7 additions & 0 deletions src/templates/BuildingDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,11 @@ query ($id: ID!, $ID: String) {
:graph-title="currGraphTitle"
/>

<SparkLine
:graph-data="currGraphData"
:graph-title="currGraphTitle"
/>

<p class="constrained">
<strong>* Note on Rankings:</strong> Rankings and medians are among <em>included</em>
buildings, which are those who reported under the Chicago Energy Benchmarking Ordinance for
Expand Down Expand Up @@ -471,6 +476,7 @@ import { Component, Vue } from 'vue-property-decorator';

import { LatestDataYear } from '../constants/globals.vue';
import BarGraph from '~/components/BarGraph.vue';
import SparkLine from '~/components/SparkLine.vue';
import BuildingImage from '~/components/BuildingImage.vue';
import DataSourceFootnote from '~/components/DataSourceFootnote.vue';
import HistoricalBuildingDataTable from '~/components/HistoricalBuildingDataTable.vue';
Expand Down Expand Up @@ -499,6 +505,7 @@ import { IGraphPoint } from '../components/BarGraph.vue';
},
components: {
BarGraph,
SparkLine,
BuildingImage,
DataSourceFootnote,
NewTabIcon,
Expand Down

0 comments on commit 57f552f

Please sign in to comment.