diff --git a/facets_dive/components/facets_dive_legend/facets-dive-legend.ts b/facets_dive/components/facets_dive_legend/facets-dive-legend.ts index c6a238d..449dbb0 100644 --- a/facets_dive/components/facets_dive_legend/facets-dive-legend.ts +++ b/facets_dive/components/facets_dive_legend/facets-dive-legend.ts @@ -41,6 +41,7 @@ Polymer({ colorBy: { type: String, value: '', + observer: '_open', }, palette: { type: Array, @@ -73,6 +74,13 @@ Polymer({ return special ? 'special' : ''; }, + /** + * Opens the legend panel if it's not open already. + */ + _open(this: any) { + this._opened = true; + }, + /** * Toggles if the legend panel is opened. */ diff --git a/facets_dive/components/facets_dive_vis/facets-dive-vis.html b/facets_dive/components/facets_dive_vis/facets-dive-vis.html index 88582c6..cf093cd 100644 --- a/facets_dive/components/facets_dive_vis/facets-dive-vis.html +++ b/facets_dive/components/facets_dive_vis/facets-dive-vis.html @@ -42,6 +42,18 @@ @apply --paper-font-common-base; @apply --paper-font-headline; } + ::content .rotate { + stroke-dasharray: 1.5, 0.5; + animation: rotate 1s linear infinite; + } + @keyframes rotate { + from { + stroke-dashoffset: 0; + } + to { + stroke-dashoffset: 2; + } + } diff --git a/facets_dive/components/facets_dive_vis/facets-dive-vis.ts b/facets_dive/components/facets_dive_vis/facets-dive-vis.ts index ff08f93..824d179 100644 --- a/facets_dive/components/facets_dive_vis/facets-dive-vis.ts +++ b/facets_dive/components/facets_dive_vis/facets-dive-vis.ts @@ -65,22 +65,52 @@ export const CELL_BACKGROUND_FILL_COLOR = '#f8f8f9'; /** * Color for selected item borders. */ -const SELECTED_ITEM_COLOR = '#da7421'; +const SELECTED_ITEM_COLOR = '#fad411'; + +/** + * Color for stroke around selected item borders. + */ +const SELECTED_ITEM_COLOR_STROKE = '#826e09'; /** * Stroke width for the selected item borders. */ -const SELECTED_ITEM_STROKE_WIDTH = 0.1; +const SELECTED_ITEM_STROKE_WIDTH = 0.15; + +/** + * Scale of selected highlight box initially before fade-in. + */ +const SELECTED_ITEM_INITIAL_SCALE = 3; + +/** + * Final scale of selected highlight box after fade-in. + */ +const SELECTED_ITEM_FINAL_SCALE = 0.8; /** * Color for compared item borders. */ const COMPARED_ITEM_COLOR = '#16dcfb'; +/** + * Color for stroke around compared item borders. + */ +const COMPARED_ITEM_COLOR_STROKE = '#0b6371'; + /** * Stroke width for the compared item borders. */ -const COMPARED_ITEM_STROKE_WIDTH = 0.1; +const COMPARED_ITEM_STROKE_WIDTH = 0.15; + +/** + * Scale of compared highlight box initially before fade-in. + */ +const COMPARED_ITEM_INITIAL_SCALE = 3; + +/** + * Final scale of compared highlight box after fade-in. + */ +const COMPARED_ITEM_FINAL_SCALE = 0.8; /** * Precision to use for numeric labels in digits. @@ -1003,29 +1033,59 @@ class FacetsDiveVizInternal { const selectedElements = this.selectedLayer.selectAll('.selected').data(selectedBoxes); - selectedElements - // ENTER. + // ENTER. + const enterElements = selectedElements .enter() + .append('g') + .classed('selected', true) + .attr('transform', (pos: ItemPosition) => { + const x = 0.5 + (pos.x || 0); + const y = 0.5 + (pos.y || 0); + return `translate(${x},${y}) scale(${SELECTED_ITEM_INITIAL_SCALE})`; + }) + .style('opacity', 0); + + enterElements .append('rect') - .attr('class', 'selected') - .attr('x', (pos: ItemPosition) => pos.x || 0) - .attr('y', (pos: ItemPosition) => pos.y || 0) + .attr('x', -0.5) + .attr('y', -0.5) .attr('width', 1) .attr('height', 1) - .attr('stroke', SELECTED_ITEM_COLOR) + .attr('stroke', SELECTED_ITEM_COLOR_STROKE) + .attr('stroke-linecap', 'round') + .attr('stroke-linejoin', 'round') .attr('stroke-opacity', 0) - .attr('stroke-width', SELECTED_ITEM_STROKE_WIDTH) - .attr('fill-opacity', 0) - // ENTER + UPDATE. - .merge(selectedElements) - .attr('x', (pos: ItemPosition) => pos.x || 0) - .attr('y', (pos: ItemPosition) => pos.y || 0) + .attr('stroke-width', SELECTED_ITEM_STROKE_WIDTH * 2) + .attr('fill-opacity', 0); + enterElements + .append('rect') + .attr('x', -0.5) + .attr('y', -0.5) .attr('width', 1) .attr('height', 1) + .attr('stroke', SELECTED_ITEM_COLOR) + .attr('stroke-linecap', 'round') + .attr('stroke-linejoin', 'round') + .attr('stroke-opacity', 0) + .attr('stroke-width', SELECTED_ITEM_STROKE_WIDTH) + .attr('fill-opacity', 0); + + // ENTER + UPDATE. + const mergedElements = enterElements.merge(selectedElements); + mergedElements.transition() + .attr('transform', (pos: ItemPosition) => { + const x = 0.5 + (pos.x || 0); + const y = 0.5 + (pos.y || 0); + return `translate(${x},${y}) scale(${SELECTED_ITEM_FINAL_SCALE})`; + }) + .style('opacity', 1); + mergedElements + .selectAll('rect') + .classed('rotate', true) .attr('stroke-opacity', 1); // EXIT. - selectedElements.exit().remove(); + selectedElements.exit().transition().style('opacity', 0).remove(); } /** @@ -1045,29 +1105,59 @@ class FacetsDiveVizInternal { const comparedElements = this.comparedLayer.selectAll('.compared').data(comparedBoxes); - comparedElements - // ENTER. + // ENTER. + const enterElements = comparedElements .enter() + .append('g') + .classed('compared', true) + .attr('transform', (pos: ItemPosition) => { + const x = 0.5 + (pos.x || 0); + const y = 0.5 + (pos.y || 0); + return `translate(${x},${y}) scale(${COMPARED_ITEM_INITIAL_SCALE})`; + }) + .style('opacity', 0); + + enterElements .append('rect') - .attr('class', 'compared') - .attr('x', (pos: ItemPosition) => pos.x || 0) - .attr('y', (pos: ItemPosition) => pos.y || 0) + .attr('x', -0.5) + .attr('y', -0.5) .attr('width', 1) .attr('height', 1) - .attr('stroke', COMPARED_ITEM_COLOR) + .attr('stroke', COMPARED_ITEM_COLOR_STROKE) + .attr('stroke-linecap', 'round') + .attr('stroke-linejoin', 'round') .attr('stroke-opacity', 0) - .attr('stroke-width', COMPARED_ITEM_STROKE_WIDTH) - .attr('fill-opacity', 0) - // ENTER + UPDATE. - .merge(comparedElements) - .attr('x', (pos: ItemPosition) => pos.x || 0) - .attr('y', (pos: ItemPosition) => pos.y || 0) + .attr('stroke-width', COMPARED_ITEM_STROKE_WIDTH * 2) + .attr('fill-opacity', 0); + enterElements + .append('rect') + .attr('x', -0.5) + .attr('y', -0.5) .attr('width', 1) .attr('height', 1) + .attr('stroke', COMPARED_ITEM_COLOR) + .attr('stroke-linecap', 'round') + .attr('stroke-linejoin', 'round') + .attr('stroke-opacity', 0) + .attr('stroke-width', COMPARED_ITEM_STROKE_WIDTH) + .attr('fill-opacity', 0); + + // ENTER + UPDATE. + const mergedElements = enterElements.merge(comparedElements); + mergedElements.transition() + .attr('transform', (pos: ItemPosition) => { + const x = 0.5 + (pos.x || 0); + const y = 0.5 + (pos.y || 0); + return `translate(${x},${y}) scale(${COMPARED_ITEM_FINAL_SCALE})`; + }) + .style('opacity', 1); + mergedElements + .selectAll('rect') + .classed('rotate', true) .attr('stroke-opacity', 1); // EXIT. - comparedElements.exit().remove(); + comparedElements.exit().transition().style('opacity', 0).remove(); } /**