activator-oce-exporter
Version:
Extract Activator binder and convert it to valid OCE mono pacakge
838 lines (793 loc) • 22 kB
JavaScript
import { html } from '@polymer/lit-element';
import { generate } from 'c3';
import { formatDefaultLocale, format } from 'd3-format';
import { FusionBase } from '../../base';
import {
compileObjectFromContext,
mergeObj,
getValueObject,
debounce, intersectMap,
} from '../../utils';
import { FusionApi } from '../../api';
import { applyMixins, Font, SlideComponent } from '../../mixins';
const predefinedContext = require.context('d3-format/locale', true, /\.json$/);
const customContext = require.context('./locale', true, /\.json$/);
const predefinedLocales = compileObjectFromContext(predefinedContext);
const customLocales = compileObjectFromContext(customContext);
const locales = { ...predefinedLocales, ...customLocales };
class FusionChart extends applyMixins(FusionBase, [SlideComponent, Font]) {
static get properties() {
const {
top,
left,
'font-family': fontFamily,
'font-weight': fontWeight,
} = super.properties;
const localeNames = Object.keys(locales);
return {
top,
left,
width: {
type: String,
fieldType: 'Number',
value: '800px',
min: '400',
},
height: {
type: String,
fieldType: 'Number',
value: '400px',
min: '200',
},
locale: {
type: String,
fieldType: 'Select',
value: 'en-GB',
selectOptions: localeNames,
},
'font-family': fontFamily,
'show-labels': {
type: Boolean,
fieldType: 'Boolean',
value: false,
prop: true,
},
'labels-position': {
type: String,
fieldType: 'Select',
value: 'outer',
prop: true,
selectOptions: [
'outer',
'inner',
],
},
'labels-inner-indent': {
type: String,
fieldType: 'Number',
value: '0px',
},
'labels-font-size': {
type: String,
fieldType: 'Number',
value: '10px',
},
'labels-font-weight': fontWeight,
'labels-color': {
type: String,
fieldType: 'ColorPicker',
value: 'rgba(0, 0, 0, 1)',
},
'show-legend': {
type: Boolean,
fieldType: 'Boolean',
value: true,
prop: true,
},
'legend-position': {
type: String,
fieldType: 'Select',
value: 'inset',
prop: true,
selectOptions: [
'bottom',
'right',
'inset',
],
},
'show-tooltip': {
type: Boolean,
fieldType: 'Boolean',
value: true,
prop: true,
},
'grouped-tooltip': {
type: Boolean,
fieldType: 'Boolean',
value: true,
prop: true,
},
'x-axis-type': {
type: String,
fieldType: 'Select',
value: 'category',
prop: true,
selectOptions: [
'category',
'indexed',
],
},
'x-axis-tick-rotate': {
type: String,
fieldType: 'Number',
value: '0px',
prop: true,
},
'x-axis-tick-height': {
type: String,
fieldType: 'Number',
value: '0px',
prop: true,
},
'x-axis-font-size': {
type: String,
fieldType: 'Number',
value: '10px',
},
'x-axis-font-weight': fontWeight,
'x-axis-label-text': {
type: String,
fieldType: 'String',
value: '',
prop: true,
},
'x-axis-label-position': {
type: String,
fieldType: 'Select',
value: 'outer-center',
prop: true,
selectOptions: [
'inner-right',
'inner-center',
'inner-left',
'outer-right',
'outer-center',
'outer-left',
],
},
'x-axis-label-font-size': {
type: String,
fieldType: 'Number',
value: '10px',
},
'x-axis-label-font-weight': fontWeight,
'x-axis-label-color': {
type: String,
fieldType: 'ColorPicker',
value: 'rgba(0, 0, 0, 1)',
},
'y-axis-font-size': {
type: String,
fieldType: 'Number',
value: '10px',
},
'y-axis-font-weight': fontWeight,
'y-axis-label-text': {
type: String,
fieldType: 'String',
value: '',
prop: true,
},
'y-axis-label-position': {
type: String,
fieldType: 'Select',
value: 'outer-middle',
prop: true,
selectOptions: [
'inner-top',
'inner-middle',
'inner-bottom',
'outer-top',
'outer-middle',
'outer-bottom',
],
},
'y-axis-label-font-size': {
type: String,
fieldType: 'Number',
value: '10px',
},
'y-axis-label-font-weight': fontWeight,
'y-axis-label-color': {
type: String,
fieldType: 'ColorPicker',
value: 'rgba(0, 0, 0, 1)',
},
'axis-rotate': {
type: Boolean,
fieldType: 'Boolean',
value: false,
prop: true,
},
'show-grid': {
type: Boolean,
fieldType: 'Boolean',
value: false,
prop: true,
},
'show-line-point': {
type: Boolean,
fieldType: 'Boolean',
value: false,
prop: true,
},
};
}
static get options() {
return {
componentName: 'fusion-chart',
componentUIName: 'Chart',
componentScope: 'standard',
componentType: 'static',
componentCategory: 'data',
componentDescription: 'Fully configurable chart accepting any number of data series',
componentDomain: 'slide',
isTextEdit: false,
isRootNested: true,
nestedTypes: [],
nestedComponents: ['fusion-chart-data'],
defaultTemplate: '',
resizable: 'all',
draggable: 'xy',
rotatable: true,
sortable: false,
};
}
constructor() {
super();
this.series = [];
this.drawChartBinded = this.drawChart.bind(this);
this.updaterBinded = this.updateData.bind(this);
this.removerBinded = this.removeData.bind(this);
this.propsChange(this.setStaticPropsValues);
}
propsChange(cb) {
super.propsChange(cb);
}
setStaticPropsValues(key, item) {
if (item.prop) this[key] = this.getAttribute(key);
}
connectedCallback() {
super.connectedCallback();
}
disconnectedCallback() {
this.chart.destroy();
this.shadowRoot.querySelector('slot:not([name])').removeEventListener('slotchange', this.drawChartBinded);
this.querySelectorAll('fusion-chart-data').forEach(el => el.removeEventListener('update', this.updaterBinded));
this.querySelectorAll('fusion-chart-data').forEach(el => el.removeEventListener('remove', this.removerBinded));
super.disconnectedCallback();
}
revertAxis() {
const tmp = this.chartOptions.axis.x.label.position;
this.chartOptions.axis.x.label.position = this.chartOptions.axis.y.label.position;
this.chartOptions.axis.y.label.position = tmp;
}
updateProps() {
const currentProps = this.getPropsOptions();
this.chartOptions = mergeObj(this.chartOptions, currentProps);
if (this.chartOptions.axis.rotated) this.revertAxis();
debounce(this.generateChart);
}
update(changedProps) {
super.update(changedProps);
if (changedProps.has('locale')) {
const d3GroupSeparator = ',';
formatDefaultLocale(locales[this.locale]);
this.localeFormat = format(d3GroupSeparator);
}
if (this.chartOptions) {
this.updateProps();
}
}
checkSizes(changedProps) {
const properties = intersectMap(changedProps, this.constructor.sizeTriggers);
Array.from(properties.keys()).forEach((prop) => {
const { num, unit } = getValueObject(this[prop]);
const value = Math.max(num, this.constructor.properties[prop].min);
this.setElementProp(prop, `${value}${unit}`);
this.setAttribute(prop, `${value}${unit}`);
});
this.chartResize();
}
chartResize() {
if (this.chart) {
this.chart.resize();
this.chart.internal.selectChart.style('max-height', 'none');
}
}
static changeChartDataId(chartDataEl) {
const chartDataId = FusionApi.generateId();
chartDataEl.setAttribute('chart-data-id', chartDataId);
FusionApi.saveAttributes(`#${chartDataEl.id}`, { ['chart-data-id']: chartDataId }, true);
return chartDataId;
}
static checkChartDataIdDuplication(list) {
list.reduce((ids, next) => {
let id = next.getAttribute('chart-data-id');
if (ids.includes(id)) {
id = FusionChart.changeChartDataId(next);
}
ids.push(id);
return ids;
}, []);
return list;
}
getChartDataList() {
const list = [...this.querySelectorAll('fusion-chart-data')];
return FusionChart.checkChartDataIdDuplication(list);
}
getSeriesIdList() {
return this.series.map(s => s.id);
}
drawChart() {
this.chartDataList = this.mutateChartData();
this.drawChartData();
}
mutateChartData() {
const seriesIdList = this.getSeriesIdList();
const chartDataList = this.getChartDataList();
if (chartDataList.length > seriesIdList.length) {
this.addItemToSerie([...chartDataList], seriesIdList);
}
return chartDataList;
}
addItemToSerie(chartDataList, seriesIdList) {
const item = chartDataList.shift();
if (item && !seriesIdList.includes(item.getAttribute('chart-data-id'))) {
item.addEventListener('update', this.updaterBinded);
item.addEventListener('remove', this.removerBinded);
this.series.push(FusionChart.createSerie(item));
}
if (chartDataList.length > 0) this.addItemToSerie(chartDataList, seriesIdList);
}
updateData({ target }) {
const index = this.getIndex(target.getAttribute('chart-data-id'));
const newSerie = FusionChart.createSerie(this.chartDataList[index]);
this.series.splice(index, 1, newSerie);
this.drawChartData();
}
async removeData({ target }) {
const index = this.getIndex(target.getAttribute('chart-data-id'));
this.series.splice(index, 1);
target.removeEventListener('update', this.updaterBinded);
target.removeEventListener('remove', this.removerBinded);
await this.updateComplete;
this.generateChart();
}
getIndex(id) {
return this.series.findIndex(i => i.id === id);
}
static createSerie(el) {
const id = el.getAttribute('chart-data-id');
const legend = el.hasAttribute('legend') ? el.getAttribute('legend') : id;
const values = el.hasAttribute('values') ? el.getAttribute('values').split(',').map(i => Number(i)) : [];
const color = el.getAttribute('chart-color');
const type = el.getAttribute('type');
const groups = el.getAttribute('groups') || false;
return {
id, legend, color, values, type, groups,
};
}
drawChartData() {
const {
columns, colors, types, names, groups,
} = this.gatheringData();
this.chartOptions.data = {
...this.chartOptions.data, columns, colors, types, names, groups,
};
this.updateChart(this.chartOptions.data);
}
gatheringData() {
const res = {
types: {},
colors: {},
names: {},
};
const grouped = [];
const columns = this.series.map((item) => {
FusionChart.groupingData(item, grouped);
res.types = FusionChart.dataAssign(res.types, item, 'type');
res.colors = FusionChart.dataAssign(res.colors, item, 'color');
res.names = FusionChart.dataAssign(res.names, item, 'legend');
return [item.id, ...item.values];
});
return { ...res, ...{ columns, groups: [grouped] } };
}
updateChart(data) {
this.chart.unload({
done: () => {
this.chart.load(data);
this.chart.groups(data.groups);
},
});
}
static groupingData(item, grouped) {
if (item.groups) {
grouped.push(item.id);
}
}
static dataAssign(data, item, prop) {
return { ...data, [item.id]: item[prop] };
}
initChartOptions() {
const graphOpt = this.getGraphOptions();
const propsOpt = this.getPropsOptions();
return mergeObj(propsOpt, graphOpt);
}
getGraphOptions() {
const { shadowRoot, updateLabelsByPosition, id } = this;
const updateLabelsBound = updateLabelsByPosition.bind(this);
const el = shadowRoot.getElementById('chart');
return {
bindto: el,
data: {
columns: [],
groups: [],
},
onresized() {
this.selectChart.style('max-height', 'none');
},
onrendered() {
const labels = this.main.selectAll(`.${this.CLASS.texts} .${this.CLASS.text}`);
if (labels.data().length) {
labels.classed(`custom-labels-${id}`, true);
updateLabelsBound();
}
},
};
}
getPropsOptions() {
return {
size: {
height: getValueObject(this.height).num,
width: getValueObject(this.width).num,
},
data: {
labels: {
format: this.localeFormat,
},
},
legend: {
show: this['show-legend'],
position: this['legend-position'],
},
tooltip: {
show: this['show-tooltip'],
grouped: this['grouped-tooltip'],
order: 'desc',
format: this.localeFormat,
},
axis: {
rotated: this['axis-rotate'],
x: {
label: {
text: this['x-axis-label-text'],
position: this['x-axis-label-position'],
},
type: this['x-axis-type'],
tick: {
rotate: getValueObject(this['x-axis-tick-rotate']).num,
format: this.localeFormat,
},
height: getValueObject(this['x-axis-tick-height']).num,
},
y: {
label: {
text: this['y-axis-label-text'],
position: this['y-axis-label-position'],
},
tick: {
format: this.localeFormat,
},
},
},
grid: {
y: {
show: this['show-grid'],
},
x: {
show: this['show-grid'],
},
},
point: {
show: this['show-line-point'],
},
};
}
generateChart() {
this.chart = generate(this.chartOptions);
this.drawChartData();
}
slotChanges() {
this.shadowRoot.querySelector('slot:not([name])').addEventListener('slotchange', this.drawChartBinded);
}
firstUpdated(changedProps) {
super.firstUpdated(changedProps);
this.slotChanges();
this.chartOptions = this.initChartOptions();
this.chartDataList = this.mutateChartData();
this.generateChart();
}
updateLabelsByPosition() {
const position = this.getChartRotation();
if (this['labels-position'] === 'inner') {
this.setLabelsPosition(position);
}
}
getChartRotation() {
return this['axis-rotate'] ? 'horizontal' : 'vertical';
}
setLabelsPosition(position) {
const { coordinate, property, isNegative } = FusionChart.getLabelPresets()[position];
const sign = isNegative ? '-' : '';
const indent = getValueObject(this['labels-inner-indent']).num;
const labels = Array.from(this.shadowRoot.querySelectorAll(`.custom-labels-${this.id}`));
labels.map(text => text.setAttribute(coordinate, `${sign}${text.getBBox()[property] + indent}`));
}
static getLabelPresets() {
return {
horizontal: {
property: 'width',
coordinate: 'dx',
isNegative: true,
},
vertical: {
property: 'height',
coordinate: 'dy',
isNegative: false,
},
};
}
static getStyle() {
const styleRoot = super.getStyle();
return `
${styleRoot}
:host {
display: block;
}
:host #chart {
margin: 0 auto;
height: var(--height);
font-family: var(--font-family);
text-align: center;
z-index: 1;
}
/*-- Chart --*/
.c3 svg {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.c3 path, .c3 line {
fill: none;
stroke: #000000;
}
.c3 text {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.c3-text {
fill: var(--labels-color) !important;
font-size: var(--labels-font-size);
font-weight: var(--labels-font-weight);
}
.c3-axis-x {
font-size: var(--x-axis-font-size);
font-weight: var(--x-axis-font-weight);
}
.c3-axis-x-label {
fill: var(--x-axis-label-color);
font-size: var(--x-axis-label-font-size);
font-weight: var(--x-axis-label-font-weight);
}
.c3-axis-y {
font-size: var(--y-axis-font-size);
font-weight: var(--y-axis-font-weight);
}
.c3-axis-y-label {
fill: var(--y-axis-label-color);
font-size: var(--y-axis-label-font-size);
font-weight: var(--y-axis-label-font-weight);
}
.c3-legend-item-tile,
.c3-xgrid-focus,
.c3-ygrid,
.c3-event-rect,
.c3-bars path {
shape-rendering: crispEdges;
}
.c3-chart-arc path {
stroke: #ffffff;
}
.c3-chart-arc rect {
stroke: white;
stroke-width: 1;
}
.c3-chart-arc text {
fill: #ffffff;
font-size: 13px;
}
/*-- Axis --*/
/*-- Grid --*/
.c3-grid line {
stroke: #aaaaaa;
}
.c3-grid text {
fill: #aaaaaa;
}
.c3-xgrid, .c3-ygrid {
stroke-dasharray: 3 3;
}
/*-- Text on Chart --*/
.c3-text.c3-empty {
fill: #808080;
font-size: 2em;
}
/*-- Line --*/
.c3-line {
stroke-width: 1px;
}
/*-- Point --*/
.c3-circle._expanded_ {
stroke-width: 1px;
stroke: white;
}
.c3-selected-circle {
fill: white;
stroke-width: 2px;
}
/*-- Bar --*/
.c3-bar {
stroke-width: 0;
}
.c3-bar._expanded_ {
fill-opacity: 1;
fill-opacity: 0.75;
}
/*-- Focus --*/
.c3-target.c3-focused {
opacity: 1;
}
.c3-target.c3-focused path.c3-line, .c3-target.c3-focused path.c3-step {
stroke-width: 2px;
}
.c3-target.c3-defocused {
opacity: 0.3 !important;
}
/*-- Region --*/
.c3-region {
fill: steelblue;
fill-opacity: 0.1;
}
/*-- Brush --*/
.c3-brush .extent {
fill-opacity: 0.1;
}
/*-- Select - Drag --*/
/*-- Legend --*/
.c3-legend-item {
font-size: 12px;
}
.c3-legend-item-hidden {
opacity: 0.15;
}
.c3-legend-background {
opacity: 0.75;
fill: transparent;
stroke: lightgray;
stroke-width: 0;
}
/*-- Title --*/
.c3-title {
font-size: 14px;
}
/*-- Tooltip --*/
.c3-tooltip-container {
z-index: 10;
}
.c3-tooltip {
border-collapse: collapse;
border-spacing: 0;
background-color: #ffffff;
empty-cells: show;
-webkit-box-shadow: 7px 7px 12px -9px #777777;
-moz-box-shadow: 7px 7px 12px -9px #777777;
box-shadow: 7px 7px 12px -9px #777777;
opacity: 0.9;
}
.c3-tooltip tr {
border: 1px solid #cccccc;
}
.c3-tooltip th {
background-color: #aaaaaa;
font-size: 14px;
padding: 2px 5px;
text-align: left;
color: #ffffff;
}
.c3-tooltip td {
font-size: 13px;
padding: 3px 6px;
background-color: #ffffff;
border-left: 1px dotted #999999;
text-align: left;
}
.c3-tooltip td > span {
display: inline-block;
width: 10px;
height: 10px;
margin-right: 6px;
}
.c3-tooltip td.value {
text-align: right;
}
/*-- Area --*/
.c3-area {
stroke-width: 0;
opacity: 0.2;
}
/*-- Arc --*/
.c3-chart-arcs-title {
dominant-baseline: middle;
font-size: 1.3em;
}
.c3-chart-arcs .c3-chart-arcs-background {
fill: #e0e0e0;
stroke: #ffffff;
}
.c3-chart-arcs .c3-chart-arcs-gauge-unit {
fill: #000000;
font-size: 16px;
}
.c3-chart-arcs .c3-chart-arcs-gauge-max {
fill: #777777;
}
.c3-chart-arcs .c3-chart-arcs-gauge-min {
fill: #777777;
}
.c3-chart-arc .c3-gauge-value {
fill: #000000;
/* font-size: 28px !important;*/
}
.c3-chart-arc.c3-target g path {
opacity: 1;
}
.c3-chart-arc.c3-target.c3-focused g path {
opacity: 1;
}
/*-- Zoom --*/
.c3-drag-zoom.enabled {
pointer-events: all !important;
visibility: visible;
}
.c3-drag-zoom.disabled {
pointer-events: none !important;
visibility: hidden;
}
.c3-drag-zoom .extent {
fill-opacity: 0.1;
}
`;
}
render() {
super.render();
return html`
<style>
${FusionChart.getStyle()}
</style>
<div id='chart'></div>
<slot></slot>
${FusionChart.getSystemSlotTemplate()}
`;
}
}
export { FusionChart };