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.
136 lines • 6.13 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.
* ------------------------------------------------------------------------------------------ */
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPlansView = exports.PlansView = void 0;
const PlanView_1 = require("./PlanView");
const PLAN_SELECTORS = "planSelectors";
const PLAN_SELECTOR = "planSelector";
const PLAN_SELECTOR_SELECTED = PLAN_SELECTOR + "-selected";
const PLAN_VIEWS = "planViews";
/** Multiple-plan view. */
class PlansView extends PlanView_1.View {
constructor(hostElement, options) {
super(hostElement, options);
this.selectedPlan = -1;
this.plans = [];
this.planViews = [];
this.onPlanSelected = options.onPlanSelected;
this.clear();
}
clear() {
this.showPlans([], -1);
}
/**
* Get `PlanView` for the plan at given `planIndex`
* @param planIndex plan index
* @throws when planIndex is out of range
*/
getView(planIndex) {
return this.planViews[planIndex];
}
showPlans(plans, planId = -1, configuration) {
this.selectedPlan = planId < 0 ? plans.length - 1 : planId;
this.plans = plans;
this.planViews = [];
this.createPlanSelectors();
this.createPlanViews(configuration);
}
addPlan(plan, configuration) {
const planIndex = this.plans.push(plan) - 1;
this.createPlanSelectors();
this.planViewsEl && this.addPlanView(plan, planIndex, this.planViewsEl, configuration);
}
setSelectedPlan(newSelectedPlan) {
var _a;
if (this.selectedPlan != newSelectedPlan) {
// remember the index of the plan that is being shown for later manipulation
this.selectedPlan = newSelectedPlan;
(_a = this.onPlanSelected) === null || _a === void 0 ? void 0 : _a.call(this, this.selectedPlan);
}
}
createPlanSelectors() {
const planSelectorsEl = this.getOrCreateBlankChildElement(PLAN_SELECTORS);
planSelectorsEl.style.display = this.plans.length > 1 ? "flex" : "none";
const maxMetric = Math.max(...this.plans.map(plan => { var _a; return (_a = plan.metric) !== null && _a !== void 0 ? _a : 0; }));
this.plans.forEach((plan, planIndex) => this.createPlanSelector(plan, planIndex, this.selectedPlan, maxMetric, planSelectorsEl));
this.scrollPlanSelectorIntoView(this.selectedPlan);
}
createPlanSelector(plan, planIndex, selectedPlan, maxMetric, parentEl) {
var _a;
const normalizedMetric = ((_a = plan.metric) !== null && _a !== void 0 ? _a : 0) / maxMetric * 100;
const costRounded = plan.metric !== undefined ? plan.metric.toFixed(PlanView_1.DIGITS) : NaN.toString();
const tooltip = `Plan #${planIndex}
Metric value / cost: ${plan.metric}
Makespan: ${plan.makespan}
States evaluated: ${plan.statesEvaluated}`;
const planSelectorEl = document.createElement('div');
planSelectorEl.className = PLAN_SELECTOR;
if (planIndex === selectedPlan) {
planSelectorEl.classList.add(PLAN_SELECTOR_SELECTED);
}
planSelectorEl.setAttribute(PlanView_1.ATTR_PLAN, planIndex.toString());
planSelectorEl.onclick = () => this.showSelectedPlan(planIndex);
const label = document.createElement("span");
label.innerText = costRounded;
planSelectorEl.appendChild(label);
const bar = document.createElement("div");
bar.className = "planMetricBar";
bar.style.height = (0, PlanView_1.px)(normalizedMetric);
bar.title = tooltip;
planSelectorEl.appendChild(bar);
parentEl.appendChild(planSelectorEl);
}
createPlanViews(configuration) {
const planViesEl = this.planViewsEl = this.getOrCreateBlankChildElement(PLAN_VIEWS);
this.plans.forEach((plan, planIndex) => this.addPlanView(plan, planIndex, planViesEl, configuration));
}
addPlanView(plan, planIndex, parent, configuration) {
const newPlanView = (0, PlanView_1.appendPlanView)(parent, planIndex, this.options);
newPlanView.showPlan(plan, configuration);
this.showSelectedPlan(planIndex);
this.planViews[planIndex] = newPlanView;
}
showSelectedPlan(selectedPlanIndex) {
this.setSelectedPlan(selectedPlanIndex);
this.planViews.forEach(planView => {
planView.setVisible(planView.planIndex === selectedPlanIndex);
});
document.querySelectorAll("div." + PLAN_SELECTOR).forEach(div => {
const planIdAsStr = div.getAttribute(PlanView_1.ATTR_PLAN);
if (planIdAsStr !== null) {
const planId = parseInt(planIdAsStr);
if (selectedPlanIndex === planId) {
div.classList.add(PLAN_SELECTOR_SELECTED);
}
else {
div.classList.remove(PLAN_SELECTOR_SELECTED);
}
}
else {
console.warn(`planSelector element does not have the 'plan' attribute`);
}
});
}
/**
* Ensures the plan selector with the given index is visible by scrolling the plan selectors div.
* @param planIndex plan selector to scroll to
*/
scrollPlanSelectorIntoView(planIndex) {
document.querySelectorAll('div.' + PLAN_SELECTOR).forEach(div => {
var _a;
if (parseInt((_a = div.getAttribute(PlanView_1.ATTR_PLAN)) !== null && _a !== void 0 ? _a : "-1") === planIndex) {
div.scrollIntoView();
}
});
}
}
exports.PlansView = PlansView;
function createPlansView(hostElementId, options) {
const hostElement = (0, PlanView_1.getHostElement)(hostElementId);
return new PlansView(hostElement, options);
}
exports.createPlansView = createPlansView;
//# sourceMappingURL=PlansView.js.map