@visactor/vmind
Version:
<div align="center"> <a href="https://github.com/VisActor#gh-light-mode-only" target="_blank"> <img alt="VisActor Logo" width="200" src="https://github.com/VisActor/.github/blob/main/profile/logo_500_200_light.svg"/> </a> <a href="https://githu
259 lines (245 loc) • 9.94 kB
JavaScript
import { AtomName } from "../../types/atom";
import { BaseAtom } from "../base";
import { isNumber, isValidNumber, merge } from "@visactor/vutils";
import { InsightType } from "../dataInsight/type";
import { getCellFromSpec } from "../../utils/spec";
import { TrendType } from "../dataInsight/algorithms/statistics";
import { isStackChart } from "../dataInsight/utils";
import { Factory } from "../../core/factory";
export class SpecInsightAtom extends BaseAtom {
constructor(context, option) {
super(context, option), this.name = AtomName.SPEC_INSIGHT, this.isLLMAtom = !1;
}
buildDefaultContext(context) {
return merge({}, {
spec: {},
insights: []
}, context);
}
buildDefaultOptions() {
return Object.assign(Object.assign({}, super.buildDefaultOptions()), {
defaultMarkerLineStyle: {
stroke: "#000",
lineWidth: 1,
pickStrokeBuffer: 10
},
defaultMarkerSymbolStyle: {
fill: "#000",
lineWidth: 0,
stroke: null
},
diffMarkerSymbolStyle: {
size: 12,
originSymbolType: "arrow",
style: {
stroke: "#000",
fill: !1,
lineWidth: 1
}
},
labelBackground: {
visible: !0,
padding: 4,
style: {
fill: "#3e3e3e",
fillOpacity: .85,
stroke: "#3e3e3e",
lineWidth: 1,
cornerRadius: 4
}
},
defaultOffsetInGrowthMarkLine: 10
});
}
shouldRunByContextUpdate(context) {
return !0;
}
generateMarkPoint(spec, datum, options) {
const {direction: direction, text: text, info: info} = options;
spec.markPoint || (spec.markPoint = []);
const {labelBackground: labelBackground} = this.options, {seriesId: seriesId, seriesIndex: seriesIndex} = info || {};
let offsetX = 0, offsetY = -12;
const dOffset = {
dx: 0,
dy: 8
};
"bottom" === direction ? (offsetY = 12, dOffset.dy = -8) : "top" !== direction && (dOffset.dy = 0,
offsetY = 0, "right" === direction ? (offsetX = 12, dOffset.dx = -8) : "left" === direction && (offsetX = -12,
dOffset.dx = 8)), spec.markPoint.push(Object.assign(Object.assign(Object.assign({
coordinate: datum
}, isNumber(seriesIndex) ? {
relativeSeriesIndex: seriesIndex
} : {}), seriesId ? {
relativeSeriesId: seriesId
} : {}), {
itemContent: {
offsetX: offsetX,
offsetY: offsetY,
autoRotate: !1,
confine: !0,
text: Object.assign(Object.assign({
text: text,
padding: 4
}, dOffset), {
labelBackground: labelBackground,
style: {
fill: "#fff"
}
})
},
itemLine: {
type: "type-s",
arcRatio: .05,
startSymbol: {
visible: !1
},
endSymbol: {
visible: !1
},
line: {
style: {
lineWidth: 1.5
}
}
},
targetSymbol: {
offset: 0,
style: {
size: 6,
lineWidth: 1
}
}
}));
}
formatterValue(value) {
const floatValue = Number(value);
return floatValue > 10 ? floatValue.toFixed(0) : floatValue >= 1 ? floatValue.toFixed(1) : floatValue >= .1 ? floatValue.toFixed(2) : isValidNumber(floatValue) ? floatValue.toFixed(3) : "";
}
getMarkPointText(type, value) {
switch (type) {
case InsightType.Min:
case InsightType.Max:
return value ? `${type}: ${value}` : type;
case InsightType.TurningPoint:
return value ? `Turning Point: ${value}` : "Turning Point";
default:
return value ? `Outlier: ${value}` : "Outlier";
}
}
getAvgMarkLine(spec, value, options) {
const {position: position, text: text, info: info} = options;
spec.markLine || (spec.markLine = []);
const {defaultMarkerLineStyle: defaultMarkerLineStyle, defaultMarkerSymbolStyle: defaultMarkerSymbolStyle, labelBackground: labelBackground} = this.options, {seriesId: seriesId, seriesIndex: seriesIndex} = info || {};
spec.markLine.push(Object.assign(Object.assign(Object.assign({
[position]: value
}, isNumber(seriesIndex) ? {
relativeSeriesIndex: seriesIndex
} : {}), seriesId ? {
relativeSeriesId: seriesId
} : {}), {
label: {
visible: !0,
autoRotate: !1,
text: text,
position: "insideEndTop",
labelBackground: labelBackground,
formatConfig: {
content: [ "percentage" ],
fixed: 1
},
style: {
fill: "#fff",
fontSize: 12
}
},
line: {
style: Object.assign({}, defaultMarkerLineStyle)
},
endSymbol: {
visible: !0,
size: 10,
refX: 6,
symbolType: "triangleLeft",
autoRotate: !1,
style: Object.assign({}, defaultMarkerSymbolStyle)
}
}));
}
getGrowthMarkLine(spec, options) {
spec.markLine || (spec.markLine = []);
const {defaultMarkerLineStyle: defaultMarkerLineStyle, defaultMarkerSymbolStyle: defaultMarkerSymbolStyle, defaultOffsetInGrowthMarkLine: defaultOffsetInGrowthMarkLine, labelBackground: labelBackground} = this.options, {coordinates: coordinates, text: text, isTransposed: isTransposed = !1} = options, offset = `${isTransposed ? defaultOffsetInGrowthMarkLine : -defaultOffsetInGrowthMarkLine}%`;
spec.markLine.push({
coordinates: coordinates,
autoRange: !0,
line: {
style: Object.assign(Object.assign({}, defaultMarkerLineStyle), {
lineDash: [ 0 ]
})
},
label: {
position: "middle",
text: text,
labelBackground: labelBackground,
style: {
fill: "#fff",
fontSize: 14
},
pickable: !0,
childrenPickable: !1,
refY: 0
},
endSymbol: Object.assign({}, defaultMarkerSymbolStyle),
coordinatesOffset: [ {
x: isTransposed ? offset : 0,
y: isTransposed ? 0 : offset
}, {
x: isTransposed ? offset : 0,
y: isTransposed ? 0 : offset
} ]
});
}
runBeforeLLM() {
const {spec: spec, insights: insights, chartType: chartType} = this.context, newSpec = merge({}, spec), cell = getCellFromSpec(spec, chartType), pointIndexMap = {}, isStack = isStackChart(spec, chartType, cell);
return insights.forEach((insight => {
var _a;
const {type: type, data: data, value: value, fieldId: fieldId, info: info} = insight, direction = cell.isTransposed ? Number(value) >= 0 ? "right" : "left" : Number(value) >= 0 || !isValidNumber(value) ? "top" : "bottom";
if ([ InsightType.Outlier, InsightType.ExtremeValue, InsightType.MajorityValue, InsightType.TurningPoint ].includes(type) && isStack) return;
const formatV = this.formatterValue(value), dataString = JSON.stringify((null === (_a = null == data ? void 0 : data[0]) || void 0 === _a ? void 0 : _a.dataItem) || {});
switch (type) {
case InsightType.Min:
case InsightType.Max:
case InsightType.Outlier:
case InsightType.ExtremeValue:
case InsightType.MajorityValue:
case InsightType.TurningPoint:
pointIndexMap[dataString] || (pointIndexMap[dataString] = !0, this.generateMarkPoint(newSpec, Object.assign(Object.assign({}, data[0].dataItem), {
[fieldId]: Number(value)
}), {
direction: direction,
text: this.getMarkPointText(type, formatV),
info: info
}));
break;
case InsightType.Avg:
this.getAvgMarkLine(newSpec, Number(value), {
position: cell.isTransposed ? "x" : "y",
text: formatV ? `Avg: ${formatV}` : "Avg",
info: info
});
break;
case InsightType.OverallTrend:
this.getGrowthMarkLine(newSpec, {
coordinates: info.overall.coordinates,
isTransposed: cell.isTransposed,
text: value === TrendType.INCREASING ? `+${(100 * info.change).toFixed(1)}%` : `${(100 * info.change).toFixed(1)}%`
});
}
})), this.updateContext({
newSpec: newSpec
}), this.context;
}
}
export const registerSpecInsightAtom = () => {
Factory.registerAtom(AtomName.SPEC_INSIGHT, SpecInsightAtom);
};
//# sourceMappingURL=index.js.map