<div id="app">
    <!-- Paste MCE markup here -->
<mds-section
        bold
        :title="chartAriaLabel"
        :aria-label="chartAriaLabel"
        aria-describedby="aria-description"
    >
        <span
            id="aria-description"
            class="accessibly-hidden"
        >
            {{ chartAriaDescription }}
        </span>

        <div style="position: relative">
            <mce-hover-flag
                v-if="isFlagVisible"
                :x="hoverFlagPosition.pageX"
                :y="hoverFlagPosition.pageY"
                role="region"
                aria-live="polite"
            >
                <mce-legend
                    hide-top-border
                    hide-bottom-border
                >
                    <mce-legend-group :title="selectedData.title">
                        <mce-legend-item
                            :color="chartColors[0]"
                            :label="chartData.name"
                            :value="selectedData.value"
                            key-type="bar"
                        ></mce-legend-item>
                    </mce-legend-group>
                </mce-legend>
            </mce-hover-flag>
        </div>

        <mce-layout
            :plot-width="plotWidth"
            :plot-height="plotHeight"
            :axis-left-width="axisLeftWidth"
        >
            <template #axis-left>
                <mce-y-axis
                    :domain="domainY"
                    :range="[plotHeight, 0]"
                    :labels="yAxisLabels"
                    :tick-quantity="tickQuantity"
                ></mce-y-axis>
            </template>

            <!-- Main plot (default slot) -->
            <mce-grid
                :range-x="[0, plotWidth]"
                :range-y="[plotHeight, 0]"
                :domain-y="domainY"
                scale-type-x="band"
                :tick-quantity-y="tickQuantity"
                :outlines="{
                    top: true,
                }"
            ></mce-grid>

            <mce-bar-plot-vertical
                :mouse="mouse"
                :data="plotData"
                :data-focused="focusedData"
                :domain-y="domainY"
                :domain-x="domainX"
                :range-x="[0, plotWidth]"
                :range-y="[plotHeight, 0]"
                :color="[chartColors[0]]"
                @mousemove-plot="barPlotInteract"
                @mouseleave-plot="resetData"
            ></mce-bar-plot-vertical>
            <mce-pointer v-model="mouse"></mce-pointer>

            <template #legend-top>
                <mce-legend horizontal>
                    <mce-legend-group>
                        <mce-legend-item
                            :color="chartColors[0]"
                            :label="chartData.name"
                            key-type="bar"
                        ></mce-legend-item>
                    </mce-legend-group>
                </mce-legend>
            </template>
            <template #axis-bottom>
                <mce-x-axis
                    scale-type="band"
                    type="categorical"
                    :domain="xAxisLabels.values"
                    :labels="xAxisLabels"
                    :range="[0, plotWidth]"
                ></mce-x-axis>
            </template>
        </mce-layout>

        <!-- provide an accessible alternative for screen-readers -->
        <mds-table style="margin-top: 60px; max-width: 400px">
            <caption>
                {{
                    chartAriaLabel
                }}
            </caption>
            <mds-thead>
                <mds-th>Quintile</mds-th>
                <mds-th>Fund Closure</mds-th>
            </mds-thead>
            <mds-tbody>
                <mds-tr
                    v-for="(row, i) in chartData.data"
                    :key="i"
                >
                    <mds-td> {{ row.title }} </mds-td>
                    <mds-td> {{ row.value }} </mds-td>
                </mds-tr>
            </mds-tbody>
        </mds-table>
    </mds-section>
</div>
// All mixins, constants, and typography from MDS are available for use
@mixin mds-accessibly-hidden() {
    clip: rect(0 0 0 0);
    left: 0;
    position: absolute;
    z-index: -1;
}

.accessibly-hidden {
    @include mds-accessibly-hidden();
}
View Compiled
import { min, range } from "https://cdn.skypack.dev/d3-array@3.2.0";

const { generic } = window.utilities.color;

// Add Data
const chartData = [
    {
        name: 'Closed Fund',
        data: [
            { id: '1', title: '1 (best)', value: 434 },
            { id: '2', title: '2', value: 405 },
            { id: '3', title: '3', value: 543 },
            { id: '4', title: '4', value: 768 },
            { id: '5', title: '5 (worst)', value: 1383 },
        ],
    },
];

// Initialize and render chart
const app = new Vue({
    el: "#app",
    data() {
        // Reactive data
        return {
          colors: generic,

                // Mouse and Keyboard related data
                hoverFlagPosition: {
                    pageX: 96,
                    pageY: 70,
                },
                mouse: null,
                selectedData: {},
                focusedData: null,
                focusDataIndex: -1,

                // Plot data
                axisLeftWidth: 82,
                chartData: chartData[0],
                plotHeight: 450,
                plotWidth: 600,
                chartColors: generic,
                tickQuantity: 8,

                // Accessible content
                chartAriaLabel: 'Fund Closures by Performance Quintile (Full Life)',
                chartAriaDescription: `
                A clear relationship emerged between category-relative performance and fund closures. About 12% of all closed funds landed in the best-performing quintile of their respective category, while 39% came from the worst-performing quintile.
                Further analysis revealed a similar relationship between funds that close and their category-relative performance over their final 12 months. This relationship may prove more useful for spotting funds that are not long for this world. Trailing performance over the prior 12 months could be combined with the other characteristics examined here in assessing how likely it is that a fund will shut down.
                `,
            };
    },
    computed: {
            isFlagVisible() {
                return this.focusDataIndex > -1 || this.mouse;
            },
            yAxisLabels() {
                return { axis: 'Number of Closures' };
            },
            xAxisLabels() {
                const values = this.chartData.data.map(d => {
                    return d.title;
                });

                return {
                    values,
                    axis: 'Morningstar Category Return Quintile',
                };
            },
            plotData() {
                return this.chartData.data;
            },
            domainY() {
                const start = min(this.plotData, d => d.value) > 0 ? 0 : min(this.plotData, d => d.value);
                const end = 1400;

                // boundaries for the dataset
                return [start, end];
            },
            domainX() {
                return range(this.chartData.data.length);
            },
    },
    mounted() {
        window.addEventListener('resize', this.onResize);
        this.setSize();
    },
    destroyed() {
        window.removeEventListener('resize', this.onResize);
    },
    methods: {
        barPlotInteract(inputData) {
            // Handle logic if mode is mouse
            if (inputData.position) {
                const { data } = inputData;

                // Set array item for focussing plot
                this.focusedData = [data._itemId];

                // Update hover flag content
                this.selectedData = data;

                // Update hover flag position using mouse data
                this.hoverFlagPosition = this.mouse;
            } else {
                // Keyboard
                if (inputData === 'next') {
                    this.focusDataIndex = this.focusDataIndex + 1;
                } else {
                    this.focusDataIndex = this.focusDataIndex - 1;
                }

                // Update hover flag content
                this.selectedData = this.plotData[this.focusDataIndex];

                // Set array item for focussing plot
                this.focusedData = [this.selectedData.id];
            }
        },
        resetData() {
            this.hoverFlagPosition = {
                pageX: 96,
                pageY: 70,
            };
            this.selectedData = {};
            this.focusedData = null;
            this.focusDataIndex = -1;
        },
        setSize() {
            // these widths are default values set in the layout element
            // 16 = margin on body
            let windowWidth = window.innerWidth - 16;
            this.plotWidth = windowWidth - this.axisLeftWidth;
        },
        onResize() {
            this.setSize();
        },
    },
});
View Compiled

External CSS

  1. https://mds-static-assets.s3.amazonaws.com/sandbox/constants.scss
  2. https://mds-static-assets.s3.amazonaws.com/sandbox/fonts.scss
  3. https://mds-static-assets.s3.amazonaws.com/sandbox/typography_constants.scss
  4. https://mds-static-assets.s3.amazonaws.com/sandbox/typography.scss
  5. https://mds-static-assets.s3.amazonaws.com/sandbox/link.scss

External JavaScript

  1. https://codepen.io/morningstar-design-system/pen/WNywvEG.js
  2. https://mds-static-assets.s3.amazonaws.com/sandbox/components.js
  3. https://mds-static-assets.s3.amazonaws.com/mce-codepen/charts.js
  4. https://mds-static-assets.s3.amazonaws.com/mce-codepen/utilities.js