<commit_before>import { inject, bindable, DOM } from 'aurelia-framework';
import * as d3lib from 'd3';

@inject(d3lib, DOM.Element)
export class DonutChartComponent {
    @bindable public chartData: Array<any>;
    @bindable public color: Function;

    private d3;
    private element: HTMLElement;
    private arc: Function;
    private pie: Function;
    private svg;
    private path;
    private size: number;

    constructor (d3lib, element: HTMLElement) {
        this.d3 = d3lib;
        this.element = element;
    }

    /**
     * lifecycle callback
     * sets up the size based on the host element
     *
     * @memberOf DonutChartComponent
     */
    public attached () {
        const rect = this.element.getBoundingClientRect();
        this.size = Math.floor(rect.width);
    }

    /**
     * attribute change listener
     * initializes or updates the chart
     *
     * @param {Arra<any>} [data=[]]
     * @returns
     *
     * @memberOf DonutChartComponent
     */
    public chartDataChanged (data: Array<any> = []) {
        if (!this.size) {
            return;
        }

        if (!this.svg) {
            this.createElements(this.element, this.size);
            this.initialize(this.svg, data, this.color);
            return;
        }

        this.update(this.svg, data, this.color);
    }

    /**
     * initializes the reusable chart elements
     *
     * @private
     * @param {HTMLElement} element
     * @param {number} size
     *
     * @memberOf DonutChartComponent
     */
    private createElements (element: HTMLElement, size: number) {
        const radius = size / 2;
        this.arc = this.d3.arc()
            .outerRadius(radius)
            .innerRadius(radius * 0.6);

        this.pie = this.d3.pie()
            .value((d: any) => d.count)
            .sort(null)
            .padAngle(0.05);

        this.svg = this.d3.select(element).append('svg')
            .attr('width', size)
            .attr('height', size)
            .append('g')
            .attr('transform', `translate(${radius},${radius})`);
    }

    /**
     * sets up the chart, including enter animations
     *
     * @private
     * @param {any} svg
     * @param {any} data
     * @param {any} color
     *
     * @memberOf DonutChartComponent
     */
    private initialize (svg, data, color) {
        this.path = svg.selectAll('path')
            .data(this.pie(data))
            .enter()
            .append('path')
            .attr('d', this.arc)
            .attr('fill', d => color(d.data.id));

        this.path.transition()
            .duration(1000)
            .attrTween('d', this.getArcTween());
    }

    /**
     * redraws the chart
     *
     * @private
     * @param {any} svg
     * @param {any} data
     * @param {any} color
     *
     * @memberOf DonutChartComponent
     */
    private update (svg, data: Array<any>, color: Function) {
        const arcs = svg.selectAll('path')
            .data(this.pie(data));

        const exit = arcs.exit();
        const enter = arcs.enter().append('path');
        const enterUpdate = enter.merge(arcs);

        enterUpdate
            .attr('d', this.arc)
            .attr('fill', d => color(d.data.id));

        exit.transition()
            .duration(600)
            .attrTween('d', this.getArcTween())
            .remove();

        enter.transition()
            .duration(600)
            .attrTween('d', this.getArcTween());
    }

    private getArcTween (base: Object = { endAngle: 0, startAngle: 0 }) {
        return (d) => {
            const interpolate = this.d3.interpolateObject(base, d);
            return t => this.arc(interpolate(t));
        };
    }
}
<commit_msg>feat(donut-chart-component): saveArcs, transition update<commit_after>import { inject, bindable, DOM } from 'aurelia-framework';
import * as d3lib from 'd3';

@inject(d3lib, DOM.Element)
export class DonutChartComponent {
    @bindable public chartData: any[];
    @bindable public color: Function;

    private d3;
    private element: HTMLElement;
    private arc: Function;
    private pie: Function;
    private svg;
    private size: number;
    private arcLookup: Object = {};

    constructor (d3lib, element: HTMLElement) {
        this.d3 = d3lib;
        this.element = element;
    }

    /**
     * lifecycle callback
     * sets up the size based on the host element
     *
     * @memberOf DonutChartComponent
     */
    public attached () {
        const rect = this.element.getBoundingClientRect();
        this.size = Math.floor(rect.width);
    }

    /**
     * attribute change listener
     * initializes or updates the chart
     *
     * @param {Arra<any>} [data=[]]
     * @returns
     *
     * @memberOf DonutChartComponent
     */
    public chartDataChanged (data: any[] = []) {
        if (!this.size) {
            return;
        }

        if (!this.svg) {
            this.createElements(this.element, this.size);
            this.initialize(this.svg, data, this.color);
            return;
        }

        this.update(this.svg, data, this.color);
    }

    /**
     * initializes the reusable chart elements
     *
     * @private
     * @param {HTMLElement} element
     * @param {number} size
     *
     * @memberOf DonutChartComponent
     */
    private createElements (element: HTMLElement, size: number) {
        const radius = size / 2;
        this.arc = this.d3.arc()
            .outerRadius(radius)
            .innerRadius(radius * 0.6);

        this.pie = this.d3.pie()
            .value((d: any) => d.count)
            .sort(null)
            .padAngle(0.05);

        this.svg = this.d3.select(element).append('svg')
            .attr('width', size)
            .attr('height', size)
            .append('g')
            .attr('transform', `translate(${radius},${radius})`);
    }

    /**
     * sets up the chart, including enter animations
     *
     * @private
     * @param {any} svg
     * @param {any} data
     * @param {any} color
     *
     * @memberOf DonutChartComponent
     */
    private initialize (svg, data, color) {
        const arcs = svg.selectAll('path')
            .data(this.pie(data))
            .enter()
            .append('path')
            .attr('d', this.arc)
            .attr('fill', d => color(d.data.id));

        arcs.transition()
            .duration(1000)
            .attrTween('d', this.getArcTween())
            .on('end', () => this.saveArcs(arcs));
    }

    /**
     * redraws the chart
     *
     * @private
     * @param {any} svg
     * @param {any} data
     * @param {any} color
     *
     * @memberOf DonutChartComponent
     */
    private update (svg, data: any[], color: Function) {
        const arcs = svg.selectAll('path')
            .data(this.pie(data));

        const exit = arcs.exit();
        const enter = arcs.enter().append('path');
        const enterUpdate = enter.merge(arcs);

        enterUpdate.attr('fill', d => color(d.data.id));

        // update
        arcs.transition()
            .duration(600)
            .attrTween('d', (d) => {
                const base = this.arcLookup[d.data.id];
                this.getArcTween(base)(d);
            })
            .on('end', () => this.saveArcs(enterUpdate));

        // exit
        exit.transition()
            .duration(600)
            .attrTween('d', this.getArcTween())
            .remove();

        // enter
        enter.transition()
            .duration(600)
            .attrTween('d', this.getArcTween());
    }

    private saveArcs (arcs: any) {
        arcs.each((arc) => {
            this.arcLookup[arc.data.id] = {
                endAngle: arc.endAngle,
                startAngle: arc.startAngle
            };
        });
    }

    private getArcTween (base: Object = { endAngle: 0, startAngle: 0 }) {
        return (d) => {
            const interpolate = this.d3.interpolateObject(base, d);
            return t => this.arc(interpolate(t));
        };
    }
}

{'fraction_non_alphanumeric': 0.139261114589856, 'fraction_numerical': 0.0076393237319974956, 'mean_word_length': 1.7652354570637119, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '254567', 'n_tokens_mistral': 2478, 'n_tokens_neox': 2410, 'n_words': 531}