import { PropertyExt, SVGWidget } from "@hpcc-js/common";
import { event as d3Event, select as d3Select, selectAll as d3SelectAll } from "d3-selection";
import "../src/Opportunity.css";
export class Column extends PropertyExt {
_owner: Opportunity;
constructor() {
super();
}
owner(): Opportunity;
owner(_: Opportunity): this;
owner(_?: Opportunity): Opportunity | this {
if (!arguments.length) return this._owner;
this._owner = _;
return this;
}
valid(): boolean {
return !!this.headerLabel();
}
}
Column.prototype._class += " other_Opportunity.Column";
export interface Column {
headerLabel(): string;
headerLabel(_: string): this;
}
Column.prototype.publish("headerLabel", null, "string", "Header value of a table", function (this: Column) { return this._owner ? this._owner.columns() : []; }, { tags: ["Basic"], optional: true });
export class MouseHoverColumn extends PropertyExt {
_owner: Opportunity;
constructor() {
super();
}
owner(): Opportunity;
owner(_: Opportunity): this;
owner(_?: Opportunity): Opportunity | this {
if (!arguments.length) return this._owner;
this._owner = _;
return this;
}
valid(): boolean {
return !!this.hoverValue() && !!this.hoverList();
}
}
MouseHoverColumn.prototype._class += " other_Opportunity.MouseHoverColumn";
export interface MouseHoverColumn {
hoverValue(): string;
hoverValue(_: string): this;
hoverList(): string;
hoverList(_: string): this;
}
MouseHoverColumn.prototype.publish("hoverValue", null, "string", "Hover value of a table", function () { return this._owner ? this._owner.columns() : []; }, { tags: ["Basic"], optional: true });
MouseHoverColumn.prototype.publish("hoverList", null, "set", "Hover value of a table", function () { return this._owner ? this._owner.getIds() : []; }, { tags: ["Basic"], optional: true });
export class ColumnDropdown extends PropertyExt {
_owner: Opportunity;
constructor() {
super();
}
owner(): Opportunity;
owner(_: Opportunity): this;
owner(_?: Opportunity): Opportunity | this {
if (!arguments.length) return this._owner;
this._owner = _;
return this;
}
valid(): boolean {
return !!this.columnIndex() && !!this.ColumnDropdownList();
}
}
ColumnDropdown.prototype._class += " other_Opportunity.ColumnDropdown";
export interface ColumnDropdown {
columnIndex(): number;
columnIndex(_: number): this;
ColumnDropdownList(): string;
ColumnDropdownList(_: string): this;
}
ColumnDropdown.prototype.publish("columnIndex", null, "number", "Column index for display context data based on column dropdown list selction", {}, { tags: ["Basic", "Shared"] });
ColumnDropdown.prototype.publish("ColumnDropdownList", null, "set", "column value of a table", function () { return this._owner ? this._owner.getIds() : []; }, { tags: ["Basic"], optional: true });
export class Opportunity extends SVGWidget {
groupCount;
svg;
tooltipdiv;
Column;
MouseHoverColumn;
ColumnDropdown;
constructor() {
super();
this._drawStartPos = "origin";
this.groupCount = 7;
}
enter(domNode, element) {
super.enter(domNode, element);
const paddingTop = 30;
const nodeRectHeight = 14;
const verticalPadding = 10;
const h = (this.data().length + 1) * (nodeRectHeight + verticalPadding + 1) + paddingTop;
this.svg = element.append("g")
.attr("width", ((this.groupCount * 100) + 1))
.attr("height", h);
this.svg.append("defs").append("marker")
.classed("arrowhead", true)
.attr("id", "end-arrow")
.attr("viewBox", "0 -5 10 10")
.attr("refX", 6)
.attr("markerWidth", 8)
.attr("markerHeight", 8)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.attr("fill", "rgb(100,100,100)");
this.tooltipdiv = d3Select("body").append("div")
.attr("class", "other_Opportunity-tooltip tooltip")
.style("opacity", 0);
}
update(domNode, element) {
super.update(domNode, element);
const context = this;
const data = this.data();
const dropDownOption = this.opportunityId();
data.sort(function (a, b) {
if (a.cur_group > b.cur_group) return 1;
else if (a.cur_group < b.cur_group) return -1;
else return 0;
});
const groups = [];
for (let i = 1; i <= context.groupCount; i++) {
groups.push(i);
}
const paddingTop = 30;
const nodeRectHeight = 14;
const verticalPadding = 10;
const h = (data.length + 1) * (nodeRectHeight + verticalPadding + 1) + paddingTop;
const w = this.width();
const nodeRectWidthPadding = 30;
const nodeRectWidth = ((w / context.groupCount) - nodeRectWidthPadding);
// Groups ---
const group = this.svg.selectAll(".group").data(groups);
group.enter().append("rect")
.attr("class", "group");
group
.attr("x", function (d, i) {
return (i * w / context.groupCount) + 1;
})
.attr("y", paddingTop)
.attr("width", w / this.groupCount)
.attr("height", h - paddingTop);
group.exit().remove();
// Group Headings ---
const groupHeadings = this.svg.selectAll(".group_headings").data(groups);
groupHeadings.enter().append("text")
.attr("class", "group_headings")
.attr("y", 20);
groupHeadings
.attr("x", function (d, i) {
return (i * w / context.groupCount) + ((w / context.groupCount) / context.groupCount);
})
.text(function (d, i) {
if (context.headerLabels().length > 0) {
if (context.headerLabels()[i] && (context.headerLabels()[i]).headerLabel()) {
return (context.headerLabels()[i]).headerLabel();
}
}
return "";
});
groupHeadings.exit().remove();
if (this.previousGroup() === "prev_group" && this.currentGroup() === "cur_group") {
// Node Date Change ---
const node_date_change = this.svg.selectAll(".node_date_change").data(data);
node_date_change.enter().append("g")
.attr("class", "node_date_change update")
.on("mouseover", function (d) {
context.tooltipdiv.transition()
.duration(200)
.style("opacity", 0.9);
let htmlInput = "" + "Close Date Change " + "" + "
";
const mouseHoverMapping = context.mouseHover();
mouseHoverMapping.forEach(function (obj, index) {
if (obj.hoverValue() !== undefined) {
htmlInput = htmlInput + "" + obj.hoverValue() + ": " + "" + d[obj.hoverList()] + "
";
}
});
let prevDate = d.prevdate + "";
prevDate = prevDate.replace(/(\d\d\d\d)(\d\d)(\d\d)/g, "$3-$2-$1");
let fromDate = d.curdate + "";
fromDate = fromDate.replace(/(\d\d\d\d)(\d\d)(\d\d)/g, "$3-$2-$1");
htmlInput = htmlInput + "" + "From: " + "" + prevDate + "
" + "" + "To: " + "" + fromDate + "
";
context.tooltipdiv.html(htmlInput)
.style("left", (d3Event.pageX) + "px")
.style("top", (d3Event.pageY - 50) + "px");
})
.on("mouseout", function (d) {
context.tooltipdiv.transition()
.duration(500)
.style("opacity", 0);
})
.each(function (d) {
const element2 = d3Select(this);
element2.append("rect")
.attr("class", "node_date_change_rect")
.attr("width", 5)
.attr("height", nodeRectHeight)
.attr("rx", 6)
.attr("ry", 6);
});
node_date_change
.attr("transform", function (d, i) {
return "translate(" + ((9 * w / context.groupCount) + (nodeRectWidthPadding) - 80) + "," + ((i + (i * (nodeRectHeight + verticalPadding))) + 12 + paddingTop) + ")";
});
node_date_change.exit().remove();
// Node Prev Group ---
const node_prev_group = this.svg.selectAll(".node_prev_group").data(data);
node_prev_group.enter().append("g")
.attr("class", "node_prev_group")
.on("mouseover", function (d, i) {
context.tooltipdiv.transition()
.duration(200)
.style("opacity", 0.9);
let tooltipHtml = "";
const mouseHoverMapping = context.mouseHover();
mouseHoverMapping.forEach(function (obj, index) {
if (obj.hoverValue() !== undefined) {
tooltipHtml = tooltipHtml + "" + obj.hoverValue() + ": " + "" + d[obj.hoverList()] + "
";
}
});
context.tooltipdiv.html(tooltipHtml)
.style("left", (d3Event.pageX) + "px")
.style("top", (d3Event.pageY - 100) + "px");
})
.on("mouseout", function (d) {
context.tooltipdiv.transition()
.duration(500)
.style("opacity", 0);
})
.each(function (d) {
const element2 = d3Select(this);
element2.append("rect")
.attr("class", "node_prev_rect")
.attr("rx", 6)
.attr("ry", 6);
element2.append("text")
.attr("class", "node_prev_text");
});
node_prev_group
.classed("update", true)
.classed("changed", function (d) {
return d.delta !== 0;
})
.attr("transform", function (d, i) {
return "translate(" + ((((d.prev_group - 1)) * w / context.groupCount) + (nodeRectWidthPadding / 2)) + "," + ((i + (i * (nodeRectHeight + verticalPadding))) + 10 + paddingTop) + ")";
})
.each(function (d) {
const element2 = d3Select(this);
// Change Lines ---
const changeLines = element2.selectAll(".arrow").data(d.delta !== 0 ? [d] : []);
changeLines.enter().append("line")
.attr("class", "arrow update");
changeLines
.attr("x1", function (d2) {
return (d2.delta > 0) ? nodeRectWidth : 0;
})
.attr("y1", nodeRectHeight / 2)
.attr("x2", function (d2) {
return (d2.delta > 0) ? (nodeRectWidth + nodeRectWidthPadding - 4) + ((Math.abs(d2.delta) - 1)) * (w / context.groupCount) : ((-nodeRectWidthPadding - ((Math.abs(d2.delta) - 1)) * (w / context.groupCount)) + 4);
})
.attr("y2", nodeRectHeight / 2)
.style("stroke-dasharray", ("3, 3"))
.style("stroke", "rgb(100,100,100)")
.style("marker-end", "url(#end-arrow)")
.style("opacity", "1");
changeLines.exit().remove();
});
const node_previous_rect = node_prev_group.select(".node_prev_rect");
node_previous_rect
.attr("width", nodeRectWidth)
.attr("height", nodeRectHeight);
const node_previous_text = node_prev_group.select(".node_prev_text");
node_previous_text
.attr("dy", (nodeRectHeight / 2) + 3)
.attr("dx", (nodeRectWidth / 4))
.text(function (d) {
if (typeof d[dropDownOption] === "number")
return d[dropDownOption];
else
return d[dropDownOption].substring(0, 14);
});
node_prev_group.exit().remove();
// Node Cur Group ---
const node_cur_group = this.svg.selectAll(".node_cur_group").data(data);
node_cur_group.enter().append("g")
.attr("class", "node_cur_group")
.attr("transform", function (d, i) {
return "translate(" + ((((d.prev_group - 1)) * w / context.groupCount) + (nodeRectWidthPadding / 2)) + "," + ((i + (i * (nodeRectHeight + verticalPadding))) + 10 + paddingTop) + ")";
})
.on("mouseover", function (d, i) {
context.tooltipdiv.transition()
.duration(200)
.style("opacity", 0.9);
let tooltipHtml = "";
const mouseHoverMapping = context.mouseHover();
mouseHoverMapping.forEach(function (obj, index) {
if (obj.hoverValue() !== undefined) {
tooltipHtml = tooltipHtml + "" + obj.hoverValue() + ": " + "" + d[obj.hoverList()] + "
";
}
});
context.tooltipdiv.html(tooltipHtml)
.style("left", (d3Event.pageX) + "px")
.style("top", (d3Event.pageY - 100) + "px");
})
.on("mouseout", function (d) {
context.tooltipdiv.transition()
.duration(500)
.style("opacity", 0);
})
.each(function (d) {
const element2 = d3Select(this);
element2.append("rect")
.attr("class", "node_cur_rect")
.attr("fill", function (d2: any) {
let color;
if (d2.delta < 0 || d2.cur_group === 7) {
color = "#F78181";
} else {
color = "#A9F5A9";
}
return color;
})
.attr("rx", 6)
.attr("ry", 6);
element2.append("a")
.append("text")
.attr("class", "node_cur_text");
});
node_cur_group
.classed("update", true)
.classed("changed", function (d) {
return d.delta !== 0;
})
.transition().duration(800)
.ease("linear")
.attr("transform", function (d, i) {
return "translate(" + ((((d.cur_group) - 1) * w / context.groupCount) + (nodeRectWidthPadding / 2)) + "," + ((i + (i * (nodeRectHeight + verticalPadding))) + 10 + paddingTop) + ")";
})
.each("end", function () {
d3SelectAll(".arrow").style("opacity", "1");
});
const node_current_anchor = node_cur_group.select(".node_cur_group a");
node_current_anchor.classed("update", true)
.attr("xlink:href", function (d) {
return context.url() + d.id;
})
.attr("xlink:show", "new");
const node_current_rect = node_cur_group.select(".node_cur_rect");
node_current_rect
.attr("width", nodeRectWidth)
.attr("height", nodeRectHeight);
const node_current_text = node_cur_group.select(".node_cur_text");
node_current_text
.classed("update", true)
.attr("dy", (nodeRectHeight / 2) + 3)
.attr("dx", (nodeRectWidth / 4))
.style("fill", "blue")
.text(function (d) {
if (typeof d[dropDownOption] === "number")
return d[dropDownOption];
else
return d[dropDownOption].substring(0, 14);
});
node_cur_group.exit().remove();
}
for (let colIndex = 0; colIndex < context.columnData().length; colIndex++) {
if ((context.columnData()[colIndex]) && (context.columnData()[colIndex]).ColumnDropdownList()) {
const columnData = this.svg.selectAll(".columnDataText_" + colIndex).data(data);
columnData.enter().append("g")
.attr("class", "columnDataText_" + colIndex + " update")
.each(function (d) {
const element2 = d3Select(this);
element2.append("text");
});
columnData
.attr("transform", function (d, i) {
return "translate(" + (((context.columnData()[colIndex]).columnIndex() * w / context.groupCount) + (nodeRectWidthPadding / 2)) + "," + ((i + (i * (nodeRectHeight + verticalPadding))) + 12 + paddingTop) + ")";
})
.attr("width", 5)
.attr("height", nodeRectHeight)
.attr("rx", 6)
.attr("ry", 6);
const textLable = columnData.select("text");
textLable
.attr("y", -6)
.attr("dy", (nodeRectHeight) + 14)
.attr("dx", 0)
.attr("height", 20)
.attr("width", 29)
.text(function (d, i) {
return d[(context.columnData()[colIndex]).ColumnDropdownList()];
});
columnData.exit().remove();
}
}
}
exit(domNode, element) {
super.exit(domNode, element);
}
getIds() {
const dropdownList = this.columns();
dropdownList.unshift("default");
return dropdownList;
}
previousGroup: { (): string; (_: string): Opportunity };
previousGroup_exists: () => boolean;
currentGroup: { (): string; (_: string): Opportunity };
currentGroup_exists: () => boolean;
opportunityId: { (): string; (_: string): Opportunity };
opportunityId_exists: () => boolean;
url: { (): string; (_: string): Opportunity };
url_exists: () => boolean;
// width: { (): number; (_: number): Opportunity };
width_exists: () => boolean;
addColumn: { (): string; (_: string): Opportunity };
addColumn_exists: () => boolean;
removeColumn: { (): string; (_: string): Opportunity };
removeColumn_exists: () => boolean;
headerLabels: { (): any[]; (_: any[]): Opportunity };
headerLabels_exists: () => boolean;
mouseHover: { (): any[]; (_: any[]): Opportunity };
mouseHover_exists: () => boolean;
columnData: { (): any[]; (_: any[]): Opportunity };
columnData_exists: () => boolean;
}
Opportunity.prototype._class += " other_Opportunity";
Opportunity.prototype.Column = Column;
Opportunity.prototype.MouseHoverColumn = MouseHoverColumn;
Opportunity.prototype.ColumnDropdown = ColumnDropdown;
Opportunity.prototype.publish("previousGroup", "", "set", "label in Opportunity", function () { return this.getIds(); }, { tags: ["Basic", "Shared"] });
Opportunity.prototype.publish("currentGroup", "", "set", "label in Opportunity", function () { return this.getIds(); }, { tags: ["Basic", "Shared"] });
Opportunity.prototype.publish("opportunityId", "id", "set", "Id for label in Opportunity", function () { return this.getIds(); }, { tags: ["Basic", "Shared"] });
Opportunity.prototype.publish("url", null, "string", "URL in Opportunity", {}, { tags: ["Basic", "Shared"] });
Opportunity.prototype.publish("width", 1100, "number", "label in Opportunity", {}, { tags: ["Basic", "Shared"] });
Opportunity.prototype.publish("addColumn", null, "string", "number of columns in a table", {}, {
tags: ["Basic", "Shared"],
editor_input: (context, widget, cell, param) => {
cell.append("button")
.attr("id", context.id() + "_addColumn" + param.id)
.classed("property-input custom-editor-input addColumn update", true)
.text("AddColumn")
.on("click", function () {
widget.groupCount = widget.groupCount + 1;
const new_value_after_click = "Added a new column";
context.setProperty(widget, param.id, new_value_after_click);
});
}
});
Opportunity.prototype.publish("removeColumn", null, "string", "number of columns in a table", function () { return this.columns(); }, {
tags: ["Basic", "Shared"],
editor_input: (context, widget, cell, param) => {
cell.append("button")
.attr("id", context.id() + "_removeColumn" + param.id)
.classed("property-input custom-editor-input removeColumn update", true)
.text("RemoveColumn")
.on("click", function () {
widget.groupCount = widget.groupCount - 1;
const new_value_after_click = "Removed a column";
context.setProperty(widget, param.id, new_value_after_click);
});
}
});
Opportunity.prototype.publish("headerLabels", [], "propertyArray", "Source Columns", null, { autoExpand: Column });
Opportunity.prototype.publish("mouseHover", [], "propertyArray", "mouse hover options", null, { autoExpand: MouseHoverColumn });
Opportunity.prototype.publish("columnData", [], "propertyArray", "column data", null, { autoExpand: ColumnDropdown });