pddl-gantt
Version:
Plan visualization for AI-Planning plans. The package includes HTML components for Gantt, swimlane and line plot visualization of plan originating from AI Planning solvers.
627 lines • 31.5 kB
JavaScript
"use strict";
/* --------------------------------------------------------------------------------------------
* Copyright (c) Jan Dolejsi 2020. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.appendPlanView = exports.createPlanView = exports.px = exports.PlanView = exports.PLAN_VIEW_CLASS = exports.ATTR_PLAN = exports.View = exports.getHostElement = exports.DIGITS = void 0;
/* eslint-disable @typescript-eslint/no-use-before-define */
const vscode_uri_1 = require("vscode-uri");
const pddl_workspace_1 = require("pddl-workspace");
const pddl_workspace_2 = require("pddl-workspace");
const charts_1 = require("./charts");
const planCapitalization_1 = require("./planCapitalization");
const SwimLane_1 = require("./SwimLane");
exports.DIGITS = 4;
function getHostElement(hostElementId) {
const host = document.getElementById(hostElementId);
if (host === null) {
throw new Error(`Element with id#${hostElementId} not found in the document.`);
}
return host;
}
exports.getHostElement = getHostElement;
class View {
constructor(hostElement, options) {
this.options = options;
this.host = hostElement;
}
/**
* Sets new display width. Does not trigger (re-)drawing.
* @param displayWidth new width in pixels, the width is used to fit all gantt chart bars (not necessarily the labels next to them)
*/
setDisplayWidth(displayWidth) {
this.options.displayWidth = displayWidth;
}
getOrCreateBlankChildElement(className) {
const el = this.host.querySelector('.' + className);
if (el) {
el.innerHTML = '';
}
return el !== null && el !== void 0 ? el : this.createChildElement(className);
}
createChildElement(className) {
const child = document.createElement('div');
child.className = className;
return this.host.appendChild(child);
}
}
exports.View = View;
const CUSTOM_PLAN_VIZ = 'planViz';
const GANTT = 'gantt';
const RESOURCE_UTILIZATION = 'resourceUtilization';
const LINE_CHARTS = 'lineCharts';
exports.ATTR_PLAN = "plan";
exports.PLAN_VIEW_CLASS = "planView";
/** Single-plan view. */
class PlanView extends View {
constructor(hostElement, planIndex, options) {
super(hostElement, options);
this.planIndex = planIndex;
this.planStepHeight = 20;
this.linePlotsGenerated = false;
this.visible = true;
this.colors = ['#ff0000', '#ff4000', '#ff8000', '#ffbf00', '#ffff00', '#bfff00', '#80ff00', '#40ff00', '#00ff00', '#00ff40', '#00ff80', '#00ffbf', '#00ffff', '#00bfff', '#0080ff', '#0040ff', '#0000ff', '#4000ff', '#8000ff', '#bf00ff', '#ff00ff', '#ff00bf', '#ff0080', '#ff0040'];
if (this.host.style.width.length == 0) {
this.host.style.width = px(options.displayWidth + 100);
}
}
clear() {
this.getOrCreateBlankChildElement(CUSTOM_PLAN_VIZ);
this.getOrCreateBlankChildElement(GANTT);
this.getOrCreateBlankChildElement(RESOURCE_UTILIZATION);
this.getOrCreateBlankChildElement(LINE_CHARTS);
this.plan = undefined;
this.customVisualization = undefined;
this.deactivateLinePlotPlaceholder();
}
setVisible(visible) {
if (this.visible !== visible) {
this.visible = visible;
const newDisplayStyle = visible ? "block" : "none";
this.host.style.display = newDisplayStyle;
if (!this.linePlotsGenerated && this.plan) {
// line plots were not generated yet
if (!visible) {
// unsubscribe scroll event
this.deactivateLinePlotPlaceholder();
}
else {
this.lineCharts && this.activateLinePlotPlaceholder(this.lineCharts, this.plan);
}
}
}
}
showPlan(plan, configuration) {
this.plan = plan = defaultDomain((0, planCapitalization_1.capitalize)(plan));
const planVizDiv = this.getOrCreateBlankChildElement(CUSTOM_PLAN_VIZ);
this.tryVisualizePlan(planVizDiv, plan, configuration);
const stepsToDisplay = plan.steps
.filter(step => PlanView.shouldDisplay(step, configuration));
const ganttDiv = this.getOrCreateBlankChildElement(GANTT);
this.showGantt(ganttDiv, plan, stepsToDisplay);
const swimLanes = this.getOrCreateBlankChildElement(RESOURCE_UTILIZATION);
this.showSwimLanes(swimLanes, plan, configuration);
this.lineCharts = this.getOrCreateBlankChildElement(LINE_CHARTS);
this.activateLinePlotPlaceholder(this.lineCharts, plan);
}
tryVisualizePlan(planVizDiv, plan, configuration) {
var _a;
try {
this.visualizePlan(planVizDiv, plan, configuration);
}
catch (ex) {
planVizDiv.style.width = px(this.options.displayWidth);
const error = ex;
this.addError(planVizDiv, (_a = error.message) !== null && _a !== void 0 ? _a : '' + error);
}
}
addError(planVizDiv, ex) {
const errorSpan = document.createElement('span');
errorSpan.className = 'error';
errorSpan.innerText = `Error: ` + ex;
planVizDiv.appendChild(errorSpan);
}
visualizePlan(planVizDiv, plan, configuration) {
var _a, _b;
return __awaiter(this, void 0, void 0, function* () {
this.customVisualization = yield (configuration === null || configuration === void 0 ? void 0 : configuration.getCustomVisualization());
if (this.customVisualization) {
if (this.customVisualization.visualizePlanHtml) {
const vizHtml = this.customVisualization.visualizePlanHtml(plan, this.options.displayWidth);
planVizDiv.innerHTML = vizHtml;
}
else if (this.customVisualization.visualizePlanInDiv) {
this.customVisualization.visualizePlanInDiv(planVizDiv, plan, this.options.displayWidth);
}
else if (this.customVisualization.visualizePlanSvg) {
const vizSvg = this.customVisualization.visualizePlanSvg(plan, this.options.displayWidth);
planVizDiv.appendChild(vizSvg);
}
else if (this.customVisualization.visualizeStateHtml ||
this.customVisualization.visualizeStateInDiv ||
this.customVisualization.visualizeStateSvg) {
(_b = (_a = this.options).onFinalStateVisible) === null || _b === void 0 ? void 0 : _b.call(_a, this);
}
}
});
}
showPlanLinePlots(title, yAxisUnit, objects, data) {
if (this.lineCharts) {
this.hideLinePlotLoadingProgress();
this.addLinePlot(title, yAxisUnit, objects, data);
}
}
showFinalState(finalState) {
if (!this.customVisualization || !this.plan) {
return;
}
const planVizDiv = this.getOrCreateBlankChildElement(CUSTOM_PLAN_VIZ);
if (this.customVisualization.visualizeStateHtml) {
const vizHtml = this.customVisualization.visualizeStateHtml(this.plan, finalState, this.options.displayWidth);
planVizDiv.innerHTML = vizHtml;
}
else if (this.customVisualization.visualizeStateInDiv) {
this.customVisualization.visualizeStateInDiv(planVizDiv, this.plan, finalState, this.options.displayWidth);
}
else if (this.customVisualization.visualizeStateSvg) {
const vizSvg = this.customVisualization.visualizeStateSvg(this.plan, finalState, this.options.displayWidth);
planVizDiv.appendChild(vizSvg);
}
}
showGantt(ganttDiv, plan, stepsToDisplay) {
// split this to two batches and insert helpful actions in between
const planHeadSteps = stepsToDisplay
.filter(step => this.isPlanHeadStep(step, plan.now));
const relaxedPlanSteps = stepsToDisplay
.filter(step => !this.isPlanHeadStep(step, plan.now));
const oneIfHelpfulActionsPresent = (plan.hasHelpfulActions() ? 1 : 0);
const relaxedPlanStepIndexOffset = planHeadSteps.length + oneIfHelpfulActionsPresent;
const ganttChartHeight = (stepsToDisplay.length + oneIfHelpfulActionsPresent) * this.planStepHeight;
ganttDiv.style.height = px(ganttChartHeight);
planHeadSteps
.map((step, stepIndex) => this.renderGanttStep(ganttDiv, step, stepIndex, plan));
this.renderHelpfulActions(ganttDiv, plan, planHeadSteps.length);
relaxedPlanSteps
.map((step, stepIndex) => this.renderGanttStep(ganttDiv, step, stepIndex + relaxedPlanStepIndexOffset, plan));
}
renderGanttStep(ganttDiv, step, index, plan) {
const fromTop = index * this.planStepHeight;
const fromLeft = this.computeLeftOffset(step, plan);
const planHeadDuration = this.computePlanHeadDuration(step, plan);
const width = this.computeWidth(planHeadDuration, plan);
const widthRelaxed = this.computeRelaxedWidth(planHeadDuration, step, plan);
const actionColor = plan.domain ? this.getActionColor(step, plan.domain) : 'gray';
const actionIterations = step.getIterations() > 1 ? `${step.getIterations()}x` : '';
const planStep = document.createElement('div');
planStep.id = "plan${planIndex}step${index}";
planStep.className = "planstep";
planStep.style.left = px(fromLeft);
planStep.style.top = px(fromTop);
const planStepBar = document.createElement('div');
planStepBar.className = "planstep-bar";
planStepBar.title = this.toActionTooltipPlain(step);
planStepBar.style.width = px(width);
planStepBar.style.backgroundColor = actionColor;
const planStepBarRelaxed = document.createElement('div');
planStepBarRelaxed.className = "planstep-bar-relaxed whitecarbon";
planStepBarRelaxed.style.width = px(widthRelaxed);
const actionLink = this.toActionLink(step.getActionName(), plan);
const text = document.createTextNode(` ${step.getObjects().join(' ')} ${actionIterations}`);
planStep.append(planStepBar, planStepBarRelaxed, actionLink, text);
ganttDiv.appendChild(planStep);
}
renderHelpfulActions(ganttDiv, plan, planHeadLength) {
var _a;
if (plan.hasHelpfulActions()) {
const fromTop = planHeadLength * this.planStepHeight;
const fromLeft = this.toViewCoordinates(plan.now, plan);
const helpfulActions = document.createElement("div");
helpfulActions.className = "planstep";
helpfulActions.style.top = px(fromTop);
helpfulActions.style.left = px(fromLeft);
helpfulActions.style.marginTop = px(3);
const arrow = document.createTextNode(`▶ `);
helpfulActions.appendChild(arrow);
(_a = plan.helpfulActions) === null || _a === void 0 ? void 0 : _a.forEach((helpfulAction, index) => this.renderHelpfulAction(helpfulActions, index, helpfulAction));
ganttDiv.appendChild(helpfulActions);
}
}
renderHelpfulAction(helpfulActions, index, helpfulAction) {
const suffix = PlanView.getActionSuffix(helpfulAction);
const beautifiedName = `${helpfulAction.actionName}<sub>${suffix}</sub> `;
helpfulActions.appendChild(document.createTextNode(`${index + 1}. `));
const a = document.createElement("a");
a.className = "action";
a.onclick = () => { var _a, _b; return (_b = (_a = this.options).onHelpfulActionSelected) === null || _b === void 0 ? void 0 : _b.call(_a, helpfulAction.actionName); };
a.innerHTML = beautifiedName;
helpfulActions.appendChild(a);
}
static getActionSuffix(helpfulAction) {
switch (helpfulAction.kind) {
case pddl_workspace_2.HappeningType.START:
return '├';
case pddl_workspace_2.HappeningType.END:
return '┤';
}
return '';
}
computeLeftOffset(step, plan) {
return this.toViewCoordinates(step.getStartTime(), plan);
}
/** Converts the _time_ argument to view coordinates */
toViewCoordinates(time, plan) {
return (time !== null && time !== void 0 ? time : 0) / (plan.makespan + this.options.epsilon) * this.options.displayWidth;
}
toActionLink(actionName, plan) {
if (this.options.selfContained || !plan.domain) {
return document.createTextNode(actionName);
}
else {
const a = document.createElement("a");
a.className = "action";
a.onclick = () => { var _a, _b; return (_b = (_a = this.options).onActionSelected) === null || _b === void 0 ? void 0 : _b.call(_a, actionName); };
a.title = `Reveal '${actionName}' action in the domain file`;
a.innerText = actionName;
return a;
}
}
toActionTooltip(tooltipHost, step) {
var _a, _b;
const table = document.createElement("table");
{
const tr = document.createElement("tr");
const th = document.createElement("th");
th.className = "actionToolTip";
th.setAttribute("colspan", "" + 2);
th.innerText = `${step.getActionName()} ${step.getObjects().join(' ')}`;
tr.appendChild(th);
table.appendChild(tr);
}
{
const tr = document.createElement("tr");
{
const td = document.createElement("td");
td.className = "actionToolTip";
td.style.width = px(50);
td.innerText = "Start: ";
tr.appendChild(td);
}
{
const td = document.createElement("td");
td.className = "actionToolTip";
td.innerText = `${step.getStartTime().toFixed(exports.DIGITS)}`;
tr.appendChild(td);
}
table.appendChild(tr);
}
if (step.isDurative && step.getDuration() !== undefined) {
{
const tr = document.createElement("tr");
{
const td = document.createElement("td");
td.className = "actionToolTip";
td.innerText = "Duration: ";
tr.appendChild(td);
}
{
const td = document.createElement("td");
td.className = "actionToolTip";
td.innerText = (_b = (_a = step.getDuration()) === null || _a === void 0 ? void 0 : _a.toFixed(exports.DIGITS)) !== null && _b !== void 0 ? _b : '';
tr.appendChild(td);
}
table.appendChild(tr);
}
{
const tr = document.createElement("tr");
{
const td = document.createElement("td");
td.className = "actionToolTip";
td.innerText = "End: ";
tr.appendChild(td);
}
{
const td = document.createElement("td");
td.className = "actionToolTip";
td.innerText = step.getEndTime().toFixed(exports.DIGITS);
tr.appendChild(td);
}
table.appendChild(tr);
}
}
tooltipHost.appendChild(table);
}
toActionTooltipPlain(step) {
var _a;
const durationRow = step.isDurative && step.getDuration() !== undefined ?
`Duration: ${(_a = step.getDuration()) === null || _a === void 0 ? void 0 : _a.toFixed(exports.DIGITS)}, End: ${step.getEndTime().toFixed(exports.DIGITS)}` :
'';
const startTime = step.getStartTime() !== undefined ?
`, Start: ${step.getStartTime().toFixed(exports.DIGITS)}` :
'';
return `${step.getActionName()} ${step.getObjects().join(' ')}${startTime} ${durationRow}`;
}
computePlanHeadDuration(step, plan) {
var _a, _b, _c;
if (plan.now === undefined) {
return (_a = step.getDuration()) !== null && _a !== void 0 ? _a : this.options.epsilon;
}
else if (step.getEndTime() < plan.now) {
if (step.commitment === undefined || step.commitment === pddl_workspace_2.PlanStepCommitment.Committed) {
return (_b = step.getDuration()) !== null && _b !== void 0 ? _b : this.options.epsilon;
}
else {
return 0;
} // the end was not committed yet
}
else if (step.getStartTime() >= plan.now) {
return 0;
}
else {
switch (step.commitment) {
case undefined:
case pddl_workspace_2.PlanStepCommitment.Committed:
return (_c = step.getDuration()) !== null && _c !== void 0 ? _c : this.options.epsilon;
case pddl_workspace_2.PlanStepCommitment.EndsInRelaxedPlan:
return 0;
case pddl_workspace_2.PlanStepCommitment.StartsInRelaxedPlan:
return plan.now - step.getStartTime();
default:
return 0; // should not happen
}
}
}
computeWidth(planHeadDuration, plan) {
// remove the part of the planStep duration that belongs to the relaxed plan
return Math.max(1, this.toViewCoordinates(planHeadDuration, plan));
}
computeRelaxedWidth(planHeadDuration, step, plan) {
var _a;
// remove the part of the planStep duration that belongs to the planhead part
const relaxedDuration = ((_a = step.getDuration()) !== null && _a !== void 0 ? _a : this.options.epsilon) - planHeadDuration;
return this.toViewCoordinates(relaxedDuration, plan);
}
isPlanHeadStep(step, timeNow) {
return timeNow === undefined ||
step.commitment === undefined ||
step.commitment === pddl_workspace_2.PlanStepCommitment.Committed ||
step.commitment === pddl_workspace_2.PlanStepCommitment.EndsInRelaxedPlan;
}
static shouldDisplay(planStep, configuration) {
var _a;
return (_a = configuration === null || configuration === void 0 ? void 0 : configuration.shouldDisplay(planStep)) !== null && _a !== void 0 ? _a : true;
}
static shouldDisplayObject(step, obj, domain, configuration) {
var _a;
if (!(PlanView.shouldDisplay(step, configuration))) {
return false;
}
const liftedAction = domain === null || domain === void 0 ? void 0 : domain.getActions().find(a => a.getNameOrEmpty().toLowerCase() === step.getActionName().toLowerCase());
if (!liftedAction) {
console.debug('Unexpected plan action: ' + step.getActionName());
return step.getObjects().includes(obj);
}
let fromArgument = 0; // search from this argument positional index
do {
const indexOfArgument = step.getObjects().indexOf(obj, fromArgument);
fromArgument = indexOfArgument + 1;
if (indexOfArgument > -1 && indexOfArgument < liftedAction.parameters.length) {
const parameter = liftedAction.parameters[indexOfArgument];
if (!parameter) {
console.warn(`Parameter #${indexOfArgument} of action ${liftedAction.getNameOrEmpty()} corresponding to plan step ${step.fullActionName} is null`);
return true;
}
const shouldIgnoreThisArgument = configuration === null || configuration === void 0 ? void 0 : configuration.shouldIgnoreActionParameter((_a = liftedAction.name) !== null && _a !== void 0 ? _a : 'unnamed', parameter.name);
if (!shouldIgnoreThisArgument) {
return true;
}
}
} while (fromArgument > 0);
return false;
}
getActionColor(step, domain) {
const actionIndex = domain === null || domain === void 0 ? void 0 : domain.getActions().findIndex(action => action.getNameOrEmpty().toLowerCase() === step.getActionName().toLowerCase());
if (actionIndex === undefined || actionIndex < 0) {
return 'gray';
}
else {
return this.colors[actionIndex * 7 % this.colors.length];
}
}
showSwimLanes(swimLanes, plan, configuration) {
if (this.options.disableSwimlanes || !plan.domain || !plan.problem) {
swimLanes.remove();
return;
}
const allTypeObjects = plan.domain.getConstants().merge(plan.problem.getObjectsTypeMap());
const table = document.createElement("table");
plan.domain.getTypesInclObject()
.filter(type => { var _a, _b; return type !== "object" || ((_b = (_a = allTypeObjects.getTypeCaseInsensitive(type)) === null || _a === void 0 ? void 0 : _a.getObjects().length) !== null && _b !== void 0 ? _b : 0) > 0; })
.forEach(type => {
const typeObjects = allTypeObjects.getTypeCaseInsensitive(type);
typeObjects && this.renderTypeSwimLanes(table, type, typeObjects.getObjects(), plan, configuration);
});
swimLanes.appendChild(table);
}
renderTypeSwimLanes(table, type, objects, plan, configuration) {
const tr = document.createElement("tr");
const tableHeaderTypeName = document.createElement("th");
tableHeaderTypeName.innerText = type;
const tableHeaderFill = document.createElement("th");
tableHeaderFill.style.width = px(this.options.displayWidth);
tr.append(tableHeaderTypeName, tableHeaderFill);
table.appendChild(tr);
objects.forEach(obj => this.renderObjectSwimLane(table, obj, plan, configuration));
}
renderObjectSwimLane(table, obj, plan, configuration) {
const subLanes = new SwimLane_1.SwimLane(1);
const tr = document.createElement("tr");
const tdName = document.createElement("td");
tdName.className = "objectName";
tdName.innerText = obj;
const tdLane = document.createElement("td");
tdLane.style.position = "relative";
plan.steps
.filter(step => PlanView.shouldDisplayObject(step, obj, plan.domain, configuration))
.forEach(step => this.renderSwimLaneStep(tdLane, step, plan, obj, subLanes));
// now size the row appropriately
tdLane.style.height = px(subLanes.laneCount() * this.planStepHeight);
tr.append(tdName, tdLane);
table.appendChild(tr);
}
renderSwimLaneStep(tdLane, step, plan, thisObj, swimLanes) {
const actionColor = this.getActionColor(step, plan.domain);
const leftOffset = this.computeLeftOffset(step, plan);
const planHeadDuration = this.computePlanHeadDuration(step, plan);
const width = this.computeWidth(planHeadDuration, plan) + this.computeRelaxedWidth(planHeadDuration, step, plan);
const objects = step.getObjects()
.map(obj => obj.toLowerCase() === thisObj.toLowerCase() ? '@' : obj)
.join(' ');
const availableLane = swimLanes.placeNext(leftOffset, width);
const fromTop = availableLane * this.planStepHeight + 1;
const div = document.createElement("div");
div.className = "resourceTaskTooltip";
div.style.backgroundColor = actionColor;
div.style.left = px(leftOffset);
div.style.width = px(width);
div.style.top = px(fromTop);
const tooltipText = document.createElement("span");
tooltipText.className = "resourceTaskTooltipText";
this.toActionTooltip(tooltipText, step);
div.append(`${step.getActionName()} ${objects}`, tooltipText);
tdLane.appendChild(div);
}
/**
* Line plots get populated lazily, when they get scrolled to the view.
* @param lineCharts line chart element
* @param plan plan being displayed
*/
activateLinePlotPlaceholder(lineCharts, plan) {
var _a, _b;
if (this.options.disableLinePlots || !plan.domain || !plan.problem) {
return;
}
this.deactivateLinePlotPlaceholder();
if ((0, charts_1.isInViewport)(lineCharts)) {
// load charts immediately
(_b = (_a = this.options).onLinePlotsVisible) === null || _b === void 0 ? void 0 : _b.call(_a, this);
}
else {
// defer chart loading
// show loader
this.addLoader(lineCharts);
// eslint-disable-next-line @typescript-eslint/no-this-alias
const planView = this;
const scrollHandler = function handleScrollEvent() {
var _a, _b;
const lineChartVisible = (0, charts_1.isInViewport)(lineCharts);
if (lineChartVisible) {
(_b = (_a = planView.options).onLinePlotsVisible) === null || _b === void 0 ? void 0 : _b.call(_a, planView);
// unsubscribe the scroll events
planView.deactivateLinePlotPlaceholder();
}
};
document.addEventListener('scroll', scrollHandler, { passive: true });
document.addEventListener("resize", scrollHandler, { passive: true });
// also sign-up to the mouse over, in case the window gets expanded without the content scrolling
lineCharts.addEventListener("mouseenter", scrollHandler);
// retain the handler, so it may be cleared along with the plan
this.handleScrollEvent = scrollHandler;
}
}
/** Removes the scroll events to avoid generating charts for plans that have been cleared from the view */
deactivateLinePlotPlaceholder() {
var _a;
if (this.handleScrollEvent !== undefined) {
document.removeEventListener("scroll", this.handleScrollEvent);
document.removeEventListener("resize", this.handleScrollEvent);
(_a = this.lineCharts) === null || _a === void 0 ? void 0 : _a.removeEventListener("mouseenter", this.handleScrollEvent);
this.handleScrollEvent = undefined;
}
}
addLoader(lineCharts) {
// <div class="loader"></div>
if (!lineCharts.querySelector("div.loader")) {
// only ever add one loader, even if the scroll handler is activated/deactivated many times
const loader = document.createElement("div");
loader.className = "loader";
lineCharts.appendChild(loader);
}
}
hideLinePlotLoadingProgress() {
var _a, _b;
(_b = (_a = this.lineCharts) === null || _a === void 0 ? void 0 : _a.querySelector(".loader")) === null || _b === void 0 ? void 0 : _b.remove();
}
addLinePlot(title, yAxisUnit, objects, data) {
var _a;
this.linePlotsGenerated = true;
const linePlot = document.createElement("div");
linePlot.className = "lineChart";
linePlot.style.width = px(this.options.displayWidth + 100);
linePlot.style.height = px(Math.round(this.options.displayWidth / 2));
(_a = this.lineCharts) === null || _a === void 0 ? void 0 : _a.appendChild(linePlot);
if (!this.options.selfContained) {
(0, charts_1.drawChart)(linePlot, title, yAxisUnit, objects, data);
}
else {
console.error("Line plots are not implemented in self-contained mode.");
// todo: lineChartScripts += ` drawChart('${chartDivId}', '${chartTitleWithUnit}', '', ${JSON.stringify(values.legend)}, ${JSON.stringify(values.values)}, ${this.options.displayWidth});\n`;
}
}
}
exports.PlanView = PlanView;
function px(valueInPx) {
return `${valueInPx}px`;
}
exports.px = px;
function createPlanView(hostElementId, options) {
const hostElement = getHostElement(hostElementId);
return new PlanView(hostElement, 0, options);
}
exports.createPlanView = createPlanView;
function appendPlanView(parent, planIndex, options) {
const hostElement = document.createElement('div');
hostElement.setAttribute(exports.ATTR_PLAN, planIndex.toString());
hostElement.className = exports.PLAN_VIEW_CLASS;
const planView = new PlanView(hostElement, planIndex, options);
parent.appendChild(hostElement);
return planView;
}
exports.appendPlanView = appendPlanView;
/** Creates a default domain and problem, if the plan does not have one associated. */
function defaultDomain(plan) {
if (plan.domain === undefined && plan.problem === undefined) {
const defaultDomain = new pddl_workspace_2.DomainInfo(vscode_uri_1.URI.parse('file:///mock/domain'), 0, 'mock', pddl_workspace_2.parser.PddlSyntaxTree.EMPTY, new pddl_workspace_2.SimpleDocumentPositionResolver(''));
const actions = new Set(plan.steps.map(step => toDefaultAction(step)));
defaultDomain.setActions([...actions]);
defaultDomain.setTypeInheritance(new pddl_workspace_1.utils.DirectionalGraph().addEdge("object"));
const defaultProblem = new pddl_workspace_2.ProblemInfo(vscode_uri_1.URI.parse('file:///mock/problem'), 0, 'mock', 'mock', pddl_workspace_2.parser.PddlSyntaxTree.EMPTY, new pddl_workspace_2.SimpleDocumentPositionResolver(''));
const objectNames = plan.steps.map(step => step.getObjects()).reduce((prev, curr) => prev.concat(curr), []).sort();
const objectMap = new pddl_workspace_2.TypeObjectMap().addAll('object', objectNames);
defaultProblem.setObjects(objectMap);
return new pddl_workspace_2.Plan(plan.steps, defaultDomain, defaultProblem, plan.now, plan.helpfulActions);
}
else {
return plan;
}
}
/** Creates a default action from the plan step. */
function toDefaultAction(planStep) {
const parameters = planStep.getObjects().map((_o, index) => new pddl_workspace_2.Parameter("p" + index, "object"));
if (planStep.isDurative) {
return new pddl_workspace_2.DurativeAction(planStep.getActionName(), parameters, pddl_workspace_2.PddlRange.createUnknown(), undefined);
}
else {
return new pddl_workspace_2.InstantAction(planStep.getActionName(), parameters, pddl_workspace_2.PddlRange.createUnknown());
}
}
//# sourceMappingURL=PlanView.js.map